序列化性能之巅:使用Fury替换Protobuf/Flatbuffers实现10倍加速

简介: 问题背景Protobuf/Flatbuffers是业界广泛使用的序列化库,服务于大量的业务场景。但随着业务场景的复杂化,Protobuf/Flatbuffers逐渐不能满足性能需求开始成为系统瓶颈,在这种情况下,用户不得不手写大量序列化逻辑来进行极致性能优化,但这带来了三个问题:大量字段手写序列化逻辑冗长易出错;手写重复序列化逻辑开发效率低下;难以处理发送端和接收端字段变更的前后兼容性问题;这里将

问题背景

Protobuf/Flatbuffers是业界广泛使用的序列化库,服务于大量的业务场景。但随着业务场景的复杂化,Protobuf/Flatbuffers逐渐不能满足性能需求开始成为系统瓶颈,在这种情况下,用户不得不手写大量序列化逻辑来进行极致性能优化,但这带来了三个问题:

  • 大量字段手写序列化逻辑冗长易出错;
  • 手写重复序列化逻辑开发效率低下;
  • 难以处理发送端和接收端字段变更的前后兼容性问题;

这里将介绍如何通过我们开发的序列化框架Fury来解决这些问题。Fury是我们开发的一个基于JIT的通用的高性能多语言序列化框架,通过在运行时基于对象类型动态生成序列化代码,和基于Unsafe的高性能内存操作,在保证类型前后兼容(可选)的情况下,实现了全自动的动态序列化能力,能够提供相比于Protobuf/Flatbuffers十倍以上的性能

相比Protobuf/Flatbuffers,Fury不仅有着更高的性能,同时支持直接动态序列化Java原生对象,不需要进行IDL定义和编译,提供了更高的易用性。

本文将首先给出Fury相比于Protobuf&Flatbuffers的性能数据,然后给出快速从Protobuf/Flatbuffers切换到Fury的代码,最后给出对比Protobuf/Flatbuffers的JMH基准测试详细数据。

Fury/Protobuf/Flatbuffers性能对比

这里先给出性能对比TPS图表,纵轴是每秒序列化次数,值越高表示性能越好,横轴是JDK版本。可以看到Fury相比Protobuf最高有11.6倍的性能,相比Flatbuffers最高有8.5倍的性能:

详细数据如下:

  • JDK11序列化:
  • SAMPLE 序列化性能fury是flatbuffers的 7.4倍,是protobuf的 11.6倍
  • MEDIA_CONTENT 序列化性能fury是flatbuffers的 8.5倍,是protobuf的 5倍
  • SAMPLE 反序列化性能fury是flatbuffers的 1.9倍,是protobuf的 5.9倍
  • MEDIA_CONTENT 反序列化性能fury是flatbuffers的 3倍,是protobuf的 3.5倍
  • JDK8序列化:
  • SAMPLE 序列化性能fury是flatbuffers的 6.7倍,是protobuf的 9.8倍
  • MEDIA_CONTENT 序列化性能fury是flatbuffers的 4.2倍,是protobuf的 5.7倍
  • SAMPLE 反序列化性能fury是flatbuffers的 2.6倍,是protobuf的 5.2倍
  • MEDIA_CONTENT 反序列化性能fury是flatbuffers的 1.9倍,是protobuf的 2.2倍

如何快速使用Fury

安装Fury依赖

<dependency>
  <groupId>io.fury</groupId>
  <artifactId>fury-core</artifactId>
  <version>0.11.0</version>
</dependency>

创建Fury实例

// 建议作为一个全局变量,避免重复创建
Fury fury = Fury.builder()
    .withLanguage(Language.JAVA)
    //开启共享引用/循环引用支持,不需要的话建议关闭,性能更快
    .withReferenceTracking(true)
    // 允许序列化未注册类型
    // .withClassRegistrationRequired(false)
    // 开启int/long压缩,减少序列化数据大小,无该类需求建议关闭,性能更好
    // .withNumberCompressed(true)
    .withCompatibleMode(CompatibleMode.SCHEMA_CONSISTENT)
    // 开启类型前后兼容,允许序列化和反序列化字段不一致,无该类需求建议关闭,性能更好
    // .withCompatibleMode(CompatibleMode.COMPATIBLE)
    // 开启异步多线程编译
    .withAsyncCompilationEnabled(true)
    .build();
