前言
Thrift
支持二进制,压缩格式,以及json
格式数据的序列化和反序列化。开发人员可以更加灵活的选择协议的具体形式。协议是可自由扩展的,新版本的协议,完全兼容老的版本!
正文
数据交换格式简介
当前流行的数据交换格式可以分为如下几类:
(一) 自解析型
序列化的数据包含完整的结构, 包含了field
名称和value
值。比如xml/json/java serizable
,大百度的mcpack/compack
,都属于此类。即调整不同属性的顺序对序列化/反序列化不造成影响。
(二) 半解析型
序列化的数据,丢弃了部分信息, 比如field
名称, 但引入了index
(常常是id
+type
的方式)来对应具体属性和值。这方面的代表有google protobuf/thrift
也属于此类。
(三) 无解析型
传说中大百度的infpack
实现,就是借助该种方式来实现,丢弃了很多有效信息,性能/压缩比最好,不过向后兼容需要开发做一定的工作, 详情不知。
交换格式 | 类型 | 优点 | 缺点 |
---|---|---|---|
Xml | 文本 | 易读 | 臃肿,不支持二进制数据类型 |
JSON | 文本 | 易读 | 丢弃了类型信息,比如"score":100,对score类型是int/double解析有二义性, 不支持二进制数据类型 |
Java serizable | 二进制 | 使用简单 | 臃肿,只限制在JAVA领域 |
Thrift | 二进制 | 高效 | 不易读,向后兼容有一定的约定限制 |
Google Protobuf | 二进制 | 高效 | 不易读,向后兼容有一定的约定限制 |
Thrift的数据类型
- 基本类型:
bool: 布尔值
byte: 8位有符号整数
i16: 16位有符号整数
i32: 32位有符号整数
i64: 64位有符号整数
double: 64位浮点数
string: UTF-8编码的字符串
binary: 二进制串 - 结构体类型:
struct: 定义的结构体对象 - 容器类型:
list: 有序元素列表
set: 无序无重复元素集合
map: 有序的key/value集合 - 异常类型:
exception: 异常类型 - 服务类型:
service: 具体对应服务的类
Thrift的序列化协议
Thrift
可以让用户选择客户端与服务端之间传输通信协议的类别,在传输协议上总体划分为文本(text
)和二进制(binary
)传输协议。为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数,有时还会使用基于文本类型的协议,这需要根据项目/产品中的实际需求。常用协议有以下几种:
- TBinaryProtocol:二进制编码格式进行数据传输
- TCompactProtocol:高效率的、密集的二进制编码格式进行数据传输
- TJSONProtocol: 使用
JSON
文本的数据编码协议进行数据传输 - TSimpleJSONProtocol:只提供
JSON
只写的协议,适用于通过脚本语言解析
Thrift的序列化测试
(a). 首先编写一个简单的thrift
文件pair.thrift
:
struct Pair {
1: required string key
2: required string value
}
这里标识了
required
的字段,要求在使用时必须正确赋值,否则运行时会抛出TProtocolException
异常。缺省和指定为optional
时,则运行时不做字段非空校验。
(b). 编译并生成java
源代码:
thrift -gen java pair.thrift
(c). 编写序列化和反序列化的测试代码:
- 序列化测试,将
Pair
对象写入文件中
private static void writeData() throws IOException, TException {
Pair pair = new Pair();
pair.setKey("key1").setValue("value1");
FileOutputStream fos = new FileOutputStream(new File("pair.txt"));
pair.write(new TBinaryProtocol(new TIOStreamTransport(fos)));
fos.close();
}
- 反序列化测试,从文件中解析生成
Pair
对象
private static void readData() throws TException, IOException {
Pair pair = new Pair();
FileInputStream fis = new FileInputStream(new File("pair.txt"));
pair.read(new TBinaryProtocol(new TIOStreamTransport(fis)));
System.out.println("key => " + pair.getKey());
System.out.println("value => " + pair.getValue());
fis.close();
}
</