FlatBuffers去年发布,最近看了一下,与同是出自Google之手的Protocol Buffers非常类似。在官网上介绍,FlatBuffers(简称FB)主要针对game development和对性能有要求的应用。相对于Protocol Buffers(简称PB),FB不需要解析,只通过序列化后的二进制buffer即可完成数据访问。
FB的主要特点有:
1)数据访问不需要解析
将数据序列化成二进制buffer,之后的数据访问直接读取这个buffer,所以读取的效率很高。
2)内存高效、速度快
- 数据访问只在序列化后的二进制buffer,不需额外的内存分配。
- 数据访问速度接近原生的struct,只多了一次解引用(根据起始地址和偏移量,然后取值)
3)弹性
都是可选字段,支持向前、向后兼容
4)生成的代码量小
只需依赖一个头文件
5)强类型
编译时检测错误
6)易于使用
可以解析schema和json文本
7)跨平台
C++/Java/Go不需额外依赖
FB的实现原理:
通过FB序列化后的数据就是一个二进制buffer,内部包含各种objects(structs,tables,vectors),通过offset组织。所以数据可以in-place访问(起始地址+偏移量),就像数组或者struct访问。
FB中table代表一个数据结构,这个table会对应一个vtable,用于指示各个字段在buffer中的偏移量。接下来,在访问某个字段时,直接根据偏移量就可以找到该字段。 由于FB直接访问raw buffer,所以在数据破坏时,会得到脏数据。FB通过Verifier确保不可信buffer数据是正确的。
下面测试了PB和FB,做性能对比,测试场景很简单,构造N个对象,序列化,写入文件,然后再反序列化。测试的对象结构如下:
message Sample { required int32 id = 1; required string name = 2; required int32 ip = 3; repeated int32 addr_list = 4; }
测试结果如下:
记录个数 |
FlatBuffers |
Protocol Buffers |
10000 |
0.197 / 4.4M / 0.02 |
0.166 / 3.0M / 0.08 |
20000 |
0.383 / 8.8M / 0.03 |
0.248 / 6.4M / 0.168 |
30000 |
0.534 / 13M / 0.05 |
0.378 / 10M / 0.26 |
100000 |
1.937 / 44M / 0.144 |
1.314 / 38M / 0.8 |
200000 |
3.9 / 88M / 0.276 |
2.66 / 67M / 1.542 |
1000000 |
17.59 / 439M / 1.396 |
13.355 / 397M / 8.012 |
X / Y / Z三个数据,分别对应,序列化总时间 / 文件大小 / 反序列时间,其中包括读写文件的时间。可以看到,PB在序列化的时间和大小都要优于FB,序列化要快30%左右,序列化数据大小要小20%左右。而FB由于不需要解析,反序列化异常快。
虽然FB的反序列化超级快,但是数据大小还是蛮大的(可能的原因是不需要解析,直接访问binary buffer,所以不能对数据进行压缩),带来的传输或存储开销,可能会抵过一部分反序列化的时间。感觉上,FB的使用场景上还是很受限,在移动端可能是一个应用场景。
具体测试代码见github