Fury 是一个极快的多语言序列化框架,由 jit(即时编译) 和 零拷贝 提供支持,提供高达 170 倍的性能和终极易用性。
https://furyio.org
特征
- 多种语言 :Java/Python/C++/Golang/Javascript。
- 零拷贝:受 pickle5和堆外读/写启发的跨语言带外序列化。
- 高性能 :高度可扩展的 JIT 框架,可在运行时以异步多线程方式生成序列化器代码以加速序列化,通过以下方式提供 20-170 倍的加速:通过生成代码中的内联变量减少内存访问。通过生成代码中的内联调用减少虚拟方法调用。减少条件分支。减少哈希查找。
- 多种二进制协议 :对象图、行格式等。
除了跨语言序列化之外,Fury 还具有以下功能:
- 直接替换 JDK/Kryo/Hessian 等 Java 序列化框架,无需修改任何代码,但速度提高 100 倍。它可以极大地提高高性能RPC调用、数据传输和对象持久化的效率。
- JDK序列化 100%兼容 ,原生支持java自定义序列化 writeObject/readObject/writeReplace/readResolve/readObjectNoData。
- 支持 golang 的共享和循环引用对象序列化。
- 支持 golang 自动对象序列化。
协议
不同的场景有不同的序列化要求。Fury 为这些要求设计并实现了多个二进制协议:
- 跨语言对象图协议 :跨语言自动序列化任何对象,无需 IDL 定义、模式编译以及对象与协议之间的转换。支持共享引用和循环引用,无重复数据或递归错误。支持对象多态性。
- 原生 java/python 对象图协议 :基于语言的类型系统进行高度优化。
- 行格式协议 :一种缓存友好的二进制随机访问格式,支持跳过序列化和部分序列化,并且可以自动转换为列格式。
可以基于现有的缓冲区、编码、元、代码生成和其他功能轻松添加新协议。所有这些都共享相同的代码库,并且一种协议的优化可以由另一种协议重用。
基准测试
不同的序列化框架适合不同的场景,这里的基准测试结果仅供参考。
如果您需要针对特定场景进行基准测试,请确保所有序列化框架都针对该场景进行了适当配置。
动态序列化框架支持多态性和引用,但与静态序列化框架相比,它们通常具有更高的成本,除非它们像 Fury 那样使用 JIT 技术。由于 Fury 在运行时生成代码,因此建议在收集基准统计数据之前 预热 系统。
Java序列化
标题中包含“兼容”表示架构兼容模式:支持类型向前/向后兼容。
标题中不带“兼容”的表示模式一致模式:序列化和反序列化之间的类模式必须相同。
Struct是一个具有100 个原始字段的类,是来自jvm-serializers 的MediaContent类,是来自kryo benchmark的类。Sample








