编码与演化
开发新功能
- 因此数据库可以包含在不同时间写⼊的新⽼数据格式的混合
- 服务端滚动升级
- 客户端看用户心情
- 双向兼容
编码数据的格式
- 在内存中,数据保存在对象,结构体,列表,数组,哈希表,树等中。 这些数据结构针对CPU的⾼效访问和操作进⾏了优化(通常使⽤指针)。
- 如果要将数据写⼊⽂件,或通过⽹络发送,则必须将其编码(encode)为某种⾃包含的字节序列(例如,JSON⽂档)。 由于每个进程都有⾃⼰独⽴的地址空间,⼀个进程中的指针对任何其他进程都没有意义,所以这个字节序列表示会与通常在内存中使⽤的数据结构完全不同
语言特定的格式
- 这类编码通常与特定的编程语⾔深度绑定,其他语⾔很难读取这种数据。如果以这类编码存储或传输数据,那你就和这⻔语⾔绑死在⼀起了。并且很难将系统与其他组织的系统(可能⽤的是不同的语⾔)进⾏集成。
- 为了恢复相同对象类型的数据,解码过程需要实例化任意类的能⼒,这通常是安全问题的⼀个来源如果攻击者可以让应⽤程序解码任意的字节序列,他们就能实例化任意的类,这会允许他们做可怕的事情,如远程执⾏任意代码。
- 在这些库中,数据版本控制通常是事后才考虑的。因为它们旨在快速简便地对数据进⾏编码,所以往往忽略了前向后向兼容性带来的麻烦问题。
- 效率(编码或解码所花费的CPU时间,以及编码结构的⼤⼩)往往也是事后才考虑的。 例如,Java的内置序列化由于其糟糕的性能和臃肿的编码⽽臭名昭着
JSON,XML和⼆进制变体
二进制编码
JSON⽐XML简洁,但与⼆进制格式⼀⽐,还是太占地⽅。这⼀事实导致⼤量⼆进制编码版本JSON &XML的出现,JSON(MessagePack,BSON,BJSON,UBJSON,BISON和Smile等)(例如WBXML和Fast Infoset)。这些格式已经被各种各样的领域所采⽤,但是没有⼀个像JSON和XML的⽂本版本那样被⼴泛采⽤。
Thrift与Protocol Buffffers
字段标签和模式演变
- 因此,为了保持向后兼容性,在模式的初始部署之后添加的每个字段必须是可选的或具有默认值。
数据类型和模式演变
- Protobuf的⼀个奇怪的细节是,它没有列表或数组数据类型,⽽是有⼀个字段的重复标记(这是第三个选项旁边必要和可选)
- Thrift有⼀个专⽤的列表数据类型,它使⽤列表元素的数据类型进⾏参数化。
Avro
作者模式与读者模式
- 有了Avro,当应⽤程序想要编码⼀些数据(将其写⼊⽂件或数据库,通过⽹络发送等)时,它使⽤它知道的任何版本的模式编码数据,例如,架构可能被编译到应⽤程序中。这被称为作者的模式。
- 当⼀个应⽤程序想要解码⼀些数据(从⼀个⽂件或数据库读取数据,从⽹络接收数据等)时,它希望数据在某个模式中,这就是读者的模式。
模式演变规则
使⽤Avro,向前兼容性意味着您可以将新版本的架构作为编写器,并将旧版本的架构作为读者。相反,向后兼容意味着你可以有⼀个作为读者的新版本的模式和作为作者的旧版本。
动态⽣成的模式
不同之处在于Avro对动态⽣成的模式更友善。例如,假如你有⼀个关系数据库,你想要把它的内容转储到⼀个⽂件中,并且你想使⽤⼆进制格式来避免前⾯提到的⽂本格式(JSON,CSV,SQL)的问题。如果你使⽤Avro,你可以很容易地从关系模式⽣成⼀个Avro模式(在我们之前看到的JSON表示中),并使⽤该模式对数据库内容进⾏编码,并将其全部转储到Avro对象容器⽂件【25】中。您为每个数据库表⽣成⼀个记录模式,每个列成为该记录中的⼀个字段。数据库中的列名称映射到Avro中的字段名称。