Avro
定义
Avro是一个面向数据存储与交换的序列化系统,由Apache软件基金会孵化并维护。按照官方文档的界定,它同时提供4类能力:结构化的数据类型、紧凑而快速的二进制格式、用于持久保存数据的容器文件,以及远程过程调用(RPC)机制[1]。
与许多序列化方案不同,Avro并不把类型信息逐值写入字节流,而是要求每份数据都伴随一份模式(Schema)。模式用JSON书写,描述记录的字段名称、字段类型与嵌套结构,因此凡是具备JSON解析能力的语言都能较容易地实现Avro[1][3]。
Avro常被拿来与Thrift、Protocol Buffers比较,三者目标相近,但Avro在动态类型、无标记数据和字段编号方式上走的是另一条路线[1]。
原理
Avro的模式由原始类型与复杂类型组合而成。原始类型包括 null、boolean、int、long、float、double、bytes 和 string;复杂类型包括 record、enum、array、map、union 和 fixed。一个record至少要声明类型、名称和字段列表,加上namespace后便构成模式的完整名称[4][3]。
在编码层面,Avro的二进制格式刻意做得紧凑:按照规范,二进制编码不包含字段名、不含逐字节的自描述类型信息,也不设字段或记录分隔符。一条记录只是按模式声明顺序拼接起来的字段值,整数按zig-zag变长整数编码,字符串则先写长度再写UTF-8字节。解码器不依赖负载自身来推断结构,而是沿着模式逐字段读取[5]。
由此产生Avro的两模式模型:写入方序列化时使用的模式称为写入模式(writer schema),读取方当前期望的结构称为读取模式(reader schema)。当两者不一致时,由解析规则逐字段比对并完成转换,这一过程通常称为读时模式(schema on read)[6][5]。
写入模式必须对读取方可得。对象容器文件把模式直接写进文件头;单对象编码则在负载前加一段写入模式的指纹,指纹本身只是查找键,仍需模式库换回完整模式[5]。使用RPC时,客户端与服务端在连接握手阶段交换模式,因双方都掌握对方的完整模式,同名字段、缺失字段与多余字段的差异都能被解析[1]。
容器文件的设计还考虑了分布式处理的切分需求。文件头之后是若干数据块,每块带有与头部相同的同步标记、记录数量与压缩后字节长度;HDFS按块切分文件、MapReduce为每个块启动任务时,任务可以从块起点之后最近的同步标记开始处理。Avro采用的块大小约64KB,因此定位开销在整体计算中占比很小[7][8]。
发展历程
Avro源自Hadoop项目内部。道格·卡廷(Doug Cutting)在提议设立该子项目时提出,希望用它同时替换Hadoop原有的RPC机制并承载Pig、Hive等组件的大部分数据文件,最初的提交者除他本人外还有沙拉德·阿加瓦尔(Sharad Agarwal),两人是当时该软件仅有的作者[9]。
在讨论中,Avro与Protocol Buffers、Thrift的差异被明确为模式演进与模式协调方式的不同:Avro把模式与数据放在一起管理,并依赖字段名而非手工分配的数字字段号来解决差异,这被认为更适合HDFS上大规模数据集与表的使用场景[9]。
2009年7月,Avro作为新子项目进入Hadoop。2010年5月,它脱离Hadoop成为Apache顶级项目;Apache软件基金会公布的一批新顶级项目名单中亦包含Avro[10][11]。
此后Avro长期处于维护与小幅迭代状态。2024年9月,项目社区宣布发布1.11.4版本,该版本属于修订版,主要修复Java SDK中的若干缺陷,官方同时建议其他语言的SDK改用1.12.0[12]。
应用
Avro的主要用武之地是Hadoop生态的数据平台。据InfoQ的介绍,MapReduce、Pig、Hive、Crunch、Flume、Sqoop等组件都支持Avro,其设计目标是让一套格式与序列化机制贯穿整个数据平台,而不是只服务于其中少数环节;同时它保留了Hadoop数据格式的常见特性,例如可压缩与可切分[2]。
在流处理与消息系统方向,Avro常与Kafka配合使用,由模式注册中心集中保存与检索模式,消息端通过相应的序列化器注册或取用模式,并可用Avro支持的压缩编解码器压缩负载[13][6]。Dubbo等RPC框架也提供基于Avro的序列化扩展,应用侧通过引入相应依赖并配置即可启用[3]。
模式演进使Avro适合长期保存的数据。常见做法是新增字段时给出默认值,读取旧数据时由默认值补齐;删除字段时读取方跳过写入方多出的字段;字段重命名可在读取方模式中为旧名声明别名;字段顺序变化不影响解析,因为匹配依据是名称而非位置;类型只能单向提升,int可提升为long、float或double,long可提升为float或double,float可提升为double,string与bytes可互换[6][5]。
现实中的兼容性通常分为3种模式:向后兼容指新代码能读旧数据,向前兼容指旧代码能读新数据,二者兼得则称完全兼容。新增字段不提供默认值会破坏向后兼容,这是实践中较常见的故障来源[6][14]。
局限
Avro的紧凑编码以牺牲自描述性为代价。裸二进制负载不含字段名与类型信息,脱离写入模式便无法还原数据含义,因此凡是自行实现存储或传输的场景,都必须额外保存写入模式,模式一旦丢失,字节流就只剩字节[5]。
解析规则虽覆盖不少变更,但并非万能。有分析指出,当记录中多个同类型字段发生增删、而双方模式又无法唯一对应时,规范层面缺少判定依据,这是Avro在模式演进上受到质疑的地方;另有讨论认为,若让解码结果完全确定,需要在二进制编码中引入字段编号,而这会破坏与既有版本的兼容[15]。
具体规则上也存在方向性限制。字段重命名只有在读取方声明了旧名别名时才向后兼容,并不具备向前兼容性;向union类型增加分支同样只向后兼容。一旦数据以更宽的类型写入,窄类型的读取方无法解读,类型提升是单向的[16][5]。
此外,Avro没有内建的二级索引机制,复杂嵌套结构的管理也相对麻烦;各语言实现的成熟度与功能丰富程度并不齐平,同一功能在不同SDK上的支持存在差异[17]。版本升级同样可能带来摩擦,例如1.8.2/1.9与1.11.3之间生成的Java代码在字段访问方式上并不一致,迁移前需要重新编译并调整代码[18]。
参见
参考资料
- Apache Avro 1.7.0 Documentation [引用日期2026-10-29]
- InfoQ Homepage Articles Building Applications With Hadoop [引用日期2026-10-29]
- content/zh-cn/overview/what/ecosystem/serialization/avro.md [引用日期2026-10-29]
- AVRO-1202.2 [引用日期2026-10-29]
- +++ [引用日期2026-10-29]
- xebia.com 上的网页 [引用日期2026-10-29]
- FAQ [引用日期2026-10-29]
- AVRO-160 [引用日期2026-10-29]
- Re: [PROPOSAL] new subproject: Avro [引用日期2026-10-29]
- 百度百科 [引用日期2026-10-29]
- New top-level Apache projects named [引用日期2026-10-29]
- [ANNOUNCE] Apache Avro 1.11.4 released [引用日期2026-10-29]
- Avro [引用日期2026-10-29]
- Avro Schema Evolution: Compatibility Guide [引用日期2026-10-29]
- From the Avro specification: [引用日期2026-10-29]
- githubusercontent.com 上的网页 [引用日期2026-10-29]
- What is Avro and How does it work? [引用日期2026-10-29]
- Apache Avroの使用 - メイン・コンテンツにスキップ [引用日期2026-10-29]