Thrift概述
Thrift作为Facebook开源的RPC框架, 通过IDL(Interface Definition Language)中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码
语义语法
注释
- Thrift支持C多行风格和Java/C++单行风格.
命名空间
- Thrift中的命名空间类似于C++中的namespace和java中的package,它们提供了一种组织(隔离)代码的简便方式; 名字空间也可以用于解决类型定义中的名字冲突.
基本类型
bool
: 布尔值 对应Java中的booleanbyte
: 8位有符号整型 对应Java中的bytei16
: 16位有符号整型 对应Java中的shorti32
: 32位有符号整型 对应Java中的inti64
: 64位有符号整型 对应Java中的longdouble
: 64位浮点型 对应Java中的doublestring
: 字符串 对应Java中的Stringbinary
: Blob 类型 对应Java中的byte[]
集合类型
list<t>
: 元素类型为t的有序表,容许元素重复.set<t>
: 元素类型为t的无序表,不容许元素重复.map<t, t>
: 值类型为t的键值对,键不容许重复.
枚举类型
- Thrift不支持枚举类嵌套,枚举常量必须是32位的正整数, 末尾属性没有分号
常量
- 在变量前面加上const, 改变量被声明为一个常量.
结构体
类似与Java中的对象, struct不能继承,但是可以嵌套(不能嵌套自己), 其成员都是有明确类型. 不支持泛型. 成员分割符可以是
,
或是;
定义结构体成员时, 成员必须是被正整数编号过的,其中的编号使不能重复的,这个是为了在传输过程中编码使用.字段会有optional和required之分, 如果不指定则为无类型–可以不填充该值,但是在序列化传输的时候也会序列化进去,optional是不填充则部序列化,required是必须填充也必须序列化.
同一文件可以定义多个struct,也可以定义在不同的文件,进行include引入.
异常
- 异常在语法和功能上类似于结构体,差别是异常使用关键字exception,而且异常是继承每种语言的基础异常类
文件包含
- 为了便于管理、重用和提高模块性/组织性,我们常常分割Thrift定义在不同的文件中; 通过
include
关键字进行分文件的引入包含
应用示例
基于IDL示例
示例结构
1 | [root@localhost etc]$ tree sample |
定义结构体
定义入参
1 | [root@localhost sample]$ cat idl/Request.thrift |
定义出参
1 | [root@localhost sample]$ cat idl/Response.thrift |
定义接口
1 | [root@localhost sample]$ cat idl/ServiceIface.thrift |
代码生成
1 | [root@localhost sample]$ thrift -version |
基于注解示例
上面的IDL生成的方式我们可以使用注解方式进行定义
定义结构体
QueryEntry.java
1 |
|
AuditEnum.java
1 | // 定义枚举 |
SampleView.java
1 |
|
ApiResult.java
1 |
|
定义接口服务
1 |
|
说明: 示例中@Getter
、@Setter
、@NoArgsConstructor
是lombok注解(简化模板代码),非thrift注解.
Maven生成插件
thrift对应maven生成插件为maven-thrift-plugin(注意:将thrift文件放置在src/main/thrift/目录下)
1 | <build> |
运行mvn package后,会自动在target目录下生成java源码及编译后的class
数据传输协议
Thrift在传输协议(传输格式)上总体上划分为文本(text)和二进制(binary)传输协议;为节约带宽,提供传输效率, 一般情况下使用二进制类型的传输协议为多数.
TBinaryProtocol
: 二进制编码格式进行数据传输。TCompactProtocol
: 压缩格式进行数据传输。TTupleProtoco
: 继承于TCompactProtocol,Struct的编解码时使用更省地方但IDL间版本不兼容的TupleScheme.TJSONProtocol
: JSON格式编码协议进行数据传输。TSimpleJSONProtocol
: 这种协议只提供JSON只写的协议,适用于通过脚本语言解析TDebugProtocol
: 在开发的过程中帮助开发人员调试用的,使用易懂的可读的文本格式.
说明: 客户端和服务端的协议要一致.
数据传输方式
protocol说明的是什么被传送(传送内容格式),transports说明的是如何传送(传送方式)
一个server只允许定义一个接口服务。这样的话多个接口需要多个server。这样会带来资源的浪费。通常可以通过定义一个组合服务来解决。
TSocket
: 采用blocking socket I/OTFileTransport
: 以文件(日志)形式进行传输。TFramedTransport
: 以帧的形式发送,每帧前面是一个长度。要求服务器方式为non-blocking serverTZlibTransport
: 使用zlib进行压缩传输,与其他传输方式联合使用.TMemoryTransport
: 使用内存I/O,java实现中在内部使用了ByteArrayOutputStreamTNonblockingTransport
: 使用JDKNIO的Transport实现,读写的byte[]会每次被wrap成一个ByteBuffer.
序列化和反序列化
Thrift序列化时属性标识如下, 没有域的名称,因此与JSON/XML这种序列化工具相比,thrift序列化后生成的文件体积要小很多.
1 | 数字ID + 属性类型TYPE |
Thrift的向后兼容性需要满足2个条件, 这样无论增加还是删除域,都可以实现向后兼容.
域的序号不能改变(数值)
域的类型不能改变(类型)
服务端类型
Thrift提供网络模型有单线程、多线程、事件驱动; 也可划分为:阻塞服务模型、非阻塞服务模型。
阻塞服务模型
TSimpleServer
: 简单的单线程服务器,主要用于测试.TThreadPoolServer
: 使用标准阻塞式IO的多线程服务器
非阻塞服务模型
TNonblockingServer
: 采用NIO的模式, 借助Channel/Selector机制, 采用IO事件模型来处理.唯一可惜的是这个单线程处理. 当遇到handler里有阻塞的操作时, 会导致整个服务被阻塞住.(需使用TFramedTransport数据传输方式)THsHaServer
: 同步半异步的服务模型,一个单独的线程用来处理网络I/O,一个worker线程池用来进行消息的处理.TThreadedSelectorServer
: 有一条线程专门负责accept,若干条Selector线程处理网络IO,一个Worker线程池处理消息(使用得最多)。
相关文档
- http://calvin1978.blogcn.com/articles/apache-thrift.html
- https://blog.csdn.net/xuemengrui12/article/details/60876260
参考文档
- http://www.micmiu.com/soa/rpc/thrift-sample/
- https://www.cnblogs.com/cyfonly/p/6059374.html
- https://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/
- http://dongxicheng.org/search-engine/thrift-framework-intro/
- https://www.cnblogs.com/mumuxinfei/p/3875165.html
- http://1csh1.github.io/2017/02/21/Thrift%20IDL%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95