Thrift
1、简介
Thrift是一种接口描述语言(IDL)和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的、无缝的跨平台高效服务,可以使用C#、C++(基于POSIX兼容系统)、Erlang、Go、Java、Node.js、PHP、Pathon、Ruby等。
2、架构
Thrift软件栈分层从下向上分别为:传输层( TransportLayer)、协议层( ProtocolLayer)、处理层( ProcessorLayer)和服务层( ServerLayer)。
- 传输层( TransportLayer):传输层负责直接从网络中读取和写入数据,它定义了具体的网络传输协议;比如说 TCP/IP传输等。
- 协议层( ProtocolLayer):协议层定义了数据传输格式,负责网络传输数据的序列化和反序列化;比如说 JSON、 XML、二进制数据等。
- 处理层( ProcessorLayer):处理层是由具体的 IDL(接口描述语言)生成的,封装了具体的底层网络传输和序列化方式,并委托给用户实现的 Handler进行处理。
- 服务层( ServerLayer):整合上述组件,提供具体的网络线程/IO服务模型,形成最终的服务。
在最上层是用户自行实现的业务逻辑代码。
Thrift支持众多通讯协议:
- TBinaryProtocol – 一种简单的二进制格式,简单,但没有为空间效率而优化。比文本协议处理起来更快,但更难于调试。
- TCompactProtocol – 更紧凑的二进制格式,处理起来通常同样高效。
- TDebugProtocol – 一种人类可读的文本格式,用来协助调试。
- TDenseProtocol – 与TCompactProtocol类似,将传输数据的元信息剥离。
- TJSONProtocol – 使用JSON对数据编码。
- TSimpleJSONProtocol – 一种只写协议,它不能被Thrift解析,因为它使用JSON时丢弃了元数据。适合用脚本语言来解析。
支持的传输协议有:
- TFileTransport – 该传输协议会写文件。
- TFramedTransport – 当使用一个非阻塞服务器时,要求使用这个传输协议。它按帧来发送数据,其中每一帧的开头是长度信息。
- TMemoryTransport – 使用存储器映射输入输出。(Java的实现使用了一个简单的ByteArrayOutputStream。)
- TSocket – 使用阻塞的套接字I/O来传输。
- TZlibTransport – 用zlib执行压缩。用于连接另一个传输协议。
Thrift还提供众多的服务器,包括:
- TNonblockingServer – 一个多线程服务器,它使用非阻塞I/O(Java的实现使用了NIO通道)。TFramedTransport必须跟这个服务器配套使用。
- TSimpleServer – 一个单线程服务器,它使用标准的阻塞I/O。测试时很有用。
- TThreadPoolServer – 一个多线程服务器,它使用标准的阻塞I/O。
3、数据类型
基本数据类型:
bool:布尔值,true 或 false,对应 Java 的 boolean
byte:8 位有符号整数,对应 Java 的 byte
i16:16 位有符号整数,对应 Java 的 short
i32:32 位有符号整数,对应 Java 的 int
i64:64 位有符号整数,对应 Java 的 long
double:64 位浮点数,对应 Java 的 double
string:未知编码文本或二进制字符串,对应Java 的 String
结构体类型:
struct:定义公共的对象,类似于C 语言中的结构体定义,在Java 中是一个JavaBean。成员是被正整数编号过的,其中的编号使不能重复的,这个是为了在传输过程中编码使用。
字段会有optional和required之分,但是如果不指定则为无类型–可以不填充该值,但是在序列化传输的时候也会序列化进去,optional是不填充则部序列化,required是必须填充也必须序列化。同一文件可以定义多个struct,也可以定义在不同的文件,进行include引入。每个字段可以设置默认值。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
struct Example { 1:i32 number=10, 2:i64 bigNumber, 3:list<double> decimals, 4:string name="thrifty"}struct People { 1: required string name; //必填 2: optional i32 age; //可选}联合(union)当一个结构体中,field之间的关系是互斥的,即只能有一个field被使用被赋值。可以用union来声明这个结构体,而不是一堆堆optional的field,语意上也更明确了。例如:union JavaObjectArg { 1: i32 int_arg; 2: i64 long_arg; 3: string string_arg; 4: bool bool_arg; 5: binary binary_arg; 6: double double_arg;} |
容器类型:
集合中的元素可以是除了service之外的任何类型,包括exception。
list: 一系列由T类型的数据组成的有序列表,元素可以重复
set: 一系列由T类型的数据组成的无序集合,元素不可重复
map: 一个字典结构,key为K类型,value为V类型
枚举类型:
和Java差不多
异常类型:
可以自定义异常类型,所定义的异常会继承对应语言的异常基类,例如java,就会继承 java.lang.Exception。
|
1
2
3
4
|
exception InvalidOperation { 1: i32 what, 2: string why} |
服务类型:
thrift定义服务相当于Java中创建Interface一样,创建的service经过代码生成命令之后就会生成客户端和服务端的框架代码。定义形式如下:
|
1
2
3
4
5
|
service StringCache { void set(1:i32 key, 2:string value), string get(1:i32 key) throws (1:KeyNotFound knf), void delete(1:i32 key)} |
4、与Dubbo对比
|
|
Dubbo
|
Thrift
|
|---|---|---|
|
|
Dubbo
|
Thrift
|
| 开发语言 | Java | 跨语言 |
| 分布式(服务治理) | √ | × |
| 多序列化框架支持 | √ | ×(thrift格式) |
| 多种注册中心 | √ | × |
| 管理中心 | √ | × |
| 跨编程语言 | × | √ |
5、典型应用场景和非应用场景
对于需求为高性能,分布式的RPC服务,Thrift是一个优秀的解决方案。它支持众多语言和丰富的数据类型,并对于数据字段的增删具有较强的兼容性。所以非常适用于作为公司内部的面向服务构建(SOA)的标准RPC框架。
不过Thrift的文档相对比较缺乏,目前使用的群众基础相对较少。另外由于其Server是基于自身的Socket服务,所以在跨防火墙访问时,安全是一个顾虑,所以在公司间进行通讯时需要谨慎。 另外Thrift序列化之后的数据是Binary数组,不具有可读性,调试代码时相对困难。最后,由于Thrift的序列化和框架紧耦合,无法支持向持久层直接读写数据,所以不适合做数据持久化序列化协议。


浙公网安备 33010602011771号