Apache Fury(正在孵化)是一種速度極快的多語言序列化框架,由JIT (即時編譯)和零複製提供支持,可提供高達 170 倍的效能和終極易用性。
https://fury.apache.org
重要的
Apache Fury(孵化中)是在 Apache 軟體基金會 (ASF) 中進行孵化的一項成果,由 Apache 孵化器 PMC 贊助。
請閱讀免責聲明和“孵化”的完整解釋。
除了跨語言序列化之外,Fury 還具有以下功能:
writeObject
/ readObject
/ writeReplace
/ readResolve
/ readObjectNoData
/ Externalizable
API。record
。Fury針對不同場景設計並實現了多種二進位協定:
基於Fury現有的緩衝區、編碼、元、程式碼產生等功能,可以輕鬆新增協定。所有這些都共享相同的程式碼庫,並且一種協定的最佳化可以由另一種協定重複使用。
不同的序列化框架適合不同的場景,這裡的基準測試結果僅供參考。
如果您需要針對特定場景進行基準測試,請確保所有序列化框架都針對該場景進行了適當配置。
動態序列化框架支援多態性和引用,但與靜態序列化框架相比,它們通常具有更高的成本,除非它們像 Fury 那樣使用 JIT 技術。為了確保準確的基準統計數據,建議在由於 Fury 的運行時程式碼產生而收集數據之前預熱系統。
在下面的這些圖表中,包含「相容」的標題代表模式相容模式:類型向前/向後相容性已啟用;而沒有「相容」的標題表示模式一致模式:序列化和反序列化之間的類別模式必須相同。
其中Struct
是一個具有 100 個原始欄位的類, MediaContent
是來自 jvm-serializers 的類,而Sample
是來自 kryo benchmark 的類別。
有關類型前向/後向相容性、堆外支援、零拷貝序列化的更多基準測試,請參閱基準測試。
夜間快照:
< repositories >
< repository >
< id >apache</ id >
< url >https://repository.apache.org/snapshots/</ url >
< releases >
< enabled >false</ enabled >
</ releases >
< snapshots >
< enabled >true</ enabled >
</ snapshots >
</ repository >
</ repositories >
< dependency >
< groupId >org.apache.fury</ groupId >
< artifactId >fury-core</ artifactId >
< version >0.10.0-SNAPSHOT</ version >
</ dependency >
<!-- row/arrow format support -->
<!-- <dependency>
<groupId>org.apache.fury</groupId>
<artifactId>fury-format</artifactId>
<version>0.10.0-SNAPSHOT</version>
</dependency> -->
發布版本:
< dependency >
< groupId >org.apache.fury</ groupId >
< artifactId >fury-core</ artifactId >
< version >0.9.0</ version >
</ dependency >
<!-- row/arrow format support -->
<!-- <dependency>
<groupId>org.apache.fury</groupId>
<artifactId>fury-format</artifactId>
<version>0.9.0</version>
</dependency> -->
斯卡拉2:
libraryDependencies += " org.apache.fury " % " fury-scala_2.13 " % " 0.9.0 "
斯卡拉3:
libraryDependencies += " org.apache.fury " % " fury-scala_3 " % " 0.9.0 "
< dependency >
< groupId >org.apache.fury</ groupId >
< artifactId >fury-kotlin</ artifactId >
< version >0.9.0</ version >
</ dependency >
pip install pyfury
npm install @furyjs/fury
go get github.com/apache/fury/go/fury
這裡我們快速入門如何使用 Fury,有關 java、跨語言和行格式的更多詳細資訊請參閱使用者指南。
如果你沒有跨語言的需求,使用這種模式會帶來更好的效能。
import org . apache . fury .*;
import org . apache . fury . config .*;
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 )
. requireClassRegistration ( true )
. 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 )
. requireClassRegistration ( true )
. buildThreadSafeFury ();
// 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 = 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 ));
}
}
}
爪哇
import org . apache . fury .*;
import org . apache . fury . config .*;
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="org.apache.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 , type_tag = "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 ))
戈蘭
package main
import furygo "github.com/apache/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 )
}
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 ). getInt64 ( 5 );
RowEncoder < Bar > barEncoder = Encoders . bean ( Bar . class );
// deserialize part of data.
Bar newBar = barEncoder . fromRow ( barStruct );
Bar newBar2 = barEncoder . fromRow ( binaryArray4 . getStruct ( 20 ));
@ 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 主要版本之間的二進位相容性。但是,小版本之間是有保證的。如果您將來要升級 Fury,請按 Fury 主要版本對您的資料versioning
,請參閱如何升級 Fury 以了解更多詳細資訊。
Fury 1.0 發佈時將保證二進位相容性。
靜態序列化相對安全。但動態序列化如Fury java/python原生序列化支援反序列化未註冊類型,提供了更多的動態性和靈活性,但也引入了安全風險。
例如,反序列化可能會呼叫init
建構函式或equals
/ hashCode
方法,如果方法體中包含惡意程式碼,系統就會面臨風險。
Fury 提供了一個類別註冊選項,預設為此類協定啟用,僅允許反序列化受信任的註冊類型或內建類型。不要停用類別註冊,除非您可以確保您的環境是安全的。
如果停用此選項,您將負責序列化安全性。您可以透過ClassResolver#setClassChecker
設定org.apache.fury.resolver.ClassChecker
來控制哪些類別允許序列化。
若要回報 Fury 中發現的安全漏洞,請遵循 ASF 漏洞報告流程。
請閱讀建置指南以取得有關如何建置的說明。
請閱讀貢獻指南以獲取有關如何貢獻的說明。
根據 Apache 授權 2.0 版獲得許可