ThreadSafeFury fury = Fury.builder()
    .withLanguage(Language.JAVA)
    //开启共享引用/循环引用支持,不需要的话建议关闭,性能更快
    .withReferenceTracking(true)
    // 允许序列化未注册类型
    // .withClassRegistrationRequired(false)
    // 开启int/long压缩,减少序列化数据大小,无该类需求建议关闭,性能更好
    // .withNumberCompressed(true)
    .withCompatibleMode(CompatibleMode.SCHEMA_CONSISTENT)
    // 开启类型前后兼容,允许序列化和反序列化字段不一致,无该类需求建议关闭,性能更好
    // .withCompatibleMode(CompatibleMode.COMPATIBLE)
    // 开启异步多线程编译
    .withAsyncCompilationEnabled(true)
    .buildThreadSafeFury();

byte[] bytes = fury.serialize(object);
System.out.println(fury.deserialize(bytes));

序列化任意对象

byte[] bytes = fury.serialize(object);
System.out.println(fury.deserialize(bytes));

JMH基准测试

测试环境

OS:MacBook Pro (16-inch, 2019)

CPU:2.6 GHz 6-Core Intel Core i7

内存:16 GB 2667 MHz DDR4

JMH version: 1.33

JDK version:

  • JDK 1.8.0_292, OpenJDK 64-Bit Server VM, 25.292-b10
  • JDK 11.0.15, OpenJDK 64-Bit Server VM, 11.0.15+10-LTS

测试数据

syntax = "proto3";
package protobuf;

option java_package = "io.fury.integration_tests.state.generated";
option java_outer_classname = "ProtoMessage";

message Sample {
  int32 int_value = 1;
  int64 long_value = 2;
  float float_value = 3;
  double double_value = 4;
  int32 short_value = 5;
  int32 char_value = 6;
  bool boolean_value = 7;
  int32 int_value_boxed = 8;
  int64 long_value_boxed = 9;
  float float_value_boxed = 10;
  double double_value_boxed = 11;
  int32 short_value_boxed = 12;
  int32 char_value_boxed = 13;
  bool boolean_value_boxed = 14;
  repeated int32 int_array = 15;
  repeated int64 long_array = 16;
  repeated float float_array = 17;
  repeated double double_array = 18;
  repeated int32 short_array = 19;
  repeated int32 char_array = 20;
  repeated bool boolean_array = 21;
  string string = 22;
}

message MediaContent {
  Media media = 1;
  repeated Image images = 2;
}

message Media {
  string uri = 1;
  optional string title = 2;
  int32 width = 3;
  int32 height = 4;
  string format = 5;
  int64 duration = 6;
  int64 size = 7;
  int32 bitrate = 8;
  bool has_bitrate = 9;
  repeated string persons = 10;
  Player player = 11;
  string copyright = 12;
}

message Image {
  string uri = 1;
  optional string title = 2; // Can be null.
  int32 width = 3;
  int32 height = 4;
  Size size = 5;
  optional Media media = 6; // Can be null.
}

enum Player {
  JAVA = 0;
  FLASH = 1;
}

enum Size {
  SMALL = 0;
  LARGE = 1;
}

JMH测试代码

序列化JMH测试:

https://code.alipay.com/ray-project/fury/blob/master/integration_tests/src/main/java/io/fury/integration_tests/UserTypeSerializeSuite.java

反序列化JMH测试:

https://code.alipay.com/ray-project/fury/blob/master/integration_tests/src/main/java/io/fury/integration_tests/UserTypeDeserializeSuite.java

