我对Avro进行了调查

我做了一些关于Apache Avro的调查。由于有很多地方我不太理解,所以如果有任何指正或评论,请务必留言。

1. 概括

Avro是一种用于系统间数据交换的格式,具有模式定义和二进制编码的特点。当JSON中的类型不明确且基于字符串的效率低下且令人困惑时,可使用Avro。类似的格式还有Protocol Buffers和Message Pack等。

主要用于文件格式、为RPC定义的协议和Kafka等消息格式。以下不会涉及RPC,因为对此不甚了解。

在日本语中,Apache Avro与Protocol Buffers的资料总结了Avro的概述以及与Protocol Buffers之间的差异,十分易于理解。

关于C、C++、C#、Java、PHP、Python和Ruby,官方都有相应的库可用,但是根据语言的不同,对于(特别是新功能方面的)支持程度似乎略有差异。我认为Go语言主要使用linkedin/goavro。以下说明是以Java为基础的。

2. 主要功能

2.1 数据模式定义

在avsc文件中定义模式。提供了以下数据类型,可以组合来定义字段。尽管稍旧,但参考Oracle NoSQL数据库起步指南的第7章Avro模式的日文文档。

種類データ型Primitive Typesnull, boolean, int, long, float, double, bytes, stringComplex Typesrecord, enum, array, maps, union, fixedLogical TypesDecimal, Date, Time, Timestamp, Duration

Logical Type是一种派生类型,它以Primitive Type作为物理形式进行序列化。

除了可以使用JSON格式来描述模式之外,还可以通过IDL来创建模式。使用IDL可以使用import等功能。

2.1.1 示例模式的例子

从http://avro.apache.org/docs/current/spec.html获取

{"namespace": "example.avro",
 "type": "record",
 "name": "User",
 "fields": [
     {"name": "name", "type": "string"},
     {"name": "favorite_number",  "type": ["int", "null"]},
     {"name": "favorite_color", "type": ["string", "null"]}
 ]

2.1.2 以 IDL 进行模式定义的示例

从AvroHubTool根据Avro IDL合成Avro schema。

(Note: The provided link appears to be written in Japanese, not Chinese.)

@namespace("avro.examples.baseball")
protocol Baseball {
   import schema "name.avsc";
   import schema "coache.avsc";
   import schema "position.avsc";
   import schema "player.avsc";

   record Team {
       Player player;
       Coache  coache;
  }
}

2.1.3 数据结构演进

在Avro中,有互換性的規則,可以在更改模式時保持互換性。但是,公式規範很難理解,所以了解viniciusccarvalho/schema-evolution-samples的解釋和示例,以及Confluent Platform各個組件的特點更容易理解。

互換性の種類説明前方互換新しいスキーマで作られたデータを古いスキーマで読む後方互換古いスキーマで作成されたデータを新しいスキーマで読む

为了保持前向兼容性,在向模式中添加列时需要指定默认值。

2.2 数据格式

Avro提供了三种数据格式,可以根据用途进行选择。由于读写数据需要模式,因此需要考虑头部开销和模式管理来进行决策。

種類内容説明スキーマの運用Binary Encodingバイナリのデータのみ、ヘッダなしBinaryEncoderを使う。単純なエンコーディングとしてのみ使用する場合ディレクトリやトピックとスキーマを規約で対応付けておく。スキーマ更新時は全体で同期をとって対応が必要Object Container Filesヘッダにスキーマ定義を含むDataFileWriterを使う。ファイルでのデータ交換用埋め込まれているスキーマをそのまま利用可能Single-Object Encodingヘッダにスキーマのフィンガープリントを含むBinaryMessageEncoderを使う。Kafkaなどのメッセージング用フィンガープリントを使用してスキーマを解決する

Object Container Files(OCF)的格式可以进行deflate/snappy压缩。此外,它还被BigQuery、RedShift、Spark等支持。您还可以加载Amazon EMR的Avro格式数据到Amazon Redshift进行引用。

为了消息传输目的,由于对象容器文件(Object Container Files)格式的开销较大,所以提供了轻量级的单一对象编码(Single-Object Encoding)作为替代。不过,也可以自行在其中嵌入模式的版本等来解决这个问题。

作为解决动态模式的机制之一,Confluent Schema Registry是一个相对复杂的选择。还可以参考Confluent Platform的各个组件的特点。

2.3 用于序列化的主要类

基本上,可以使用DatumWriter的任何子类以及Encoder或FileWriter进行序列化。序列化的示例请参考Getting Started (Java)。在反序列化中,使用相应的Reader/Decoder。

这个章节是《Oracle NoSQL Database入门指南》的第8章,虽然略微陈旧,但有关Avro绑定的日语文档可在这里找到。

packageclass/Interface説明org.apache.avro.ioDatumWriter(IF)スキーマに従ってインスタンスをEncoderに書き出すorg.apache.avro.ioSpecificDatumWriterスキーマから自動生成されたクラスを使用してシリアライズorg.apache.avro.ioGenericDatumWriterクラスの自動生成を使わずにシリアライズするorg.apache.avro.ioReflectDatumWriter既存のクラスをシリアライズするorg.apache.avro.ioEncoder(IF)フィールドの値をシリアライズするorg.apache.avro.ioBinaryEncoderフィールドの値をバイナリエンコーディングするorg.apache.avro.fileDataFileWriterDatumWriterをObject Container Files形式のファイルに出力する(encoder不要)org.apache.avro.messageMessageEncoder(IF)ByteBuffer, OutputStreamに出力するorg.apache.avro.messageBinaryMessageEncoderSingle Object EncodingでByteBuffer, OutputStreamに出力する

在Python或Ruby中,不支持或者说不需要生成类,只需要相应的GenericDatumWriter。可以参考Python的入门指南或者Ruby中的Avro文档。

考虑到模式演化,在使用SpecificDatumWriter时,我有点困惑如何对自动生成的类进行版本管理。

附录

commercehub-oss/gradle-avro-plugin Gradleのplugin

[AVRO-1891] JavaでLogical Typeを含むUnionができないというバグ。Nullを許可する場合にはunionを使うので、現状ではLogical TypeでNullを許可することができない。1.8.3で対応予定。
GADGT: The futue of gogen-avro
How to encode/decode Kafka messages using Avro binary encoder? – Stack Overflow

广告
将在 10 秒后关闭
bannerAds