前言:
  Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还是有一定距离, 本系列将对Thrift作代码解读和框架扩充, 使得它更加贴近生产环境. 本文主要讲解Thrift的序列化机制, 看看thrift作为数据交换格式是如何工作的?

构造应用场景:
1). 首先我们先来定义下thrift的简单结构.

namespace java mmxf.thrift;

struct Pair {
  1: required string key
  2: required string value
}

required修饰符你肯定能猜测到它的意义, 但是你是否有没有这样的疑惑, "1", "2" 这些数字标识符究竟有何含义? 它在序列化机制中究竟扮演什么样的角色?
编译并进行
thrift -gen java <your thrift file>

2). 编写测试代码

private String datafile = "1.dat";

// *) 把对象写入文件
public void writeData() throws IOException, TException {
Pair pair = new Pair();
pair.setKey("rowkey").setValue("column-family"); FileOutputStream fos = new FileOutputStream(new File(datafile));
pair.write(new TBinaryProtocol(new TIOStreamTransport(fos)));
fos.close();
} 

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

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

struct Pair {
  2: required string key
  1: required string value
}

评注: 这边2对应key, 1对应value.
重新编译thrift -gen java <your thrift file>

4). 然后读取该数据

private String datafile = "1.dat";
// *) 从文件恢复对象
public void readData() throws TException, IOException {
  FileInputStream fis = new FileInputStream(new File(datafile));   Pair pair = new Pair();
  pair.read(new TBinaryProtocol(new TIOStreamTransport(fis)));   System.out.println("key => " + pair.getKey());
  System.out.println("value => " + pair.getValue());   fis.close();
}

调用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结构体, 进行代码解读:

public void read(org.apache.thrift.protocol.TProtocol iprot, Pair struct) {
  // *) 读取结构结束标记
  iprot.readStructBegin();
  while ( iprot is stop) {
    // *) 读取Field属性开始标记
    schemeField = iprot.readFieldBegin();
    // *) field标记包含 id + type, switch根据(id+type)来分配相关的值
    switch (schemeField.id) {
      case <id>: // <field_name>
        if (schemeField.type == thrift.TType.<type>) {
          struct.<field_name> = iprot.read<type>();
          struct.set<field_name>IsSet(true);
        }
    }
    // *) 读取Field属性结束标记
    iprot.readFieldEnd();
  }
  // *) 读取结构体结束标记
  iprot.readStructEnd();
}

代码评注:
  从恢复对象的函数中, 我们也可以对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修饰来添加.

后续
  后续会讲解基于thrift进行服务化的专题, 首先会讲解client的封装改造, 敬请期待.

Thrift 个人实战--Thrift 的序列化机制的更多相关文章

  1. Thrift 个人实战--Thrift 网络服务模型

    前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还 ...

  2. Thrift 个人实战--Thrift 服务化 Client的改造

    前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还 ...

  3. Thrift 个人实战--Thrift 网络服务模型(转)

    前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还 ...

  4. Thrift 个人实战--Thrift RPC服务框架日志的优化

    前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还 ...

  5. 由浅入深了解Thrift之服务模型和序列化机制

    一.Thrift介绍 Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎.其允许你定义一个简单的定义文件中的数据类型和服务接口.以作为输入文件,编 ...

  6. hrift 的序列化机制

    Thrift 个人实战--Thrift 的序列化机制 前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码 ...

  7. Thrift RPC实战(三) thrift序列化揭秘

    本文主要讲解Thrift的序列化机制, 看看thrift作为数据交换格式是如何工作的? 1.构造应用场景: 1). 首先我们先来定义下thrift的简单结构. 1 2 3 4 5 namespace ...

  8. Thrift 个人实战--初次体验Thrift

    前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还 ...

  9. Thrift RPC实战(一).初次体验Thrift

    1.前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码,主要特点: 开发速度快: 通过编写RPC接口ID ...

随机推荐

  1. HTML表格与列表

    HTML表格 表格其实就是很多的小单元格,而这些小单元格很有次序的排列着,它们有很多行,很多列.这些很多行列组成的东西,就叫表格,表格是<table>标签来定义的.而<table&g ...

  2. Flex 学习笔记 ComboBox内容框宽度

    如何设置ComboBox下拉选项框的宽度呢 左边下拉框发现字符太长了   属性里也找不到相关宽度可以设置,解决如下 <!--添加open事件 打开下拉选项框时设置--> <s:Com ...

  3. Scrum Meeting 7-20151209

    任务安排 姓名 今日任务 明日任务 困难 董元财 服务器购买记录接口 请假(编译攻坚) 无 胡亚坤 发布记录和购买记录 请假(编译攻坚) 无 刘猛 完成Scrum Meeting 请假(编译攻坚) 无 ...

  4. Windows2012安装IIS和FTP

    Windows2012安装IIS和FTP  1.打开Windows 2012的服务器管理器,选择 管理→添加角色和功能  2.进入 添加角色和功能向导,选择 “Web服务器(IIS)” 3.根据情况选 ...

  5. ionic build android--> Build failed with an exception. Execution failed for task ':processDebugResources'.

    执行 ionic build android,   ionic 自动化生成安卓apk包, 出现以上报错的原因为:打包的文件中含有中文名,把中文名的文件去掉或改名即可打包成功.

  6. Web1.0、Web2.0、Web3.0的主要区别

    Web1.0:以静态.单向阅读为主,网站内信息可以直接和其他网站信息进行交互,能通过第三方信息平台同时对多家网站信息进行整合使用. Web2.0:以分享为特征的实时网络,用户在互联网上拥有自己的数据, ...

  7. Grunt自动化构建工具(网址:http://www.gruntjs.net/getting-started或者http://gruntjs.cn/getting-started)

    简介:Grunt是基于Node.js的项目构建工具,对于需要重复执行的任务,例如压缩.编译.单元测试等,自动化工具可以减少你的工作量,使你的工作更轻松. 一:检测nodejs是否安装好,打开CMD控制 ...

  8. [原]Wpf应用Path路径绘制圆弧

    1. 移动指令:Move Command(M):M 起始点  或者:m 起始点比如:M 100,240或m 100,240使用大写M时,表示绝对值; 使用小写m时; 表示相对于前一点的值,如果前一点没 ...

  9. Linux字符设备

    一.linux系统将设备分为3类:字符设备.块设备.网络设备. 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的 ...

  10. iOS开发拓展篇—CoreLocation地理编码

    iOS开发拓展篇—CoreLocation地理编码 一.简单说明 CLGeocoder:地理编码器,其中Geo是地理的英文单词Geography的简写. 1.使用CLGeocoder可以完成“地理编码 ...