JMH参数:

  • 序列化:io.*.integration_tests.UserTypeSerializeSuite.*buffer* -f 3 -wi 5 -i 5 -t 1 -w 2s -r 2s -rf csv
  • 反序列化:io.*.integration_tests.UserTypeDeserializeSuite.*buffer.* -f 3 -wi 5 -i 5 -t 1 -w 2s -r 2s -rf csv

详细运行结果

JDK11序列化测试

测试结果:

  • SAMPLE序列化是flatbuffers的 7.4倍,是protobuf的 11.6倍
  • MEDIA_CONTENT序列化是flatbuffers的 8.5倍,是protobuf的 5倍

Benchmark

Mode

Samples

Tps

Unit

bufferType

objectType

references

Lib

serialize

thrpt

15

8392449.276432

ops/s

array

SAMPLE

False

Fury

serialize

thrpt

15

4763064.092995

ops/s

array

MEDIA_CONTENT

False

Fury

serialize

thrpt

15

6988177.459275

ops/s

array

SAMPLE

False

Fury_compatible

serialize

thrpt

15

3776080.754596

ops/s

array

MEDIA_CONTENT

False

Fury_compatible

serialize

thrpt

15

1136577.337596

ops/s

array

SAMPLE

False

Flatbuffers

serialize

thrpt

15

558153.211617

ops/s

array

MEDIA_CONTENT

False

Flatbuffers

serialize

thrpt

15

725529.918252

ops/s

array

SAMPLE

False

Protobuffers

serialize

thrpt

15

959661.012576

ops/s

array

MEDIA_CONTENT

False

Protobuffers

原始数据:

Benchmark                                         (bufferType)   (objectType)  (references)   Mode  Cnt        Score        Error  Units
UserTypeSerializeSuite.fury_serialize                    array         SAMPLE         false  thrpt   15  8392449.276 ± 719314.595  ops/s
UserTypeSerializeSuite.fury_serialize                    array  MEDIA_CONTENT         false  thrpt   15  4763064.093 ± 570576.187  ops/s
UserTypeSerializeSuite.fury_serialize_compatible         array         SAMPLE         false  thrpt   15  6988177.459 ± 499285.797  ops/s
UserTypeSerializeSuite.fury_serialize_compatible         array  MEDIA_CONTENT         false  thrpt   15  3776080.755 ± 564717.770  ops/s
UserTypeSerializeSuite.flatbuffers_serialize          array         SAMPLE         false  thrpt   15  1136577.338 ± 112188.874  ops/s
UserTypeSerializeSuite.flatbuffers_serialize          array  MEDIA_CONTENT         false  thrpt   15   558153.212 ± 136300.879  ops/s
UserTypeSerializeSuite.protobuffers_serialize         array         SAMPLE         false  thrpt   15   725529.918 ± 105701.221  ops/s
UserTypeSerializeSuite.protobuffers_serialize         array  MEDIA_CONTENT         false  thrpt   15   959661.013 ±  60868.801  ops/s

JDK8序列化测试

测试结果:

  • SAMPLE序列化是flatbuffers的 6.7倍,是protobuf的 9.8倍
  • MEDIA_CONTENT序列化是flatbuffers的 4.2倍,是protobuf的 5.7倍

Benchmark

Mode

Samples

Tps

Unit

bufferType

objectType

references

Lib

serialize

thrpt

15

7787459.437293

ops/s

array

SAMPLE

False

Fury

serialize

thrpt

15

3320120.274126

ops/s

array

MEDIA_CONTENT

False

Fury

serialize

thrpt

15

6728493.639114

ops/s

array

SAMPLE

False

Fury_compatible

serialize

thrpt

15

2357805.065032

ops/s

array

MEDIA_CONTENT

False

Fury_compatible

serialize

thrpt

15

1166516.473685

ops/s

array

SAMPLE

False

Flatbuffers

serialize

thrpt

15

497051.925546

ops/s

array

MEDIA_CONTENT

False

Flatbuffers

serialize

thrpt

15

796889.828561

ops/s

array

SAMPLE

False

Protobuffers

serialize

thrpt

15

581706.298343