有关类型前向/后向兼容性、堆外支持、零拷贝序列化的更多基准测试,请参阅基准测试。
安装
爪哇
夜间快照:
<repositories>
<repository>
<id>sonatype</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependency>
<groupId>org.furyio</groupId>
<artifactId>fury-core</artifactId>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<!-- row/arrow format support -->
<!-- <dependency>
<groupId>org.furyio</groupId>
<artifactId>fury-format</artifactId>
<version>0.2.0-SNAPSHOT</version>
</dependency> -->
发布版本:
<dependency>
<groupId>org.furyio</groupId>
<artifactId>fury-core</artifactId>
<version>0.1.0</version>
</dependency>
<!-- row/arrow format support -->
<!-- <dependency>
<groupId>org.furyio</groupId>
<artifactId>fury-format</artifactId>
<version>0.1.0</version>
</dependency> -->
Python
# Release version will be provided in the future.
pip install pyfury --pre
JavaScript
npm install @furyjs/fury
Golang
即将推出。
快速开始
这里我们快速入门如何使用fury,有关java、跨语言和行格式的更多详细信息请参阅用户指南。
Fury java对象图序列化
如果没有跨语言的需求,使用这种模式会有更好的性能。
import io.fury.*;
import java.util.*;
public class Example {
public static void main(String[] args) {
SomeClass object = new SomeClass();
// Note that Fury instances should be reused between
// multiple serializations of different objects.
{
Fury fury = Fury.builder().withLanguage(Language.JAVA)
// Allow to deserialize objects unknown types, more flexible
// but may be insecure if the classes contains malicious code.
// .requireClassRegistration(false)
.build();
// Registering types can reduce class name serialization overhead, but not mandatory.
// If class registration enabled, all custom types must be registered.
fury.register(SomeClass.class);
byte[] bytes = fury.serialize(object);
System.out.println(fury.deserialize(bytes));
}
{
ThreadSafeFury fury = Fury.builder().withLanguage(Language.JAVA)
// Allow to deserialize objects unknown types, more flexible
// but may be insecure if the classes contains malicious code.
// .requireClassRegistration(false)
.buildThreadSafeFury();
byte[] bytes = fury.serialize(object);
System.out.println(fury.deserialize(bytes));
}
{
ThreadSafeFury fury = new ThreadLocalFury(classLoader -> {
Fury f = Fury.builder().withLanguage(Language.JAVA)
.withClassLoader(classLoader).build();
f.register(SomeClass.class);
return f;
});
byte[] bytes = fury.serialize(object);
System.out.println(fury.deserialize(bytes));
}
}
}
跨语言对象图序列化
Java
import io.fury.*;
import java.util.*;
public class ReferenceExample {
public static class SomeClass {
SomeClass f1;
Map<String, String> f2;
Map<String, String> f3;
}
public static Object createObject() {
SomeClass obj = new SomeClass();
obj.f1 = obj;
obj.f2 = ofHashMap("k1", "v1", "k2", "v2");
obj.f3 = obj.f2;
return obj;
}
// mvn exec:java -Dexec.mainClass="io.fury.examples.ReferenceExample"
public static void main(String[] args) {
Fury fury = Fury.builder().withLanguage(Language.XLANG)
.withRefTracking(true).build();
fury.register(SomeClass.class, "example.SomeClass");
byte[] bytes = fury.serialize(createObject());
// bytes can be data serialized by other languages.
System.out.println(fury.deserialize(bytes));
}
}
Python
from typing import Dict
import pyfury
class SomeClass:
f1: "SomeClass"
f2: Dict[str, str]
f3: Dict[str, str]
fury = pyfury.Fury(ref_tracking=True)
fury.register_class(SomeClass, "example.SomeClass")
obj = SomeClass()
obj.f2 = {"k1": "v1", "k2": "v2"}
obj.f1, obj.f3 = obj, obj.f2
data = fury.serialize(obj)
# bytes can be data serialized by other languages.
print(fury.deserialize(data))
Golang
package main
import furygo "github.com/alipay/fury/fury/go/fury"
import "fmt"
func main() {
type SomeClass struct {
F1 *SomeClass
F2 map[string]string
F3 map[string]string
}
fury := furygo.NewFury(true)
if err := fury.RegisterTagType("example.SomeClass", SomeClass{}); err != nil {
panic(err)
}
value := &SomeClass{F2: map[string]string{"k1": "v1", "k2": "v2"}}
value.F3 = value.F2
value.F1 = value
bytes, err := fury.Marshal(value)
if err != nil {
}
var newValue interface{}
// bytes can be data serialized by other languages.
if err := fury.Unmarshal(bytes, &newValue); err != nil {
panic(err)
}
fmt.Println(newValue)
}
行格式
Java
public class Bar {
String f1;
List<Long> f2;
}
public class Foo {
int f1;
List<Integer> f2;
Map<String, Integer> f3;
List<Bar> f4;
}
RowEncoder<Foo> encoder = Encoders.bean(Foo.class);
Foo foo = new Foo();
foo.f1 = 10;
foo.f2 = IntStream.range(0, 1000000).boxed().collect(Collectors.toList());
foo.f3 = IntStream.range(0, 1000000).boxed().collect(Collectors.toMap(i -> "k"+i, i->i));
List<Bar> bars = new ArrayList<>(1000000);
for (int i = 0; i < 1000000; i++) {
Bar bar = new Bar();
bar.f1 = "s"+i;
bar.f2 = LongStream.range(0, 10).boxed().collect(Collectors.toList());
bars.add(bar);
}
foo.f4 = bars;
// Can be zero-copy read by python
BinaryRow binaryRow = encoder.toRow(foo);
// can be data from python
Foo newFoo = encoder.fromRow(binaryRow);
// zero-copy read List<Integer> f2
BinaryArray binaryArray2 = binaryRow.getArray(1);
// zero-copy read List<Bar> f4
BinaryArray binaryArray4 = binaryRow.getArray(3);
// zero-copy read 11th element of `readList<Bar> f4`
BinaryRow barStruct = binaryArray4.getStruct(10);
// zero-copy read 6th of f2 of 11th element of `readList<Bar> f4`
barStruct.getArray(1).getLong(5);
RowEncoder<Bar> barEncoder = Encoders.bean(Bar.class);
// deserialize part of data.
Bar newBar = barEncoder.fromRow(barStruct);
Bar newBar2 = barEncoder.fromRow(binaryArray4.getStruct(20));
Python
@dataclass
class Bar:
f1: str
f2: List[pa.int64]
@dataclass
class Foo:
f1: pa.int32
f2: List[pa.int32]
f3: Dict[str, pa.int32]
f4: List[Bar]
encoder = pyfury.encoder(Foo)
foo = Foo(f1=10, f2=list(range(1000_000)),
f3={f"k{i}": i for i in range(1000_000)},
f4=[Bar(f1=f"s{i}", f2=list(range(10))) for i in range(1000_000)])
binary: bytes = encoder.to_row(foo).to_bytes()
foo_row = pyfury.RowData(encoder.schema, binary)
print(foo_row.f2[100000], foo_row.f4[100000].f1, foo_row.f4[200000].f2[5])
兼容性
架构兼容性
Fury java对象图序列化支持类模式向前/向后兼容性。序列化对等体和反序列化对等体可以独立添加/删除字段。
我们计划在元压缩完成后添加跨语言序列化的支持。
二进制兼容性
我们仍在改进我们的协议,目前无法确保 Fury 版本之间的二进制兼容性。shade如果您以后升级狂怒,请狂怒。
Fury 1.0 之前将确保二进制兼容性。
安全
静态序列化是安全的。但动态序列化如fury java/python原生序列化支持反序列化未注册类型,提供了更多的动态性和灵活性,但也引入了安全风险。
例如,反序列化时可能会调用init构造函数或equals/hashCode方法,如果方法体中包含恶意代码,系统就会面临风险。
Fury 提供了一个类注册选项,并默认为此类协议启用,该选项仅允许反序列化受信任的注册类型或内置类型。 不要禁用类注册,除非您可以确保您的环境确实安全 。
路线图
- 元压缩、自动元共享和跨语言模式兼容性。
- 用于 C++/golang/rust 的 AOT 框架静态生成代码。
- C++/Rust 对象图序列化支持
- Golang/Rust/NodeJS 行格式支持
- ProtoBuffer 兼容性支持
- 特征和知识图序列化协议
- 不断改进我们的任何新协议的序列化基础设施
项目地址:https://github.com/alipay/fury