本文主要讲解Thrift的序列化机制, 看看thrift作为数据交换格式是如何工作的?

1.构造应用场景:

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

1
2
3
4
5
namespace java com.yangyang.thrift.api
struct Pair {
    1: required string key
    2: required string value
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private static  String datafile = "1.dat";
// *) 把对象写入文件
public static  void writeData() throws IOException, TException {
    Pair pair = new Pair();
    pair.setKey("key1").setValue("value1");
    FileOutputStream fos = new FileOutputStream(new File(datafile));
    pair.write(new TBinaryProtocol(new TIOStreamTransport(fos)));
    fos.close();
}
// *) 从文件恢复对象
public static  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();
}
public static void main(String[] args) throws Exception{
    //writeData();
    readData();
}

调用writeData(), 把pair{key=> key1, value=> value1} 写入文件1.dat中
然后调用readData(),观察控制台结果为:
key =>key1
value =>value1
3). 如果我重新定义pair结构, 调整数字编号数序

1
2
3
4
5
namespace java com.yangyang.thrift.api
struct Pair {
    2: required string key
    1: required string value
}

评注: 这边2对应key, 1对应value.
重新编译thrift -gen java
4). 然后读取该数据
调用readData(), 注意此时不要在调用writeData(),从文件1.dat中恢复Pair对象来
结果:
key => value1
value => key1
是不是和你预期的相反, 看来属性名称并没有发挥作用, 而id标识在thrift的序列化/反序列化扮演非常重要的角色
带着这些疑惑, 我们进一步的详细解读序列化机制

2.thrift 数据格式描述

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

1
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 大专栏  Thrift RPC实战(三) thrift序列化揭秘_name:field_value => id+type:field_value), 这也解释了上述提到的场景的原因了.
对之前定义的Pair结构体, 进行代码解读:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public void read(org.apache.thrift.protocol.TProtocol iprot, Pair struct) throws org.apache.thrift.TException {
  org.apache.thrift.protocol.TField schemeField;
  //读取结构开始标记
  iprot.readStructBegin();
  while (true)
  {
    // 读取Field属性开始标记
    schemeField = iprot.readFieldBegin();
    if (schemeField.type == org.apache.thrift.protocol.TType.STOP) {
      break;
    }
    // field标记包含 id + type, switch根据(id+type)来分配相关的值
    switch (schemeField.id) {
      case 2: // KEY
        if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
          struct.key = iprot.readString();
          struct.setKeyIsSet(true);
        } else {
          org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
        }
        break;
      case 1: // VALUE
        if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
          struct.value = iprot.readString();
          struct.setValueIsSet(true);
        } else {
          org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
        }
        break;
      default:
        org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
    }
    // 读取Field属性结束标记
    iprot.readFieldEnd();
  }
   // 读取结构体结束标记
  iprot.readStructEnd();
  // check for required fields of primitive type, which can't be checked in the validate method
  struct.validate();
}

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

3.数据交换格式分类

当前的数据交换格式可以分为如下几类:
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| 二进制| 高效| 不宜读, 向后兼容有一定的约定限制|

4.向后兼容实践

  Thrift官方文档, 也提到对新增的字段属性, 采用id递增的方式标识并以optional修饰来添加.