ops/s

array

MEDIA_CONTENT

False

Protobuffers

原始数据:

Benchmark                                      (bufferType)   (objectType)  (references)   Mode  Cnt        Score        Error  Units
UserTypeSerializeSuite.flatbuffers_serialize          array         SAMPLE         false  thrpt   15  1166516.474 ± 148035.186  ops/s
UserTypeSerializeSuite.flatbuffers_serialize          array  MEDIA_CONTENT         false  thrpt   15   497051.926 ±  67025.722  ops/s
UserTypeSerializeSuite.protobuffers_serialize         array         SAMPLE         false  thrpt   15   796889.829 ±  81090.299  ops/s
UserTypeSerializeSuite.protobuffers_serialize         array  MEDIA_CONTENT         false  thrpt   15   581706.298 ±  45340.615  ops/s
UserTypeSerializeSuite.fury_serialize                    array         SAMPLE         false  thrpt   15  7787459.437 ± 690347.739  ops/s
UserTypeSerializeSuite.fury_serialize                    array  MEDIA_CONTENT         false  thrpt   15  3320120.274 ± 317451.967  ops/s
UserTypeSerializeSuite.fury_serialize_compatible         array         SAMPLE         false  thrpt   15  6728493.639 ± 724034.571  ops/s
UserTypeSerializeSuite.fury_serialize_compatible         array  MEDIA_CONTENT         false  thrpt   15  2357805.065 ± 146698.800  ops/s

JDK11反序列化测试

测试结果:

  • SAMPLE反序列化是flatbuffers的 1.9倍,是protobuf的 5.9倍
  • MEDIA_CONTENT反序列化是flatbuffers的 3倍,是protobuf的 3.5倍

Benchmark

Mode

Samples

Tps

Unit

bufferType

objectType

references

Lib

deserialize

thrpt

15

3269220.525856

ops/s

array

SAMPLE

False

Fury

deserialize

thrpt

15

2790613.161908

ops/s

array

MEDIA_CONTENT

False

Fury

deserialize

thrpt

15

3200392.443117

ops/s

array

SAMPLE

False

Fury_deserialize_compatible

deserialize

thrpt

15

2084558.335255

ops/s

array

MEDIA_CONTENT

False

Fury_deserialize_compatible

deserialize

thrpt

15

1706566.911191

ops/s

array

SAMPLE

False

Flatbuffers

deserialize

thrpt

15

914600.559409

ops/s

array

MEDIA_CONTENT

False

Flatbuffers

deserialize

thrpt

15

550393.656196

ops/s

array

SAMPLE

False

Protobuffers

deserialize

thrpt

15

804716.689997

ops/s

array

MEDIA_CONTENT

False

Protobuffers

原始数据:

Benchmark                                          (bufferType)   (objectType)  (references)   Mode  Cnt        Score        Error  Units
UserTypeDeserializeSuite.flatbuffers_deserialize          array         SAMPLE         false  thrpt   15  1706566.911 ± 235634.962  ops/s
UserTypeDeserializeSuite.flatbuffers_deserialize          array  MEDIA_CONTENT         false  thrpt   15   914600.559 ± 399501.643  ops/s
UserTypeDeserializeSuite.protobuffers_deserialize         array         SAMPLE         false  thrpt   15   550393.656 ±  76434.813  ops/s
UserTypeDeserializeSuite.protobuffers_deserialize         array  MEDIA_CONTENT         false  thrpt   15   804716.690 ±  88169.705  ops/s
UserTypeDeserializeSuite.fury_deserialize                    array         SAMPLE         false  thrpt   15  3269220.526 ± 257137.052  ops/s
UserTypeDeserializeSuite.fury_deserialize                    array  MEDIA_CONTENT         false  thrpt   15  2790613.162 ± 334259.574  ops/s
UserTypeDeserializeSuite.fury_deserialize                    array         STRUCT         false  thrpt   15  7372205.565 ± 225718.455  ops/s
UserTypeDeserializeSuite.fury_deserialize                    array        STRUCT2         false  thrpt   15  1382060.978 ±  57011.423  ops/s
UserTypeDeserializeSuite.fury_deserialize_compatible         array         SAMPLE         false  thrpt   15  3200392.443 ± 191460.600  ops/s
UserTypeDeserializeSuite.fury_deserialize_compatible         array  MEDIA_CONTENT         false  thrpt   15  2084558.335 ± 217782.898  ops/s
UserTypeDeserializeSuite.fury_deserialize_compatible         array         STRUCT         false  thrpt   15  2995349.308 ± 124593.720  ops/s
UserTypeDeserializeSuite.fury_deserialize_compatible         array        STRUCT2         false  thrpt   15  1079316.796 ±  70189.820  ops/s

