- Apache Fory Rustは、超高速なシリアライズ性能と自動参照管理を提供するクロスランゲージ・シリアライズフレームワーク
- Rustのゼロコピー技術と型安全性を基盤に、循環参照・トレイトオブジェクト・スキーマ進化を自動処理
- IDLファイルやコード生成なしで、Rust、Python、Java、Goなど多様な言語間のデータ交換をサポート
- ベンチマーク結果では、JSON・Protobuf比で10〜20倍以上高速な処理速度を記録
- マイクロサービス・データパイプライン・リアルタイムシステムなど、高性能環境での活用価値が高い
シリアライズのジレンマとApache Fory Rustの登場
- 既存のシリアライズ方式には、速度・柔軟性・言語互換性のいずれかを諦めなければならないという限界があった
- 手作業のバイナリフォーマットは高速だが、スキーマ変更に弱い
- JSON/Protobufは柔軟だが、10倍以上の性能オーバーヘッドがある
- 既存ソリューションは言語固有機能のサポートが不足
- Apache Fory Rustは、性能と柔軟性を同時に確保し、IDLや手動のスキーマ管理が不要
主な特徴
-
1. 真のクロスランゲージ対応
- 同一のバイナリプロトコルをJava、Python、C++、Goなどで共有
- RustでシリアライズしたデータをPythonでそのままデシリアライズ可能
- スキーマファイル・コード生成・バージョン不一致の問題がなく、多言語マイクロサービス間のデータ交換を簡素化
-
2. 自動的な循環・共有参照処理
- ほとんどのフレームワークが失敗する循環参照構造を自動追跡して保持
- 同一オブジェクトを複数回参照しても一度だけシリアライズし、参照同一性を維持
- グラフデータベース・ORM・複雑なドメインモデルに適している
-
3. トレイトオブジェクトのシリアライズ
- Rustの
Boxなど、トレイトオブジェクトのシリアライズをサポート
register_trait_type!マクロで多相型を登録可能
Box, Rc, Arc, dyn Anyなど多様な形式をサポート
- プラグインシステム・異種コレクション・拡張可能なアーキテクチャを実装可能
-
4. スキーマ進化(互換モード)
- Compatibleモードにより、サービスバージョン間のスキーマ変更を許容
- フィールドの追加・削除・順序変更・オプション型への変換が可能
- 型変更は不可
- 無停止デプロイと独立したマイクロサービスの進化に有用
技術的基盤
-
プロトコル設計
- 構造:
| fory header | reference meta | type meta | value data |
- 可変長整数・圧縮メタデータ・参照追跡・リトルエンディアンレイアウトを適用
- 共有オブジェクトの重複排除と型メタデータ圧縮により性能を向上
-
コンパイル時コード生成
- リフレクションではなくマクロベースのコード生成によりランタイムオーバーヘッドを排除
#[derive(ForyObject)]マクロがシリアライズ・デシリアライズ関数を自動生成
- 型安全性を確保し、バイナリサイズを最小化、IDEの自動補完にも対応
-
アーキテクチャ構成
fory/: 高水準API
fory-core/: シリアライズエンジン(バッファI/O、型登録、メタ圧縮など)
fory-derive/: 手続きマクロ定義
- モジュール化された構造により保守性と拡張性を確保
ベンチマーク結果
- JSONおよびProtobuf比で10〜20倍以上高速な処理速度
- 例:
simple_struct(small) → Fory 35,729,598 TPS / JSON 10,167,045 / Protobuf 8,633,342
person(medium) → Fory 3,839,656 TPS / JSON 337,610 / Protobuf 369,031
- すべてのテストケースでForyが最高性能を記録
活用シナリオ
-
適したユースケース
- 多言語マイクロサービス: スキーマファイルなしでデータ交換
- 高性能データパイプライン: 毎秒数百万件のレコード処理
- 複雑なドメインモデル: 循環参照・多相構造をサポート
- リアルタイムシステム: 1ms未満の遅延、ゼロコピー・デシリアライズ
-
代替案の検討
- 人が読みやすいフォーマットが必要な場合 → JSON/YAML
- 長期保存フォーマットが必要な場合 → Parquet
- 単純なデータ構造 → serde + bincode
はじめ方
-
インストール
-
基本的なシリアライズ例
#[derive(ForyObject)]で構造体を登録した後、serialize() / deserialize()を使用
- 型IDの登録によりデータの一貫性を維持
-
クロスランゲージ・シリアライズ
compatible(true).xlang(true)設定で多言語互換モードを有効化
- IDまたは名前ベースの登録(
register_by_namespace, register_by_name)をサポート
対応型
- 基本型: bool, 整数, 浮動小数点, String
- コレクション: Vec, HashMap, BTreeMap, HashSet, Option
- スマートポインタ: Box, Rc, Arc, RcWeak, ArcWeak, RefCell, Mutex
- 日付/時刻: chrono型
- ユーザー定義オブジェクト: ForyObject, ForyRow
- トレイトオブジェクト: Box/Rc/Arc, Rc/Arc
ロードマップ
-
v0.13で提供
- 静的コード生成、ゼロコピーRowフォーマット、循環参照追跡、トレイトオブジェクトのシリアライズ、スキーマ互換モード
-
予定機能
- クロスランゲージ参照シリアライズ、部分的なRow更新
本番運用時の考慮事項
- スレッド安全性: 登録完了後は
Arcで共有可能(Send + Sync)
- エラー処理:
Resultベースで、型不一致・バッファ不足などのエラーを明示的に区別
ドキュメントとコミュニティ
結論
- Apache Fory Rustは、性能・柔軟性・言語互換性のトレードオフを解消した次世代シリアライズフレームワーク
- マクロベースの自動化、トレイトオブジェクト対応、循環参照処理により開発効率を最大化
- マイクロサービス・データパイプライン・リアルタイムシステムなどで即座に活用可能
2件のコメント
この性能は本当にあり得るのか?
Hacker News の意見
新しいフォーマットを作るより、W3C EXI(Binary XML) のような既存技術のツーリング改善に注力してほしい
ただ速いだけでは不十分で、Aeron/SBE のようにエコシステムがないフォーマットは普及が難しい。XML はすでにそのエコシステムを持っている
また、共有参照や循環参照 のような複雑なオブジェクトグラフを自然に表現できない
Fory フォーマットはこうした問題を解決しつつ、言語間互換性とスキーマ進化をサポートするよう最初から設計されている
つまり、まずエンコーディングを設計し、そこから逆向きに言語やクライアントへ拡張していく方式が望ましい
ベンチマークが公正なのか疑問に感じる
コードリンクを見ると、Fory 構造体でない場合、シリアライズ過程に to/from 変換 が含まれている
この変換過程で文字列のコピーや配列の再割り当てが発生する
実際のシステムでは tonic が 8KB バッファを提供するため、単純な
Vec::default()より効率的なはずだXeon Gold 6136 CPU では 10 倍改善のように見えるが、to/from 変換と Vec のコピーを除去し、8KB バッファを事前確保すると、実際には 3 倍程度になる
ベンチマークは Fory 関連コードがまったくない tower service/codec スタイル で書き直すべきだ
Fory はテスト中に writer pool を使っている
関連コード 参照
長期的に言語間互換性を維持するには、IDL ベースの明文化された契約 が必要だと思う
言語からシリアライゼーションへ出発するアプローチは、初期は便利でも、時間が経つと言語ランタイムの変化に脆弱になる
単一言語のプロジェクトは IDL なしでもシンプルに保てるが、3 言語以上になると IDL が 単一の信頼できる情報源 の役割を果たす
Apache Fory は将来的にオプションの IDL サポートを追加する予定で、チームの状況に応じて言語優先またはスキーマ優先の方式を選べるようにする計画だ
スキーマなしで言語間の 共有型 をどう維持しているのか気になる
型付き言語ではクラス定義からスキーマを推論し、型なし言語ではコードに直接アノテーションを付ける方式だ
Python の例は こちら で確認できる
関連ブログ記事 参照
CapnProto や Flatbuffers のような ゼロシリアライズフォーマット ではなく、なぜ Fory を使うべきなのか気になる
圧縮が必要なら zstd を使えばよい
それでも Fory の 広範な言語サポート と使いやすさは印象的だ
Python では今でも dill を好んでいる — コードオブジェクトまでシリアライズできるためだ
dill リンク
ベンチマークコード 参照
サンプルリンク
pyfory は cloudpickle 比で 3 倍高い圧縮率を示し、セキュリティ監査機能 によって悪意あるデシリアライズ攻撃を防ぐ
ベンチマークリンクは 404 だったが、正しいリンク を見つけた
名前を "Fury" から "Fory" に変えたのは惜しい
Fury は高速シリアライゼーションフレームワークにぴったりの名前だった
ほとんどの バイナリプロトコル はデータサイズの削減を目指している
Protobuf は整数圧縮(varint, zigzag)を使っている
単純な TPS だけを比較すると、C 構造体をそのまま送る "do nothing" 方式が常に勝ってしまう
各種データセットでの比較表が示されている
Fory の 4096 型制限 で十分なのか気になる
関連コード 参照
実際に 4096 個を超えるプロトコルメッセージを定義した例はほとんど見たことがない
Rust ベンチマークリンク が 404 エラーを返す
ドキュメントルート ではベンチマークディレクトリを見つけられなかった