1. 简介
Thrift 是由 Facebook 为“大规模跨语言服务开发”而开发的,现在是Apache软件基金会的开源项目。
Thrift 实现了一种接口描述语言和二进制通讯协议,用来定义和创建跨语言的服务。它被当作一个RPC框架来使用。
Thrift 支持的语言和特性:

2. Thrift架构与使用方法
Thrift 的基础库程序中已经提供了用于 RPC 通讯的底层基本消息协议和传输工具,也就是调用双方如何传输 str、int、float 等不同基本类型的数据无需我们自己再实现了。
Thrift允许我们使用一种独立于任何编程语言的新的语言来定义接口服务,通常把这种语言成为接口定义语言(IDL,Interface Definition Language),我们使用Thrift的IDL将接口定义在一个文本文件中(通常使用.thrift后缀名,成为接口定义文件),然后使用Thrift提供的编译器(compiler)根据这个文件生成所需要的语言的程序源代码。

生成得到不同接口的程序代码后,我们再编写客户端的调用代码和服务端的接口功能实现代码及启动代码,就可完成Thrift RPC的调用实现。
Thrift的架构:

总结使用方法如下:
使用Thrift的IDL编写接口定义文件
使用Thrift的编译器生成特定语言的接口程序源代码
编写客户端和服务端程序
3. Thrift安装
3.1 安装依赖工具和库
sudo apt-get install automake bison flex g++ git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config
3.2 安装Thrift编译器和程序库
可以从https://thrift.apache.org/download下载Thrift源文件:
thrift-0.11.0.tar.gz 是可以在Linux或Mac安装的源文件
Thrift compiler for Windows (thrift-0.11.0.exe) 是Windows的安装文件
(1)解压缩源文件
tar -zxvf thrift-0.11.0.tar.gz
(2)配置安装过程
cd thrift-0.11.0
./configure --prefix=/usr/local/ --without-php --without-java --without-perl --without-nodejs
--prefix表示安装到的路径
--without-PACKAGE表示不安装PACKAGE语言的库,如--without-php表示不安装php的Thrift基础程序库
其他configure选项参数可以通过 ./configure --help进行查看
(3)解析来执行
sudo make
(4)安装
sudo make install
(5)验证
执行如下命令
thrift -version
3.3 注意
安装成功后对于选择安装的语言,调用Thrift的程序库实际上也安装完成。但是对于Python语言,Thrift会附带安装适用于Python 2的程序库(包),缺少了Python 3的程序库;同时,对于Ubuntu系统(或Debian系统),默认python的搜索包路径在dist-packages子目录下,而Thrift安装的Python程序包路径在site-packages子目录下,python程序不能直接导入thrift包。所以,对于Python语言,我们可以使用下面的方法自己安装thrift包。
安装Thrift 的Python包 :pip / pip3 install thrift
4. Thrift的接口定义语言IDL
4.1 基本类型
bool:布尔值,true 或 false
byte:8 位有符号整数
i16:16 位有符号整数
i32:32 位有符号整数
i64:64 位有符号整数
double:64 位浮点数
string:字符串
binary:二进制数据
4.2 容器类型
可以包含多个数据(元素)的类型。
list:元素为type类型的列表,与python的list对应,如;list<double>
set:元素为type类型且唯一的集合,与python的set对应,如:set<i32>
map:键为type1类型值为type2类型的映射,与python的dict对应,如:map<string,string>
4.3 常量类型
const 常量类型 常量名称 = 常量值
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
4.4 枚举类型
enum,一组32位整数常量
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
}
也可以省略常量值,如
enum Operation {
ADD,
SUBTRACT,
MULTIPLY,
}
如果省略了常量值,则枚举中的第一个为1,其次递增。
在Python中以类保存枚举常量值。
4.5 结构体类型
struct,封装一组不同类型的数据,与Python中的类对应,如
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}
optional 关键字表示该字段值可选,如果构建的结构体类型数据中可选字段没有设置值,则在编码生成的消息数据中不会包含可选字段。
4.6 异常类型
exception,可以自定义异常中包含的数据内容,与Python中的类对应,如
exception InvalidOperation {
1: i32 whatOp,
2: string why
}
4.7 接口服务(主要)
service,定义服务接口的方法和参数,如
service BasicService {
double divide(1:i32 num1, 2:i32 num2) throws (1:InvalidOperation e)
oneway void ping()
}
说明:
方法可以不带参数,如带参数,须指明参数的序号和参数类型
方法名前须指明返回值类型,void表示没有返回值
oneway 表示客户端发起请求后不再等待响应返回,oneway方法必须是void返回类型
throws 表示可能抛出的异常
4.8 服务继承
使用extends可以继承扩展另一个服务,如
include "base.thrift"
service Calculate extends base.BasicService {
i32 calculate(1:base.Work w) throws (1:base.InvalidOperation e)
}
4.9 其他
Thrfit支持多种注释方法
# 单行注释
// 单行注释
/* 多行注释 */
使用typedef可以为类型起别名,如
typedef i32 MyInteger
这里定义了一个新的类型MyInteger,这个MyInteger就是i32类型的别名。
4.10 编译
因为我们是pip3安装的thrift所以指定的是 py3 的thrift
使用thrift命令来编译接口定义文件,生成程序代码
thrift --gen 语言 接口定义文件
如
thrift --gen py basic.thrift
其中py 表示生成Python语言代码,其他的语言参数名可以通过thrift -help命令查看。
对于有继承服务的接口定义文件,可以添加-r参数,生成所有相关接口程序,如
thrift -r --gen py calculate.thrift
5. Thrift协议与传输选择
5.1 协议
Thrift 可以让用户选择客户端与服务端之间传输通信的消息协议类别,如我们前面所讲总体划分为文本 (text) 和二进制 (binary) ,为节约带宽,提高传输效率,一般情况下使用二进制类型的为多数,有时还会使用基于文本类型的协议,这需要根据项目 / 产品中的实际需求。常用协议有以下几种:
(1). thrift.protocol.TBinaryProtocol
二进制编码格式进行数据传输
客户端构建方式:
protocol = TBinaryProtocol.TBinaryProtocol(transport)
服务端构建方式:
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
(2). thrift.protocol.TCompactProtocol
高效率的、密集的二进制编码格式进行数据传输,推荐使用
客户端构建方式:
protocol = TCompactProtocol.TCompactProtocol(transport)
服务端构建方式:
pfactory = TCompactProtocol.TCompactProtocolFactory()
(3). thrift.protocol.TJSONProtocol
使用 JSON 的数据编码协议进行数据传输
客户端构建方式:
protocol = TJSONProtocol.TJSONProtocol(transport)
服务端构建方式:
pfactory = TJSONProtocol.TJSONProtocolFactory()
5.2 传输
常用的传输层有以下几种:
(1). thrift.transport.TSocket
使用阻塞式 I/O 进行传输,是最常见的模式
客户端构建方式:
transport = TSocket.TSocket('127.0.0.1', 8888)
服务端构建方式:
transport = TSocket.TServerSocket('127.0.0.1', 8888)
(2). thrift.transport.TTransport.TBufferedTransport
原始的socket方式效率不高,Thrift提供了封装的加了缓存的传输控制,推荐方式
客户端构建方式:
transport = TSocket.TSocket('127.0.0.1', 8888)
transport = TTransport.TBufferedTransport(transport)
服务端构建方式:
transport = TSocket.TServerSocket('127.0.0.1', 8888)
tfactory = TTransport.TBufferedTransportFactory()