JDK8反序列化测试

测试结果:

  • SAMPLE反序列化是flatbuffers的 2.6倍,是protobuf的 5.2倍
  • MEDIA_CONTENT反序列化是flatbuffers的 1.9倍,是protobuf的 2.2倍

Benchmark

Mode

Samples

Tps

Unit

bufferType

objectType

references

Lib

deserialize

thrpt

9

2378639.808937

ops/s

array

SAMPLE

False

Fury

deserialize

thrpt

9

1800751.571585

ops/s

array

MEDIA_CONTENT

False

Fury

deserialize

thrpt

9

2229307.602252

ops/s

array

SAMPLE

False

Fury_deserialize_compatible

deserialize

thrpt

9

1520342.611135

ops/s

array

MEDIA_CONTENT

False

Fury_deserialize_compatible

deserialize

thrpt

15

913254.562922

ops/s

array

SAMPLE

False

Flatbuffers

deserialize

thrpt

15

956873.841489

ops/s

array

MEDIA_CONTENT

False

Flatbuffers

deserialize

thrpt

15

455276.384332

ops/s

array

SAMPLE

False

Protobuffers

deserialize

thrpt

15

819117.894807

ops/s

array

MEDIA_CONTENT

False

Protobuffers

原始数据:

Benchmark                                          (bufferType)   (objectType)  (references)   Mode  Cnt       Score         Error  Units
UserTypeDeserializeSuite.flatbuffers_deserialize          array         SAMPLE         false  thrpt   15  913254.563 ±  38973.187  ops/s
UserTypeDeserializeSuite.flatbuffers_deserialize          array  MEDIA_CONTENT         false  thrpt   15  956873.841 ± 148809.901  ops/s
UserTypeDeserializeSuite.protobuffers_deserialize         array         SAMPLE         false  thrpt   15  455276.384 ±  63507.576  ops/s
UserTypeDeserializeSuite.protobuffers_deserialize         array  MEDIA_CONTENT         false  thrpt   15  819117.895 ±  79179.165  ops/s
UserTypeDeserializeSuite.fury_deserialize                    array         SAMPLE         false  thrpt    9  2378639.809 ±  926405.942  ops/s
UserTypeDeserializeSuite.fury_deserialize                    array  MEDIA_CONTENT         false  thrpt    9  1800751.572 ±  308042.100  ops/s
UserTypeDeserializeSuite.fury_deserialize                    array         STRUCT         false  thrpt    9  6853906.995 ± 1416593.099  ops/s
UserTypeDeserializeSuite.fury_deserialize                    array        STRUCT2         false  thrpt    9  1435421.480 ±  255227.618  ops/s
UserTypeDeserializeSuite.fury_deserialize_compatible         array         SAMPLE         false  thrpt    9  2229307.602 ±  338410.918  ops/s
UserTypeDeserializeSuite.fury_deserialize_compatible         array  MEDIA_CONTENT         false  thrpt    9  1520342.611 ±  208019.019  ops/s
UserTypeDeserializeSuite.fury_deserialize_compatible         array         STRUCT         false  thrpt    9  2579101.454 ±  741134.380  ops/s
UserTypeDeserializeSuite.fury_deserialize_compatible         array        STRUCT2         false  thrpt    9  1084974.752 ±  212686.247  ops/s

