Thrift相关概念学习笔记

一直在工作中使用 Apache Thrift,但是一直对其中的一些概念一知半解,于是终于抽空学习了一下,记录下来作为学习笔记。

Thrift 网络层级

简单示意图如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
+-------------------------------------------+
| Server |
| (single-threaded, event-driven etc) |
+-------------------------------------------+
| Processor |
| (compiler generated) |
+-------------------------------------------+
| Protocol |
| (JSON, compact etc) |
+-------------------------------------------+
| Transport |
| (raw TCP, HTTP etc) |
+-------------------------------------------+

Transport

Transport层提供了一个读写底层网络的简单抽象,这使得Thrift可以把底层的网络传输和其它部分(比如序列化、反序列化)解耦开。

Transport主要包含以下接口:

  • open
  • close
  • read
  • write
  • flush

除了上面这个Transport的接口,Thrift还提供了一个ServerTransport的接口,用来accept或者create上面的Transport对象。顾名思义,ServerTransport主要用在服务端,用来接受连接并创建Transport对象。

ServerTransport主要包含以下接口:

  • open
  • listen
  • accept
  • close

Thrift主要支持的语言中有的部分接口示例如下:

  • file: read/write to/from a file on disk
  • http: 顾名思义

Protocol

Protocol层定义了序列化、反序列化的格式和方法,比如json、xml、plain text、compact binary等等。

Protocol的接口定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
writeMessageBegin(name, type, seq)
writeMessageEnd()
writeStructBegin(name)
writeStructEnd()
writeFieldBegin(name, type, id)
writeFieldEnd()
writeFieldStop()
writeMapBegin(ktype, vtype, size)
writeMapEnd()
writeListBegin(etype, size)
writeListEnd()
writeSetBegin(etype, size)
writeSetEnd()
writeBool(bool)
writeByte(byte)
writeI16(i16)
writeI32(i32)
writeI64(i64)
writeDouble(double)
writeString(string)

name, type, seq = readMessageBegin()
readMessageEnd()
name = readStructBegin()
readStructEnd()
name, type, id = readFieldBegin()
readFieldEnd()
k, v, size = readMapBegin()
readMapEnd()
etype, size = readListBegin()
readListEnd()
etype, size = readSetBegin()
readSetEnd()
bool = readBool()
byte = readByte()
i16 = readI16()
i32 = readI32()
i64 = readI64()
double = readDouble()
string = readString()

Thrift Protocol在设计上就是以流为目标的,所以不需要任何显式的帧。比如,当我们在序列化一个string之前,我们不需要知道它有多长;同样的,当我们序列化一个list之前,不需要知道里面有几个item。部分Thrift主要支持语言所常用的Protocol如下:

  • binary: 非常简单的二进制编码,先编码长度和类型,然后编码真实的值。
  • compact: 参考THRIFT-110
  • json

Processor

Processor提供了从输入流读取数据以及写出到输出流的能力,输入和输出流都是由Protocol层实现,Processor本身很简单:

1
2
3
interface TProcessor {
bool process(TProtocol in, TProtocol out) throws TException
}

每个服务的Processor都是由compiler生成的,Processor从输入流读取数据,扔给用户的handler处理,再把response写回输出流。

Server

Server把上述所有的特性组合在一起:

  • 创建一个Transport
  • 根据Transport创建输入输出流(Protocol)
  • 基于输入输出流创建Processor
  • 等待并处理连接