Rust 终于来了!Apache Fory 0.13.0 带来高性能 Rust 序列化 + 无缝替代 Python Pickle

73 阅读5分钟

🚀 Apache Fory 0.13.0 重磅发布! 这一版本带来两大震撼更新:

  • Rust 首个正式版本完整高性能序列化栈、Dynamic Trait Object、多集合支持与 Schema 演进能力,让静态语言拥有动态序列化的灵活性。 在性能测试中,比 JSON/Protobuf 快最多 10 倍,压缩率媲美 Protobuf。
  • Python Pickle 全面替代方案 :无缝兼容 pickle/cloudpickle API,同时做到 更快、更小📦、更安全,支持本地函数/类、lambda、零拷贝 NumPy/Pandas 等高级场景。

无论是跨语言服务还是单语言优化,Fory 都能让数据传输更高效、更可靠。 立即升级,体验 Rust 与 Python 序列化的全新时代!

亮点 🚀

  • 🧠 Rust 的 Dynamic Trait Object 序列化
  • 🔁 Rust 的 Shared/Circular ownership 序列化
  • 🔮 Rust 的 Schema Forward/Backward compatibilify
  • 🐍 Python pickle 的 Drop-in Replacement:支持本地函数/类/__reduce__/__getstate__ 序列化
  • 🧾 支持 Python dataclass Schema 向前向后兼容性
  • ☕️ Java xlang 模式支持 jit codegen,加速跨语言序列化性能
  • ⚙️ 使用 SIMD 的 primitive array compression,大幅压缩数组的序列化体积
  • 📦 Row Format 新增 Compact Row Codec,编码压缩率提升50%
  • 🐹 支持Go Struct Schema 向前向后兼容性
  • 🚀 Golang struct 序列化 的 ahead-of-time codegen,加速 Golang 序列化性能

Rust:首个发布亮点 🦀

