Avro与Protobuf性能对比
所用Schema
Avro所用Schema
{"namespace": "test.avro",
"type": "record",
"name": "User",
"fields": [
{"name": "i", "type": ["int","null"]},
{"name": "l", "type": ["long", "null"]},
{"name": "s", "type": ["string", "null"]},
{"name":"b","type":["boolean","null"]}
]
}
Protobuf所用Schema
message SomeData {
optional int32 i = 1;
optional int64 l = 2;
optional string s = 3;
optional bool b=4;
}
写出的数据:
{
"i" : random,
"l" : random,
"s" : "never",
"b" : random
}
测试对象:
- 用
protoc
将 Protobuf Schema编译成java类来进行操作 - 用
DynamicMessage
动态生成所需的数据结构来进行 Protobuf 的序列化操作 - 用
GenericMessage
根据Avro的定义文件解析出来的Schema进行操作 - 用
GenericMessage
根据动态生成的Schema进行操作
测试结果:
每个测试用了1,000,000
条数据
测试1: 生成文件
其中:
-
Protobuf 用
writeDelimitedTo
方法直接写到文件输出流 -
Avro 用
DataFileWriter
生成输出文件
结果:
- 测试对象1耗时501ms
- 测试对象2耗时985ms
- 测试对象3耗时1356ms
- 测试对象4耗时1343ms
另外:
-
Protobuf 文件大小约为
28m
-
Avro 文件未压缩的状态大小约为
25m
,采用Snappy
压缩后,大小变为18m
测试2: 序列化但不生成文件
其中:
-
Protobuf 用
toByteArray
方法得到byte[]
-
Avro 用
DatumWriter
与DirectBinaryEncoder
来得到byte[]
结果:
-
测试对象1耗时
418ms
-
测试对象2耗时
978ms
-
测试对象3耗时
1741ms
-
测试对象4耗时
1748ms
分析:
-
Avro 不生成文件居然比生成文件还要慢,这主要是
DirectBinaryEncoder
导致的,具体细节还没看 -
Protobuf的两种方式效率差了2倍,这主要是因为对接入的
Field
所采用的方法不同导致的,如果通过FieldName
,速度比直接用对应的get()
方法访问速度慢得多
结论
Protobuf 比 Avro 快2~4倍
其中 Avro的序列化也许还有优化的空间,主要在DirectBinaryEncoder
和Encoder
的差异上