前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计数据密集型应用(4):Encoding and Evolution

设计数据密集型应用(4):Encoding and Evolution

作者头像
linjinhe
发布2020-02-18 17:17:01
8790
发布2020-02-18 17:17:01
举报
文章被收录于专栏:linjinhe的专栏linjinhe的专栏

第四章主要介绍数据的序列化和反序列化,以及迭代升级过程中如何保证兼容性。

分布式系统滚动升级的过程中,新旧数据与代码是同时并存的。如果出现异常,可能还需要回退程序。因此,升级过程中需要保证:

  1. 向后兼容(Backward compatibility):新代码要能正确读取旧数据。
  2. 向前兼容(Forward compatibility):旧代码要能正确读取新数据。

数据在内存中的时候是一个个“对象”(objects)。 保存到外存或通过网络传输时,得先将这个内存中的对象转换成字节流——这个过程称之为序列化(Serialization)。 反之,将字节流转换成与之对应的“对象”,这个过程叫做反序列化(Deserialization)

常见的支持序列化和反序列化的标准或实现有:

  1. 文本编码:JSON、XML 等。
  2. 二进制编码:Protocol Buffers、Apache Thrift、Apache Avro 等。

文本编码

JSON 和 XML 的优点是,序列化的结果是可读的(human-readable)。 但是缺点也很明显,比如:

  1. JSON 和 XML 的字段都不支持二进制字符串。如果你需要传送一个二进制字符串,得先将其转换成 Base64。
  2. JSON 无法支持完成的 uint64。
  3. 文本编码的序列化结果体积较大。
  4. 文本编码的序列化和反序列化一般都比二进制编码差。

在与浏览器相关的交互中,因为 JavaScript 的原生支持,JSON 占据了绝对的优势。 而在应用后台内部,JSON 和 XML 都不是一个好选择。

二进制编码

Protobuf 和 Thrift

Protobuf 和 Thrift 的设计原理、编码规则、使用方式都非常接近。只要理解了其中一种,另外一种也就手到擒来了。 Protobuf 和 Thrift 的基本使用流程如下:

  1. 通过 Protobuf/Thrift 的 interface definition language(IDL)描述数据的 schema。
  2. 通过 Protobuf/Thrift 的代码生成工具生成相应程序设计语言的源代码。
  3. 在应用代码里调用这些生成的代码。

具体可以参考官方文档,这里就不多讲:

实践中,Protobuf 的性能是优于 Thrift 的,具体可以参考:

书中举了一个简单的例子:

代码语言:javascript
复制
{
    "userName": "Martin",
    "favoriteNumber": 1337,
    "interests": ["daydreaming", "hacking"]
}

上面这个例子,JSON 序列化后长度为 66 字节,Thrift 最少需要 34 字节,Protobuf 则需要 33 字节,Avro 只需要 32 字节(不过理论上 Avro 还需要付出 schema 或 schema 版本信息的开销)

上面的例子对应到 Protobuf 的 schema 如下:

代码语言:javascript
复制
message Person {
  required string user_name = 1; 
  optional int64 favorite_number = 2; 
  repeated string interests = 3;
}

对应的 Protobuf 对象序列化后如下:

从上面的序列化结果可以看出:

  1. 序列化结果中没有标识 requiredoptional 的信息,也没有必要标识。因为 required 是运行时的信息,只需要运行的时候根据当前的 schema 进行检查即可。实际上,required 关键字在 proto3 已经被废弃了(optional 关键字其实也被废弃了,所有 field 默认都是 optional)。
  2. 每一个 field 都与一个 tag number 关联,但没有保存 field name。因此修改 field name 不影响数据的序列化和反序列化。
  3. 每一个 field 都有一个与之对应的类型,修改类型的时候要小心注意其兼容性。
  4. 只要 tag number 正确对应,field 之间的位置可以随便调整。
  5. 反序列化不依赖 schema

关于 Protobuf 序列化编码的详细信息可以参考Protobuf 编码官方文档

Avro

还是上看那个例子,对应到 Avro 的 IDL schema 为:

代码语言:javascript
复制
record Person {
  string userName;
  union { null, long } favoriteNumber = null; 
  array<string> interests;
}

Avro 的 schema 还可用用 JSON 描述:

代码语言:javascript
复制
{
  "type": "record",
  "name": "Person",
  "fields": [
    {"name": "userName", "type": "string"},
    {"name": "favoriteNumber", "type": ["null", "long"], "default": null},
    {"name": "interests", "type": {"type": "array", "items": "string"}}
  ]
}

IDL 描述一般用于人工编写,JSON 描述一般用于自动生成。

序列化结果如下:

Avro 的序列化结果和 Protobuf/Thrift 的最大不同是:Avro 的序列化结果中没有保存 tag number、field name 和数据类型。因此 Avro 的反序列化依赖序列化时的 schema —— 当 avro 将序列化结果写入文件的时候,schema 或 schema 的版本也会一起保存。

关于 Avro 的更多信息,可以参考Avro 官网

小结

  1. JSON 占据了浏览器数据交互的天下。
  2. 分布式系统内部的 RPC 交互是 Protobuf/Thrift 的主战场。实践中,建议优先考虑 Protobuf。
  3. Avro 我没有用过,其设计应该主要用于与 Hadoop 生态的大数据传输。
  4. 在我接触的范围内,XML 除了一些旧系统,已经很少使用了。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文本编码
  • 二进制编码
    • Protobuf 和 Thrift
      • Avro
      • 小结
      相关产品与服务
      文件存储
      文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档