前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 FlatBuffers 提高反序列化性能

使用 FlatBuffers 提高反序列化性能

作者头像
用户5166556
发布2023-03-18 15:07:55
9290
发布2023-03-18 15:07:55
举报
文章被收录于专栏:让技术和时代并行

最近一直在寻找一个性能和资源占用兼具的序列化和反序列化工具,大多组织都是采用的 JSON, JSON 可以做到数据的前后兼容,并且更容易让人理解和可视化,但 JSON 的性能相对更差,自身的元数据也会占用更多的存储空间。

本来打算使用协议更紧凑的 protobuffer 作为序列化工具,于是搜索一下它和 JSON 之间的性能对比,发现了如下几篇文章:

https://codeburst.io/json-vs-protocol-buffers-vs-flatbuffers-a4247f8bda6f

https://engineering.fb.com/2015/07/31/android/improving-facebook-s-performance-on-android-with-flatbuffers/

https://juzii.gitee.io/2020/03/02/protobuf-vs-flatbuffer/

以纳秒/运算为单位的反序列化性能

以纳秒/运算为单位的序列化性能

这篇文章其中提到另外一种序列化工具 FlatBuffers,根据官网介绍https://google.github.io/flatbuffers/,FlatBuffers是一个高效的、跨平台的序列化组件,保证数据向前向后兼容性,支持多种编程语言,是专门为游戏开发和其他性能关键的应用而开发的。它与Protobuf确实比较相似,最主要的区别就是,FlatBuffers并不需要一个转换/解包的步骤就可以获取原数据。

比如在游戏场景下的网络通信中,玩家往往是对延迟非常敏感的(尤其是在FPS,Moba类游戏中),抛去网络本身的网络延迟不谈,如果能够降低数据解析(反序列化)的延迟,就能降低玩家操作的延迟感,提升游戏体验。

fb 到底能比 pb 快多少?

我自己做了一个测试,结果如下:fb的序列化要略慢于pb的序列化,但是fb的反序列化要远远超过pb的反序列化。

代码语言:javascript
复制
 Benchmark                       Mode  Cnt         Score         Error  Units
 c.s.fb.SampleTest.deserialize  thrpt    5  84352854.022 ± 4278679.805  ops/s
 c.s.fb.SampleTest.serialize    thrpt    5    316259.628 ±    2395.626  ops/s
 c.s.pb.SampleTest.deserialize  thrpt    5   1407501.471 ±  221477.754  ops/s
 c.s.pb.SampleTest.serialize    thrpt    5    396038.869 ±   81730.806  ops/s

测试过程很简单,主要分为序列化和反序列化两部分,序列化比较简单,直接使用jmh执行即可;反序列化首先需要把相应序列化的二进制数据写入文件,静态读取二进制文件数据,进行反序列化操作。

pb文件
代码语言:javascript
复制
syntax = "proto2";

package com.test.pb;

option java_outer_classname = "SampleProto";

message Sample {
    optional uint32 intData = 1;
  // 数据消息
    optional uint64 longData = 2;
  // string数据
    optional string str1 = 3;
    optional string str2 = 4;
    optional string str3 = 5;
    optional string str4 = 6;
    optional string str5 = 7;
    optional string str6 = 8;
    optional string str7 = 9;
    optional string str8 = 10;
  // 数组
   repeated string person = 11;
}
pb序列化
代码语言:javascript
复制
 @Benchmark
    public static byte[] serialize() {
        SampleProto.Sample.Builder builder = SampleProto.Sample.newBuilder();
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            list.add("中国经济复苏+" + i);
        }
        byte[] bytes = builder.setIntData(100).setLongData(System.currentTimeMillis())
                .setStr1("306bb851-9a0a-4b07-b22b-7ff49a2a60e1")
                .setStr2("306bb851-9a0a-4b07-b22b-7ff49a2a60e2")
                .setStr3("306bb851-9a0a-4b07-b22b-7ff49a2a60e3")
                .setStr4("306bb851-9a0a-4b07-b22b-7ff49a2a60e4")
                .setStr5("306bb851-9a0a-4b07-b22b-7ff49a2a60e5")
                .setStr6("306bb851-9a0a-4b07-b22b-7ff49a2a60e6")
                .setStr7("306bb851-9a0a-4b07-b22b-7ff49a2a60e7")
                .setStr8("306bb851-9a0a-4b07-b22b-7ff49a2a60e8")
                .addAllPerson(list).build().toByteArray();
        return bytes;

    }
pb反序列化
代码语言:javascript
复制
 @Benchmark
    public static SampleProto.Sample deserialize() throws InvalidProtocolBufferException {
        SampleProto.Sample builder = SampleProto.Sample.parseFrom(bytes);
        return builder;
    }
fb 文件
代码语言:javascript
复制
// 指定生成消息类的Java包
namespace com.test.fb;

