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

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

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

1
2
3
4
5
6
namespace java mmxf.thrift;
 
struct Pair {
  1: required string key
  2: required string value
}

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

2). 编写测试代码

1
2
3
4
5
6
7
8
9
10
11
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结构, 调整数字编号数序

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

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

4). 然后读取该数据

1
2
3
4
5
6
7
8
9
10
11
12
13
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对象来
结果:

1
2
key => column-family
value => rowkey

是不是和你预期的相反, 看来属性名称并没有发挥作用, 而id标识在thrift的序列化/反序列化扮演非常重要的角色

带着这些疑惑, 我们进一步的详细解读序列化机制

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_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
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的封装改造, 敬请期待.

 

hrift 的序列化机制的更多相关文章

  1. 深入挖掘.NET序列化机制——实现更易用的序列化方案

    .NET框架为程序员提供了“序列化和反序列化”这一有力的工具,使用它,我们能很容易的将内存中的对象图转化为字节流,并在需要的时候再将其恢复.这一技术的典型应用场景包括[1] : 应用程序运行状态的持久 ...

  2. Hadoop阅读笔记(六)——洞悉Hadoop序列化机制Writable

    酒,是个好东西,前提要适量.今天参加了公司的年会,主题就是吃.喝.吹,除了那些天生话唠外,大部分人需要加点酒来作催化剂,让一个平时沉默寡言的码农也能成为一个喷子!在大家推杯换盏之际,难免一些画面浮现脑 ...

  3. Java序列化机制

    java的序列化机制支持将对象序列化为本地文件或者通过网络传输至别处, 而反序列化则可以读取流中的数据, 并将其转换为java对象. 被序列化的类需要实现Serializable接口, 使用Objec ...

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

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

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

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

  6. 1 weekend110的复习 + hadoop中的序列化机制 + 流量求和mr程序开发

    以上是,weekend110的yarn的job提交流程源码分析的复习总结 下面呢,来讲weekend110的hadoop中的序列化机制 1363157985066      13726230503  ...

  7. hadoop序列化机制与java序列化机制对比

    1.采用的方法: java序列化机制采用的ObjectOutputStream 对象上调用writeObject() 方法: Hadoop 序列化机制调用对象的write() 方法,带一个DataOu ...

  8. Strom序列化机制

    Storm 中的 tuple可以包含任何类型的对象.由于Storm 是一个分布式系统,所以在不同的任务之间传递消息时Storm必须知道怎样序列化.反序列化消息对象. Storm 使用 Kryo库对对象 ...

  9. 输入和输出--java序列化机制

    对象的序列化 什么是Java对象的序列化? 对象序列化的目标是将对象保存到磁盘上,或允许在网络中直接传输对象.对象序列化机制允许把内存中的Java对象转换成与平台无关的二进制流,从而保存或者传输.其他 ...

随机推荐

  1. 新秀翻译(两)——使用Java通用配置模板方法模式

    假设你发现你已经非常重码,你可能会考虑使用模板的方法来消除easy重复错误代码.下面是一个示例:以下两类,他完成了几乎相同的功能: 实例化并初始化一个Reader来读取CSV文件. 读取每一行并解析: ...

  2. Forbidden You don't have permission to access / on this server.

    原文:Forbidden You don't have permission to access / on this server. Forbidden You don't have permissi ...

  3. Ajax跨域请求数据实例(JSOPN方式)

    今天在做取消申请的时候遇到了一个跨域ajax提交的问题. 情景是: 系统A是asp.net的站点,其中包括一个取消申请的接口(get方式通过参数提交到系统的某一个页面,然后返回提交成功或失败) 系统B ...

  4. Linux centos 主机名颜色设置 和 别名设置

    方便和乐趣写今天.至于为什么主机名颜色设置 和 别名设置放在一起写.这是因为他们的设置是在一个文件中..bashrc. .bashrc放在cd /root 这个文件夹下! 这个文件主要保存个人的一些个 ...

  5. Android经常使用的布局类整理(一)

    Android经常使用的布局类整理 近期又回头做了一下android的项目,发觉越来越不从心,非常多东西都忘了,简单的页面布局也非常多写不出来,首先还是先整理一下一些会混淆的概念先 layout_wi ...

  6. Qt Quick 组件和动态创建的对象具体的解释

    在<Qt Quick 事件处理之信号与槽>一文中介绍自己定义信号时,举了一个简单的样例.定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Co ...

  7. SQL Prompt5 破解版+使用说明 [转]

    SQL脚本越写越多,总是觉得编写效率太过于低下,这和打字速度无关.在我个人编写SQL脚本时,至少会把SQL的格式排列成易于阅读的,因为其他人会阅读到你的SQL,无论是在程序中或是脚本文件中,良好的排版 ...

  8. Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds解

    产生了一个解决这个问题的方法是在项目部署到tomcat比长45第二,当项目是比较大的,框架复杂的问题经常发生. 解决方法非常easy,找到以下这个路径中 workspace\.metadata\.pl ...

  9. iOS程序 # 启动过程

    [ App 应用 ] 中文名:缺省 外文名:default 拼音:quē shěng 释义:系统默认状态 全称:缺省状态 -------------- 1.程序启动顺序 1> main.m程序入 ...

  10. IIS7伪静态化URL Rewrite模块

    原文 IIS7伪静态化URL Rewrite模块 在Win7安装了IIS7.5之后,搭建一些网站或者博客,但是IIS7.5本身没有URL Rewrite功能,也就是无法实现网址的伪静态化. 从网上找了 ...