Fury 是一个基于 JIT 动态编译和零拷贝的多语言序列化框架,支持 Java/Python/Golang/JavaScript/C++ 等语言,提供全自动的对象多语言 / 跨语言序列化能力,和相比 JDK 最高 170 倍的性能。
代码主仓库的 GitHub 地址为:src="https://static001.geekbang.org/wechat/images/95/95d1a9d1f8225559fa1ae8da44b072ee.png"/>
背景
序列化是系统通信的基础组件,在大数据、AI 框架和云原生等分布式系统中广泛使用。当对象需要 跨进程、跨语言、跨节点传输、持久化、状态读写、复制时,都需要进行序列化,其性能和易用性影响运行效率和开发效率 。
静态序列化框架 protobuf/flatbuffer/thrift 由于不支持对象引用和多态、需要提前生成代码等原因, 无法作为领域对象直接面向应用进行跨语言开发 。而动态序列化框架 JDK 序列化 /Kryo/Fst/Hessian/Pickle 等,尽管提供了易用性和动态性,但 不支持跨语言,且性能存在显著不足 ,并不能满足高吞吐、低延迟和大规模数据传输场景需求。
因此,我们开发了一个新的 多语言序列化框架 Fury ,并正式在 Github 开源。通过一套 高度优化的序列化基础原语 ,结合 JIT 动态编译和 Zero-Copy 等技术,同时满足了 性能、功能和易用性 的需求,实现了 任意对象自动跨语言序列化,并提供极致的性能 。
Fury 简介
Fury 是一个基于 JIT 动态编译和零拷贝的多语言序列化框架,提供极致的性能和易用性:
序列化核心能力
尽管不同的场景对序列化有需求,但序列化的底层操作都是类似的。因此 Fury 定义和实现了一套序列化的基础能力, 基于这套能力能够快速构建不同的多语言序列化协议,并通过编译加速等优化具备高性能。同时针对一种协议在基础能力上的性能优化,也能够让所有的序列化协议都受益 。
序列化原语
序列化涉及的常见操作主要包括:
Fury 针对这些操作在每种语言内部都做了大量的优化,结合 SIMD 指令和语言高级特性,将性能推到极致,从而方便不同协议使用。
零拷贝序列化
在大规模数据传输场景,一个对象图内部往往有多个 binary buffer,而序列化框架在序列化过程当中会把这些数据写入一个中间 buffer,引入多次耗时内存拷贝。Fury 借鉴了 pickle5、ray 以及 arrow 的零拷贝设计,实现了一套 Out-Of-Band 序列化协议,能够把一个对象图当中的所有 binary buffer 直接抓取出来,避免掉这些 buffer 的中间拷贝 ,将序列化期间的内存拷贝开销降低到 0。
下图是 Fury 关闭引用支持时 Zero-Copy 的大致序列化过程。
目前 Fury 内置了以下类型的 Zero-Copy 支持:
用户也可以基于 Fury 的接口扩展新的零拷贝类型。
JIT 动态编译加速
对于要序列化的自定义类型对象,其中通常包含大量类型信息,Fury 利用这些类型信息在运行时直接生成高效的序列化代码 ,将大量运行时的操作在动态编译阶段完成,从而 增加方法内联和代码缓存,减少虚方法调用 / 条件分支 /Hash 查找 / 元数据写入 / 内存读写 等,最终大幅加速了序列化性能。
对于 Java 语言,Fury 实现了一套运行时代码生成框架,定义了一套序列化逻辑的算子表达式 IR,在运行时基于对象类型的泛型信息进行类型推断,然后构建 一颗描述序列化代码逻辑的表达式树,根据表达式树生成高效的 Java 代码 ,再在运行时通过 Janino 编译成字节码,再加载到用户的 ClassLoader 里面或者 Fury 创建的 ClassLoader 里面,最终通过 Java JIT 编译成高效的汇编代码。
由于 JVM JIT 会跳过大方法编译和内联,Fury 也实现了一套 优化器 ,将大方法递归拆分成小方法,这样就保证了 Fury 生成的 所有代码都可以被编译和内联 ,压榨 JVM 的性能到极致。
同时 Fury 也支持 异步多线程动态编译 ,将不同序列化器的代码生成任务提交到线程池执行,在编译完成之前使用 解释模式 执行,从而保证 不会出现序列化毛刺,不需要提前预热所有类型的序列化 。
Python 和 JavaScript 场景也是采用的类似代码生成方式,这样的生成方式开发门槛低,更容易排查问题。
由于序列化需要密切操作每种编程语言的对象,而编程语言并没有暴露内存模型的低阶 API,通过 Native 方法调用存在较大开销,因此我们并不能通过 LLVM 构建一个统一的序列化器 JIT 框架,而是需要在每种语言内部结合语言特性实现特定的代码生成框架以及序列化器构建逻辑。
静态代码生成
尽管 JIT 编译能够大幅提升序列化效率,并且在运行时能够根据数据的统计分布重新生成更优的序列化代码,但 C++/Rust 等语言不支持反射,没有虚拟机,也没有提供内存模型的低阶 API,因此我们无法针对这类语言通过 JIT 动态编译生成序列化代码。
对于此类场景,Fury 正在实现一套 AOT 静态代码生成框架,在编译时根据对象的 schema 提前生成序列化代码,然后使用生成的代码进行自动序列化。对于 Rust,未来也会通过 Rust 的 macro 在编译时生成代码,提供更好的易用性。
缓存优化
在序列化 自定义类型 时,会把 字段进行重排序 ,保证相同接口类型的字段依次序列化,增加 缓存命中的概率 ,同时也促进了 CPU 指令缓存 ,实现了更加高效的序列化。 对于基本类型字段将写入顺序按照字节字段大小降序排列 ,这样如果开始地址是对齐的,随后的读写都会发生在内存地址对齐的位置,CPU 执行起来更加高效。
多协议设计与实现
基于 Fury 提供的多语言序列化核心能力,我们在这之上构建了三种序列化协议,分别适用于不同的场景:
后续我们也会针对一些核心场景添加新的协议,用户也可以基于 Fury 的序列化能力构建自己的协议。
Java 序列化
由于 Java 在大数据、云原生、微服务和企业级应用的广泛使用,对 Java 序列化的性能优化可以大幅降低 系统延迟,提升吞吐率,降低服务器成本 。
因此 Fury 针对 Java 序列化进行了大量极致性能优化,我们的实现具备以下能力:
跨语言对象图序列化
跨语言对象图序列化主要用于对动态性和易用性有更高要求的场景。尽管 Protobuf/Flatbuffer 等框架提供了多语言序列化能力,但仍然存在一些不足:
结合以上几点,Fury 实现了一套跨语言的对象图序列化协议:
自动跨语言序列化示例:
行存序列化
对于 高性能计算和大规模数据传输 场景,数据序列化和传输往往是整个系统的 性能瓶颈 。如果用户只需要读取部分数据,或者根据对象某个字段进行过滤,反序列化整个数据将带来额外开销。因此 Fury 也提供了一套二进制数据结构, 在二进制数据上直读直写,避开序列化 。
Apache arrow 是一个成熟的列存格式,支持二进制读写。但列存并不能满足所有场景需求,在线链路和流式计算场景的数据天然就是行存结构,同时列式计算引擎内部在涉及到数据变更和 Hash/Join/Aggregation 操作时,也会使用到行存结构。
而行存并没有一个统一标准实现,计算引擎如 Spark/Flink/Doris/Velox 等都定义了一套行存格式,这些格式不支持跨语言,且只能被自己引擎内部使用,无法用于其它框架。尽管 Flatbuffer 能够支持按需反序列化,但需要静态编译 Schema IDL 和管理 offset,无法满足复杂场景的动态性和易用性需求。
因此 Fury 在早期借鉴了 spark tungsten 和 apache arrow 格式,实现了一套可以随机访问的 二进制行存结构 ,目前实现了 Java/Python/C++ 版本,实现了 在二进制数据上面直读直写,避免掉了所有序列化开销 。
下图是 Fury Row Format 的二进制格式:
该格式密集存储,数据对齐,缓存友好,读写更快。由于避免了反序列化,能够减少 Java GC 压力。同时降低 Python 开销,同时由于 Python 的动态性,Fury 的数据结构实现了 _getattr__/getitem/slice/ 和其它特殊方法,保证了行为跟 python top="6839.0625">性能对比
这里给出部分 Java 序列化性能数据,其中标题包含 compatible 的图表是支持类型前后兼容下的性能数据,标题不包含 compatible 的图表是不支持类型前后兼容下的性能数据。为了公平起见,所有测试 Fury 关闭了零拷贝特性。
更多 benchmark 数据请参考 Fury Github 官方文档:src="https://static001.geekbang.org/wechat/images/9a/9ac77edab4d330b1dffee7b034360868.jpeg"/>
未来规划
加入我们
我们致力于将 Fury 打造为一个 开放中立、追求极致与创新的社区项目 ,后续的研发与讨论等工作都会在社区以开源透明的方式进行。欢迎任何形式的参与,包括但不限于提问、代码贡献、技术讨论等。非常期待收到大家的想法和反馈,一起参与到项目的建设中来,推动项目向前发展,打造最先进的序列化框架。
代码主仓库的 GitHub 地址为 :官方网站:欢迎各种 Issue、PR、Discussion。
也欢迎直接加入下面的官方交流群,和我们一起交流。
微信公众号:高性能序列化框架 Fury
钉钉交流群:钉钉群号 (36170003000)
作者简介
杨朝坤 ,蚂蚁集团技术专家,Fury 框架作者。2018 年加入蚂蚁集团,先后从事流计算框架、在线学习框架、科学计算框架和 Ray 等分布式计算框架开发,对批计算、流计算、Tensor 计算、高性能计算、AI 框架、张量编译等有深入的理解。
活动推荐
以「启航·AIGC 软件工程变革」为主题的 QCon 全球软件开发大会·北京站将于 9 月 3-5 日在北京•富力万丽酒店举办,此次大会策划了构建未来软件的编程语言、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、大前端融合提效、LLMOps、异构算力、微服务架构治理、业务安全技术、FinOps 等近 30 个精彩专题。
现在购票即可享受 8 折 优惠,立减。咨询购票可联系票务经理 18514549229(微信同手机号)。点击查看专题详情,期待与各位开发者现场交流。