// 消息
table Sample {
    // int32数据
    intData:int;
    // 数据消息
    longData:float;
    // string数据
     str1:string;
     str2:string;
     str3:string;
     str4:string;
     str5:string;
     str6:string;
     str7:string;
     str8:string;
     // 数组
     person:[string];
}
fb序列化
代码语言:javascript
复制
@Benchmark
    public static byte[] serialize() {
        FlatBufferBuilder flatBufferBuilder = new FlatBufferBuilder();

        int str1 = flatBufferBuilder.createString("306bb851-9a0a-4b07-b22b-7ff49a2a60e0");
        int str2 = flatBufferBuilder.createString("306bb851-9a0a-4b07-b22b-7ff49a2a60e1");
        int str3 = flatBufferBuilder.createString("306bb851-9a0a-4b07-b22b-7ff49a2a60e2");
        int str4 = flatBufferBuilder.createString("306bb851-9a0a-4b07-b22b-7ff49a2a60e3");
        int str5 = flatBufferBuilder.createString("306bb851-9a0a-4b07-b22b-7ff49a2a60e4");
        int str6 = flatBufferBuilder.createString("306bb851-9a0a-4b07-b22b-7ff49a2a60e5");
        int str7 = flatBufferBuilder.createString("306bb851-9a0a-4b07-b22b-7ff49a2a60e6");
        int str8 = flatBufferBuilder.createString("306bb851-9a0a-4b07-b22b-7ff49a2a60e7");
        int[] index = new int[20];
        for (int i = 0; i < 20; i++) {
            index[i] = flatBufferBuilder.createString("中国经济复苏+" + i);
        }
        int vectorOfTables = flatBufferBuilder.createVectorOfTables(index);
        int sample = Sample.createSample(flatBufferBuilder, 100, System.currentTimeMillis(),
                str1, str2, str3, str4, str5, str6, str7, str8, vectorOfTables);
        flatBufferBuilder.finish(sample);
        return flatBufferBuilder.sizedByteArray();
    }
fb反序列化
代码语言:javascript
复制
@Benchmark
    public static Sample deserialize() {
        return Sample.getRootAsSample(ByteBuffer.wrap(bytes));
    }

以上数据生成的二进制文件, pb 大小为 0.763kb,fb 大小为 1.076kb,fb 的存储占用高出了将近 29%,当然如果是纯数字 pb 还会进一步压缩。

为什么 fb 的反序列化速度这么快?

要搞清楚反序列化快的原因,就得弄明白序列化的过程,因为反序列化是序列化的逆向操作。

FlatBuffers 把对象数据,保存在一个一维的数组中,将数据都缓存在一个 ByteBuffer 中,每个对象在数组中被分为两部分。元数据部分:负责存放索引。真实数据部分:存放实际的值。然而 FlatBuffers 与大多数内存中的数据结构不同,它使用严格的对齐规则和字节顺序来确保 buffer 是跨平台的。此外,对于 table 对象,FlatBuffers 提供前向/后向兼容性和 optional 字段,以支持大多数格式的演变。除了解析效率以外,二进制格式还带来了另一个优势,数据的二进制表示通常更具有效率。我们可以使用 4 字节的 UInt 而不是 10 个字符来存储 10 位数字的整数。

FlatBuffers 对序列化基本使用原则:

  • 小端模式。FlatBuffers 对各种基本数据的存储都是按照小端模式来进行的,因为这种模式目前和大部分处理器的存储模式是一致的,可以加快数据读写的数据。
  • 写入数据方向和读取数据方向不同。

简单来说, fb 在进行数据序列化的过程中,已经记录了数据的位置和偏移量。这也是序列化后的数据要略大于 pb 的原因。

FlatBuffers 反序列化的过程就很简单了。由于序列化的时候保存好了各个字段的 offset,反序列化的过程其实就是把数据从指定的 offset 中读取出来。

整个反序列化的过程零拷贝,不消耗占用任何内存资源。并且 FlatBuffers 可以读取任意字段,而不是像 Json 和 Protobuf 需要读取整个对象以后才能获取某个字段。FlatBuffers 的主要优势就在反序列化这里了。所以 FlatBuffers 可以做到解码速度极快,或者说无需解码直接读取。

总结

FlatBuffers 和 Protobuf 一样具有数据不可读性,必须进行数据解析后才能可视化数据。但是相比其它的序列化工具,FlatBuffers 最大的优势是反序列化速度极快,或者说无需解码。如果使用场景是需要经常解码序列化的数据,则有可能从 FlatBuffers 的特性中获得巨大收益。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生技术爱好者社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • fb 到底能比 pb 快多少?
    • pb文件
      • pb序列化
        • pb反序列化
          • fb 文件
            • fb序列化
              • fb反序列化
                • 为什么 fb 的反序列化速度这么快?
                • 总结
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档