Avro
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第二十五天,点击查看活动详情同样是Apach的另一个二进制编码,Avro 是Hadoop的一个子项目,同样通过模式指定编码的一种数据结构,主要的进攻方向有两条:
- Avro IDL 人工编译。
- JSON 利于机器读取
这里再一次用到之前的案例,Avro 对于同样的内容仅仅使用32个字节的编码
这种二进制编码并没有显著的指示字段和数据类型,只是简单的连接列值而已,字符串仅仅为长度前缀,只有整数使用了可变长度编码。
这样的灵活度不是依靠数据结构本身支撑,而是换了一种思路,对于二进制数据的读写制定一套规则。
写模式和读模式
写模式:指的是对于任意数据可以使用已知模式的所有版本编码,比如编译到应用程序的模式。
读模式:需要根据模式解码某种数据的时候,期望数据符合某种模式。
和传统的编解码不一样,Avro 读写模式之间是可以进行相互转化的。
读写模式特点
最大的特点自在于读写模式不需要完全一致,只需要保持兼容即可,数据被解码读取的时候,通过对比查看读写模式同时将写模式转为读模式进行兼容,但是读写模式的转变需要符合Avro 的规范。
此外写模式和读模式的字段顺序不一样也是没有问题的,因为模式解析会通过字段名称对于字段进行匹配,如果读模式碰到了出现在写模式不在读模式的字段就会过滤,反过来如果读模式需要字段写模式没有提供会使用默认值转化。
模式演化规则
Avro的模式演化规则意味着把新版本的模式作为write,把旧版本的模式设置为reader,向后兼容则是新代码实现reader,旧版本模式为write。
这样实际上就是实现了新版本的写入会
Avro为了保持兼容性,只提供了默认值字段的增删权限,比如新增带有默认值的字段,使用新模式reader读取会使用默认值(如果读模式需要字段写模式没有提供会使用默认值转化),使用旧模式write则会直接过滤,并且只在新模式中可以看见新增默认值字段。
下面是模式演化的一个案例。
Avro 的前后兼容实质就是利write和reader这两个模式切换,利用新旧版本屏蔽的方式兼容代码。
Avro 除了这两个模式的特点之外,还有一个非常特殊的处理是 null 内容的处理,和多数编程语言不同,如果 Avro 中声明 允许为null值,必须要是联合类型。
联合类型:
union {null, long, string}
只有当null是一个联合的分支的时候才允许作为默认值,和ProtocolBuff 和Thrift 都不太一样,它没用默认标签或者列表维护的方式可选。
write 模式选择问题
Avro 还存在比较疑惑的问题那就是如何选择 reader模式如何选择write的版本,关键在于使用的上下文。
有很多记录的大文件:因为Hadoop中所有的记录都使用相同编码,所以在这种上下文中只需要开头包括write模式信息即可表示。
具有单独写入记录的数据库:不同的记录需要不同的模式和不同的版本处理,处理这种情况最简单的方式是每一个记录编码的开头记录一个版本号,并且在数据库中保留一个模式版本列表。reader模式通过从记录的“数据库”中提取write模式完成对应的操作,例如Espresso231就是这样工作的。
网络连接发送记录:在建立连接的时候建立模式建立版本,然后在生命周期当中完成工作,Avro RPC的工作原理就是如此的。
动态生成模式
动态生成模式是 Avro 的还有一项特点是对于动态生成的模式兼容更好,因为不带任何的标点符号,可以快速完成不同模式之间的转化。
比如,如果数据库模式转为 Avro 模式,只需要根据关系模式作为中转即可快速完成转化,同时根据write和read模式的转变快速完成被改变字段的同步工作。
这意味着 Avro的模式转化似乎是他原生的内容。如果使用 Thrift 或者 Protocol Buffers,则需要额外维护一套映射规则,同时维护模式生成器要特别小心错误分配标签的问题。
动态生成模式是 Avro 的设计目标之一,所以它在这一块表现十分出色。
代码生成和动态类型语言
需要注意的是这样的编码框架比较常用于静态语言,对于动态类型编程语言实际上并没有太多的意义。此外对于Avro这样动态生成模式的框架代码生成反而是一种累赘,因为本身就可以通过动态模式完成模式转化。
最后Avro的动态生成模式经常和动态类型数据处理语言结合使用。
模式的优点
通过上面的一系列对比讨论,我们发现模式对比JSON和XML格式相比,使用独特的框架设计以及更简单易懂可维护的特点,被广泛的编程语言支持。
实际上模式框架本身的思想并不是什么新东西,ASN.l 在 1984年首次被标准化的模式定义语言中可以看到类似的影子,ASN.I 本身也被用于SSL证书的二进制编码(DER)当中。
对比模式和XML以及JSON,它们通常具备下面的特点:
- 数据更加紧凑,甚至可以省略数据当中的字段名。
- 模式本身具备文档化价值 ,可维护性要强于XML和JSON。
- 模式具备前后兼容性的检查,对于大系统的升级维护这是非常有必要的。
- 对于静态类型编程语言的用户来说,从模式生成代码的能力是有用的,它能够在编译时进行类型检查。