关于开源

Fury目前已经完成开源流程审批,即将对外开源,如果有开源社区使用场景非常欢迎私聊@慕白!!!

联系我们

如果想进一步了解Fury,或者对Fury有任何使用问题,欢迎钉钉私聊和通过下方二维码加入Fury用户群(群号:35683646):

Fury系列相关文章

目录
相关文章
|
2月前
|
C++
[序列化协议] --- protobuf
[序列化协议] --- protobuf
23 0
|
4月前
protobuf 序列化和反序列化
protobuf 序列化和反序列化
21 0
|
4月前
|
存储 XML JSON
日常小知识点之序列化结构(protobuf使用及简单原理)
日常小知识点之序列化结构(protobuf使用及简单原理)
63 0
|
4月前
|
XML JSON 网络协议
JSON和Protobuf序列化
因为像TCP和UDP这种底层协议只能发送字节流,因此当我们在开发一些远程过程调用(RPC)的程序时,需要将应用层的Java POJO对象序列化成字节流,数据接收端再反序列化成Java POJO对象。序列化一定会设计编码和格式化,目前常见的编码方式有:
|
8月前
|
XML 存储 JSON
数据序列化工具 Protobuf 编码&避坑指南
我们现在所有的协议、配置、数据库的表达都是以 protobuf 来进行承载的,所以我想深入总结一下 protobuf 这个协议,以免踩坑。 先简单介绍一下 Protocol Buffers(protobuf),它是 Google 开发的一种数据序列化协议(与 XML、JSON 类似)。它具有很多优点,但也有一些需要注意的缺点: 优点: 效率高:Protobuf 以二进制格式存储数据,比如 XML 和 JSON 等文本格式更紧凑,也更快。序列化和反序列化的速度也很快。 跨语言支持:Protobuf 支持多种编程语言,包括 C++、Java、Python 等。 清晰的结构定义:使用 prot
|
9月前
|
缓存 自然语言处理 Rust
比JDK最高快170倍,蚂蚁集团开源高性能多语言序列化框架Fury
Fury是一个基于JIT动态编译和零拷贝的多语言序列化框架,支持Java/Python/Golang/JavaScript/C++等语言,提供全自动的对象多语言/跨语言序列化能力,和相比JDK最高170倍的性能。经过多年蚂蚁核心场景的锤炼打磨,现已正式在Github对外开源:https://github.com/alipay/fury
2384 5
|
11月前
|
JSON 数据格式 C++
Protobuf vs CBOR:新一代的二进制序列化格式
Protobuf vs CBOR:新一代的二进制序列化格式
552 0
|
缓存 自然语言处理 JavaScript
万字长文深度解析JDK序列化原理及Fury高度兼容的极致性能实现
Fury是一个基于JIT动态编译的高性能多语言原生序列化框架,支持Java/Python/Golang/C++/JavaScript等语言,提供全自动的对象多语言/跨语言序列化能力,以及相比于别的框架最高20~200倍的性能。
33745 10
万字长文深度解析JDK序列化原理及Fury高度兼容的极致性能实现
|
存储 分布式计算 JavaScript
Fury系列(四):一个比Kryo/Hessian快30~40倍的类型前后兼容序列化器
问题背景类型前后兼容是复杂业务场景序列化的常见需求。在快速迭代的业务场景当中,读写端经常发生对象字段发生变更:在线应用场景:线上SOFA/HSF应用提供服务给多个调用方,服务的滚动升级以及各个调用方独立更新都可能导致对象类型不一致的情况;在线服务场景:在线服务框架常驻不更改对象类型,但调用方业务逻辑变动独立更新导致对象字段跟服务端不一致;对象持久化场景:对象数据序列化后持久化写入存储(如Spark
1397 2
Fury系列(四):一个比Kryo/Hessian快30~40倍的类型前后兼容序列化器
|
1月前
|
存储 C#
C#中的序列化和反序列化
C#中的序列化和反序列化
12 0

热门文章

最新文章