这是 Apache Fory 首个 Rust 正式版本,带来完整、高性能的序列化栈。如果你正在构建 Rust 服务或库,现在可以在强类型、性能和 schema 演进方面原生使用 Fory。

  • 通过 #[derive(ForyObject)] 实现 derive-based object graph serialization
  • 支持 trait objects 的多态:Box<dyn Trait>Rc<dyn Trait>Arc<dyn Trait>,以及 dyn Any
  • Rc/ArcRcWeak/ArcWeak 的共享与循环引用追踪
  • 提供向前/向后兼容的 schema 演进(Compatible 模式)
  • 借助 #[derive(ForyRow)] 和按需字段访问,实现零拷贝 Row format
  • 线程安全并支持多线程序列化(context pool)
  • 广泛的集合支持(例如 VecDequeLinkedListBTreeMapBTreeSetBinaryHeap

快速上手(最小示例):

use fory::{Fory, Error};
use fory::ForyObject;

#[derive(ForyObject, Debug, PartialEq)]
struct User {
    name: String,
    age: i32,
    email: String,
}

fn main() -> Result<(), Error> {
    let mut fory = Fory::default();
    fory.register::<User>(1)?;

    let user = User { name: "Alice".into(), age: 30, email: "alice@example.com".into() };
    let bytes = fory.serialize(&user)?;
    let decoded: User = fory.deserialize(&bytes)?;
    assert_eq!(user, decoded);
    Ok(())
}

Rust 基准测试 📊

下表展示了在多个数据集和规模上,Fory 与 JSON、Protobuf 的序列化吞吐量(TPS,越高越好)对比,结果表明 Fory 性能是 Protobuf/JSON的10倍以上,序列化结果大小跟 Protobuf Rust 持平:

注意:结果会受到硬件、数据集和实现版本的影响。参阅 Rust 指南了解如何自行运行基准测试:github.com/apache/fory…

Python:pickle 的替代方案 🐍

pyfory 现在是一款高性能的 pickle/cloudpickle Drop-in Replacement,同时保持一致的简洁 API,并增强安全性与性能。

  • 在 Python-native 模式(xlang=False)下序列化任意 Python 对象:全局/本地函数、lambdas、全局/本地类、实例/类/静态方法
  • 遵循 Python 钩子:__getstate____setstate____reduce____reduce_ex__
  • 通过 ref=True 提供共享/循环对象图的引用追踪
  • 借助协议 5 的 out-of-band buffers 和 pickle.PickleBuffer 实现零拷贝(如 NumPy、Pandas 等)
  • 安全性:strict=True 支持基于注册的安全策略,DeserializationPolicy 提供精细化管控
  • 线程:ThreadSafeFory 支持多线程安全使用
  • 熟悉的 API:dumps/loadsserialize/deserialize 的别名

快速上手:

import pyfory

# Drop-in replacement for pickle/cloudpickle
fory = pyfory.Fory(xlang=False, ref=True, strict=False)

def make_multiplier(k):
    def mul(x):
        return k * x
    return mul

binary = fory.dumps(make_multiplier(10))
assert fory.loads(binary)(3) == 30

延伸阅读:Python Guide – fory.apache.org/docs/latest…

📦 快速开始

默认情况下会使用各语言的原生模式以获得最佳性能;只有在需要跨语言互通时,才将序列化模式切换为 xlang=true(或等效选项)。

Rust

use fory::{Error, Fory};
use fory::ForyObject;

#[derive(ForyObject, Debug, PartialEq)]
struct Person {
    name: String,
    age: i32,
}

fn main() -> Result<(), Error> {
    let mut fory = Fory::default();
    fory.register::<Person>(1)?;
    let bytes = fory.serialize(&Person { name: "Alice".into(), age: 30 })?;
    let decoded: Person = fory.deserialize(&bytes)?;
    assert_eq!(decoded.age, 30);
    Ok(())
}

Python

python -m pip install --upgrade pip
pip install pyfory==0.13.0

from dataclasses import dataclass
import pyfory

@dataclass
class Person:
    name: str
    age: pyfory.int32

fory = pyfory.Fory()
fory.register_type(Person)
payload = fory.serialize(Person(name="Alice", age=30))
decoded = fory.deserialize(payload)
print(decoded.name, decoded.age)

Java

import org.apache.fory.*;
import org.apache.fory.config.*;

public class QuickStart {
  public static class Person {
    String name;
    int age;

    Person(String name, int age) {
      this.name = name;
      this.age = age;
    }
  }

  public static void main(String[] args) {
    Fory fory = Fory.builder()
      .withLanguage(Language.JAVA)
      .requireClassRegistration(true)
      .build();
    fory.register(Person.class);
    byte[] bytes = fory.serialize(new Person("Alice", 30));
    Person result = (Person) fory.deserialize(bytes);
    System.out.println(result.name + " " + result.age);
  }
}

Scala

import org.apache.fory.Fory
import org.apache.fory.config.Language
import org.apache.fory.serializer.scala.ScalaSerializers

case class Person(name: String, age: Int)

object Example {
  def main(args: Array[String]): Unit = {
    val fory = Fory.builder()
      .withLanguage(Language.JAVA)
      .requireClassRegistration(true)
      .build()
    ScalaSerializers.registerSerializers(fory)
    fory.register(classOf[Person])
    val bytes = fory.serialize(Person("Alice", 30))
    val result = fory.deserialize(bytes).asInstanceOf[Person]
    println(s"${result.name} ${result.age}")
  }
}

Kotlin

import org.apache.fory.Fory
import org.apache.fory.config.Language
import org.apache.fory.serializer.kotlin.KotlinSerializers

data class Person(val name: String, val age: Int)

fun main() {
    val fory = Fory.builder()
        .withLanguage(Language.JAVA)
        .requireClassRegistration(true)
        .build()
    KotlinSerializers.registerSerializers(fory)
    fory.register(Person::class.java)
    val bytes = fory.serialize(Person("Alice", 30))
    val result = fory.deserialize(bytes) as Person
    println("${result.name} ${result.age}")
}

Golang

package main

import (
    "fmt"

    forygo "github.com/apache/fory/go/fory"
)

type Person struct {
    Name string
    Age  int32
}

func main() {
    fory := forygo.NewFory(true)
    fory.Register(Person{}, 1)
    payload, _ := fory.Marshal(Person{Name: "Alice", Age: 30})
    var decoded Person
    fory.Unmarshal(payload, &decoded)
    fmt.Println(decoded.Name, decoded.Age)
}

JavaScript

import Fory, { Type } from "@apache-fory/fory";
import hps from "@apache-fory/hps";

const description = Type.object("example.Person", {
  name: Type.string(),
  age: Type.int32(),
});

const fory = new Fory({ hps });
const { serialize, deserialize } = fory.registerSerializer(description);
const payload = serialize({ name: "Alice", age: 30 });
const decoded = deserialize(payload);
console.log(decoded.name, decoded.age);

功能特性 ✨