Thrift 的序列化机制

1.首先我们先来定义下thrift的简单结构。

 

[sql]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. namespace java mmxf.thrift;  
  2.    
  3. struct Pair {  
  4.   1: required string key  
  5.   2: required string value  
  6. }  

 

required修饰符你肯定能猜测到它的意义, 但是你是否有没有这样的疑惑, "1", "2" 这些数字标识符究竟有何含义? 它在序列化机制中究竟扮演什么样的角色?

编译并进行

thrift -gen java <your thrift file>

2.编写测试代码

 

[java]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. private String datafile = "1.dat";  
  2.        
  3. // *) 把对象写入文件  
  4. public void writeData() throws IOException, TException {  
  5.     Pair pair = new Pair();  
  6.     pair.setKey("rowkey").setValue("column-family");  
  7.    
  8.     FileOutputStream fos = new FileOutputStream(new File(datafile));  
  9.     pair.write(new TBinaryProtocol(new TIOStreamTransport(fos)));  
  10.     fos.close();  
  11. }   

调用writeData(), 把pair{key=> rowkey, value=> column-family} 写入文件1.dat中

 

3.如果我重新定义pair结构, 调整数字编号数序

[plain]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. struct Pair {  
  2.   2: required string key  
  3.   1: required string value  
  4. }  

 

评注: 这边2对应key, 1对应value.

重新编译thrift -gen java <your thrift file>

4.然后读取该数据

 

[java]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. private String datafile = "1.dat";  
  2. // *) 从文件恢复对象  
  3. public void readData() throws TException, IOException {  
  4.   FileInputStream fis = new FileInputStream(new File(datafile));  
  5.    
  6.   Pair pair = new Pair();  
  7.   pair.read(new TBinaryProtocol(new TIOStreamTransport(fis)));  
  8.    
  9.   System.out.println("key => " + pair.getKey());  
  10.   System.out.println("value => " + pair.getValue());  
  11.    
  12.   fis.close();  
  13. }  

调用readData(), 从文件1.dat中恢复Pair对象来。

 

结果:

key => column-family

value => rowkey

是不是和你预期的相反, 看来属性名称并没有发挥作用, 而id标识在thrift的序列化/反序列化扮演非常重要的角色。带着这些疑惑, 我们进一步的详细解读序列化机制。

thrift 数据格式描述

 

官网文档描述: http://thrift.apache.org/static/files/thrift-20070401.pdf

Versioning in Thrift is implemented via field identifiers. The field header for every member of a struct in Thrift is encoded with a unique field identifier. The combination of this field identifier and its type specifier is used to uniquely identify the field. The Thrift definition language supports automatic assignment of field identifiers, but it is good programming practice to always explicitly specify field identifiers.

翻译: thrift的向后兼容性(Version)借助属性标识(数字编号id + 属性类型type)来实现, 可以理解为在序列化后(属性数据存储由 field_name:field_value => id+type:field_value), 这也解释了上述提到的场景的原因了。

对之前定义的Pair结构体, 进行代码解读:

 

[java]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public void read(org.apache.thrift.protocol.TProtocol iprot, Pair struct) {  
  2.   // *) 读取结构结束标记  
  3.   iprot.readStructBegin();  
  4.   while ( iprot is stop) {  
  5.     // *) 读取Field属性开始标记  
  6.     schemeField = iprot.readFieldBegin();  
  7.     // *) field标记包含 id + type, switch根据(id+type)来分配相关的值  
  8.     switch (schemeField.id) {  
  9.       case <id>: // <field_name>  
  10.         if (schemeField.type == thrift.TType.<type>) {  
  11.           struct.<field_name> = iprot.read<type>();  
  12.           struct.set<field_name>IsSet(true);  
  13.         }  
  14.     }  
  15.     // *) 读取Field属性结束标记  
  16.     iprot.readFieldEnd();  
  17.   }  
  18.   // *) 读取结构体结束标记  
  19.   iprot.readStructEnd();  
  20. }  

从恢复对象的函数中, 我们也可以对thrift定义的序列化对象有个初步的认识, 庖丁解牛,最终会被细化为readStructBegin, readFieldBegin, read<type>(readString, readI32, readI64)的有组织有序调用。

 

数据交换格式分类

当前的数据交换格式可以分为如下几类:

1. 自解析型

  序列化的数据包含完整的结构, 包含了field名称和value值. 比如xml/json/java serizable, 大百度的mcpack/compack, 都属于此类. 即调整不同属性的顺序对序列化/反序列化不影响.

2. 半解析型

  序列化的数据,丢弃了部分信息, 比如field名称, 但引入了index(常常是id+type的方式)来对应具体属性和值. 这方面的代表有google protobuf, thrift也属于此类.

3. 无解析型

  传说中大百度的infpack实现, 就是借助该种方式来实现, 丢弃了很多有效信息, 性能/压缩比最好, 不过向后兼容需要开发做一定的工作, 详情不知.

 

thrift与常见数据交换格式的对比

交换格式类型优点缺点
Xml文本易读臃肿, 不支持二进制数据类型
Json文本易读丢弃了类型信息, 比如"score":100, 对score类型是int/double解析有二义性, 不支持二进制数据类型
Java serizable二进制使用简单臃肿, 只限制在java领域
Thrift二进制高效不宜读, 向后兼容有一定的约定限制
Google Protobuf二进制高效不宜读, 向后兼容有一定的约定限制

向后兼容实践:Thrift官方文档, 也提到对新增的字段属性, 采用id递增的方式标识并以optional修饰来添加。

http://blog.csdn.net/zhu_tianwei/article/details/44115489

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值