Thrift RPC实战(三) thrift序列化揭秘的更多相关文章

  1. Thrift RPC实战(二) Thrift 网络服务模型

    限于篇幅关系,在观察源码的时候,只列举了部分源代码 TServer类层次体系 TSimpleServer/TThreadPoolServer是阻塞服务模型 TNonblockingServer/THs ...

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

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

  3. Thrift 个人实战--Thrift 的序列化机制

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

  4. JAVA RPC (五) 之thrift序列化RPC消息体

    让大家久等了.继续更新thrift序列化的消息体,下面我们一步一步的看一看thrift的rpc是怎么实例化消息体的. 首先我们先准备一个request文件 namespace java bky str ...

  5. JAVA RPC (四) 之thrift序列化普通对象

    先简单写一个thrift文件 本地通过thrift编译之后会生成一个java源文件.------编译口令 :thrift -gen java mytestrequest.thrift 编译后的源代码如 ...

  6. rpc框架之 thrift 学习 1 - 安装 及 hello world

    thrift是一个facebook开源的高效RPC框架,其主要特点是跨语言及二进制高效传输(当然,除了二进制,也支持json等常用序列化机制),官网地址:http://thrift.apache.or ...

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

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

  8. 开源RPC(gRPC/Thrift)框架性能评测

    海量互联网业务系统只能依赖分布式架构来解决,而分布式开发的基石则是RPC:本文主要针对两个开源的RPC框架(gRPC. Apache Thrift),以及配合GoLang.C++两个开发语言进行性能对 ...

  9. Thrift 个人实战--初次体验Thrift(转)

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

随机推荐

  1. 年近30的Java程序员为了达到月入三万的目标,都做了哪些准备?

    1.我觉得像我这般年纪的(29岁),有相对扎实技术功底的(就不自谦了),对赚钱有着强烈欲望的程序员,应该定一个切实的小目标——五年内月入三万! 之所以要定这个目标,最主要的原因是老婆的批评刺痛了我—— ...

  2. 漫谈设计模式(一):代理(Proxy)模式与适配器(Adapter)模式对比

    1.前言 为什么要将代理模式与适配器模式放在一起来说呢?因为它们有许多的共同点,当然也有一些不同的地方.首先两者都是属于结构型模式.结构型模型是这样定义的: 结构型模式涉及到如何组合类和类以获得更大的 ...

  3. c#学习笔记05——数组&集合

    数组 声明数组 .一维数组的定义: 数据类型[] 数组名=new 数据类型[大小]; eg: ]; ,,,,}; ]; .多维数组的定义 ,];//定义二维数组 ,,];//定义三维数组 多维数组可以 ...

  4. C盘满了解决办法之pagefile.sys文件

    pagefile.sys文件一般存在于C盘,只有点击了隐藏属性才能看见. 这个文件一般比较大,它是系统创建虚拟内存页面的文件.平时大家使用软件的时候对于产生大量的临时数据,这些数据需要占用大量内存,如 ...

  5. POJ 1O17 Packets [贪心]

    Packets Description A factory produces products packed in square packets of the same height h and of ...

  6. 给select赋值之后,再点击选择下拉值时,显示一值不变的解决

    在一个项目需求中,请求数据,得到的数据dataAll渲染到页面的select下拉表单中,当时是需要一进页面就要默认选中第一个选项,所以直接将dataAll的第一个索引值赋值给了表单的绑定值formVa ...

  7. React 通过注释自动生成文档

    最近找了一些文档的生成工具,结果发现了这个 React Styleguidist 可以通过注释,自动生成对应的文档,对于 react 库来说十分方便 安装 npm i -D react-stylegu ...

  8. Hadoop_课堂笔记1

    1.课程目标 实践性 2.课下需要 在家搭建一个伪分布式 3.大数据概念和意义 08年Nature第一次正式提出大数据概念 常规的数据库:结构化的数据库 TB级的结构化数据管理就很困难,需要分布式 当 ...

  9. ansible批量部署(一)

    自动化运维工具shell脚本/Ansible(无客户端)/Saltstack(master-minion) 回顾服务器部署的流程:买云主机->环境部署->软件部署->配置部署-> ...

  10. 许家印67亿买下FF恒大是要雪中送炭吗?

    从大环境来看,当下新能源汽车已经是备受投资者青睐的领域.据不完全统计,当下国内已经有300余家电动汽车企业.而蔚来.小鹏.威马等动辄都融资上百亿元,显现出火爆的发展趋势.甚至就连董明珠董大姐也有着自己 ...