《设计数据密集型应用》第四章(1) 编码和演化

数据在内存中,一般是用对象、结构体、列表、Hash表、树等处理的,但在数据存储和传输时,需要对数据进行编码解码才能实现。互联网应用是持续在更新的,应用的更新通常会伴随着数据结构的变化,一般情况下的升级模式可能会有出现以下的问题:

  • 服务端:采用滚动升级的方式,新旧代码读写数据库中的同一份表结构
  • 客户端:可能并不会立即跟进升级

因此,这就要求数据格式支持以下的两个特性:

  • 后向兼容:新版本代码可以读取旧版本代码写入的数据
  • 前向兼容:旧版本代码可以读取新版本代码写入的数据

一般后向兼容不难实现,因为新代码是已知旧代码写入的数据格式的,可以进行显式处理;前向兼容更困难一些,它需要旧代码忽略新代码写入的部分数据。

本章我们会介绍一些常见的数据编码格式,比如JSON、XML、Protocol Buffer、Thrift和Avro等,是如何处理schema变化的。然后介绍数据存储和通信的方式,比如REST、RPC和消息队列等。

JSON、XML和二进制变体

JSON和XML是被广泛使用的通用编码方式。XML具有良好的可读性,并且并不复杂;JSON被web浏览器内置支持,并且更加简单。但它们有一些其他问题:

  • 数字处理的问题。XML无法确定是数字还是字符串;JSON虽然可以区分数字还是字符串,但不能区分整型和浮点型,并且不能指定浮点型的精度;
  • 不支持二进制字符串。JSON和XML支持Unicode编解码,不支持用Base64等方式编码得到的二进制字符串;
  • 无schema定义或者schema定义语言复杂,有些JSON/XML的schema定义方式需要在代码中进行硬编码;
  • CSV由于不存在schema,每列的含义是由应用定义的,很难进行行列的变化。

尽管存在上述的问题,由于JSON、XML和CSV在一些场景,比如数据传输等,已经可以满足需求了,因此仍将是广泛流行的编码方式。

二进制编码

JSON有很多支持二进制编码的衍生编码格式,比如MessagePack、BSON、BJSON、UBSJON、BISON等,编码的原理并不复杂,这里不做详细介绍了,下面贴出一个MessagePack的编码实例图:


MessagePack的编码实例图

Thrift和Protocol Buffers

Thrift和Protobuf是基于相同的原理的二进制编码方式,Thrift是Facebook提出的,Protobuf是Google提出的,它们都是由一种叫接口定义语言(IDL,interface define language)确定的数据结构:


Thrift

Protobuf

Thrift和Protobuf都有对应的代码生成工具,可以生成多种语言支持的类代码。

编码方式

Thrift有两种编码方式,分别为BinaryProtocol和CompactProtocol,先来看下BinaryProtocol的编码结果:


Thrift BinaryProtocol

BinaryProtocol的编码特点:

  • 每个字段都有类型和长度标识,数据中的字符串使用ASCII或UTF-8编码;
  • 用字段编号替换了字段名称,压缩了名称需要的空间。

再来看下CompactProtocol的编码结果:


Thrift CompactProtocol

CompactProtocol的编码特点:

  • 使用变长字节进行数字编码,用sign标识编码是否结束,减少数字的编码结果使用的空间。

最后看下Protobuf的编码结果:


Protobuf

Protobuf支持某字段可选的语法optional,但不影响编码的过程,区别在于required的字段在运行时检查是否存在。

schema变化

对于Thrift格式,每个字段都有相应的数字tag,因此当需要添加新的字段时,只需要按照顺序,为新的字段添加新的tag即可,这里需要注意的点是:

  • 不能修改已有tag的字段,这样会造成格式混乱;
  • 新的字段要声明成为optional的,保证旧代码写入不会报错;
  • 删除已有字段,也只能删除声明为optional的,并且字段的tag不能被再次使用。

如果要进行数据类型的变化,可能会导致精度的丢失或者超精度结果被丢弃,比如32位整形和64位整形的转换。Protobuf和Thrift在处理列表类型时有一些区别:

  • Protobuf支持列表和非列表类型的转换。在Protobuf中,列表是通过关键字repeated定义的,当一个字段从非repeated修改为repeated时,新的代码读取的历史数据是0或者1个长度的数组,旧代码读取的新数据是列表的最后一个元素;
  • Thrift自带数组类型,因此不允许像Protobuf这样可以进行数组和非数组类型的转换。

Avro

Avro主要是针对Hadoop的处理场景产生的编码格式,Avro的格式和数据样例如下:


Avro IDL

Avro Data

Avro的编码结果如下所示:


Avro编码结果
编码方式

Avro将读schema和写schema分离,分别用于解码和编码。当数据解码时,Avro会对比读schema和写schema,并完成数据从写schema到读schema的转换。这里对两份schema中字段的顺序是不关心的。


Avro的读取过程
schema变化

添加或者删除字段,必须要该字段支持以null作为默认值,这样才可以保证后向兼容和前向兼容,null为默认值在Avro的schema中必须进行显式指定。

修改字段的数据类型比较容易,因为Avro会自动根据schema进行类型转换。修改字段名称会麻烦一点,读schema支持为字段设置别名,可以设置为修改前的写schema的字段名。因此修改字段支持后向兼容,但不支持前向兼容。

如何获取写schema

在进行数据解码时,如何获取写数据时使用的schema呢?这里有几种方式:

  • 文件:对于Hadoop的场景,可能是一个大的文件,包含很多记录,那是可以把写schema存储在整个文件的开头。
  • 数据库:写入到数据库中的每条记录使用的写schema可能不一样,因此在每条记录的开头保存写schema的版本号,然后在数据库中保存版本号和schema的对应关系。
  • 网络传输:在连接建立时先将写schema传输过来,然后在整个连接过程都使用这个写schema。
动态生成schema

Avro和前两个格式相比,由于避免了必须显式的指定每个字段的标签顺序,因此可以很方便的由代码动态生成schema,在schema变化时是很方便的。

Schema的好处

在学习完JSON、XML和Thrift、Protobuf和Avro这些格式后,我们看到后者的schema定义要比前者更简单和直接,并且包含更加丰富的校验信息。

类似JSON这种,schemaless或者schema-on-read的格式灵活性是更好的,但二进制数据格式的schema可以带来以下的好处:

  • 压缩比:摒弃了编码后数据中的字段名称;
  • 可读性:schema是可读的,可以很直接的看到schema是否是最新的;
  • 兼容性检查:将所有的schema保存在数据库中,可以直观的进行后向兼容和前向兼容的判断;
  • 代码生成:为静态语言生成类代码,可在编译时进行代码检查。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343