Apache Fury (inkubasi) adalah kerangka serialisasi multi-bahasa yang sangat cepat yang didukung oleh JIT (kompilasi just-in-time) dan zero-copy , memberikan kinerja hingga 170x dan kemudahan penggunaan terbaik.
https://fury.apache.org
Penting
Apache Fury (inkubasi) merupakan upaya menjalani inkubasi di Apache Software Foundation (ASF) yang disponsori oleh Apache Incubator PMC.
Mohon untuk membaca DISCLAIMER dan penjelasan lengkap mengenai "inkubasi".
Selain serialisasi lintas bahasa, Fury juga tampil di:
writeObject
/ readObject
/ writeReplace
/ readResolve
/ readObjectNoData
/ Externalizable
API.record
Java 17+ juga didukung.Fury merancang dan mengimplementasikan beberapa protokol biner untuk berbagai skenario:
Protokol baru dapat dengan mudah ditambahkan berdasarkan buffer Fury yang ada, pengkodean, meta, codegen, dan kemampuan lainnya. Semuanya berbagi basis kode yang sama, dan pengoptimalan untuk satu protokol dapat digunakan kembali oleh protokol lain.
Kerangka kerja serialisasi yang berbeda cocok untuk skenario yang berbeda, dan hasil benchmark di sini hanya untuk referensi.
Jika Anda perlu melakukan tolok ukur untuk skenario spesifik Anda, pastikan semua kerangka serialisasi dikonfigurasi dengan tepat untuk skenario tersebut.
Kerangka kerja serialisasi dinamis mendukung polimorfisme dan referensi, tetapi seringkali biayanya lebih tinggi dibandingkan kerangka serialisasi statis, kecuali jika kerangka tersebut menggunakan teknik JIT seperti yang dilakukan Fury. Untuk memastikan statistik benchmark yang akurat, disarankan untuk melakukan pemanasan sistem sebelum mengumpulkan data karena pembuatan kode runtime Fury.
Dalam bagan di bawah ini, judul yang mengandung "kompatibel" mewakili mode kompatibel skema: kompatibilitas jenis maju/mundur diaktifkan; sedangkan judul tanpa "kompatibel" mewakili mode skema yang konsisten: skema kelas harus sama antara serialisasi dan deserialisasi.
Dimana Struct
adalah kelas dengan 100 bidang primitif, MediaContent
adalah kelas dari jvm-serializers, dan Sample
adalah kelas dari kryo benchmark.
Lihat tolok ukur untuk mengetahui tolok ukur lebih lanjut tentang kompatibilitas jenis maju/mundur, dukungan off-heap, serialisasi tanpa salinan.
Cuplikan malam:
< 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> -->
Versi rilis:
< 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> -->
Skala2:
libraryDependencies += " org.apache.fury " % " fury-scala_2.13 " % " 0.9.0 "
skala3:
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
Di sini kami memberikan gambaran singkat tentang cara menggunakan Fury, lihat panduan pengguna untuk detail lebih lanjut tentang java, lintas bahasa, dan format baris.
Jika Anda tidak memiliki persyaratan lintas bahasa, menggunakan mode ini akan menghasilkan kinerja yang lebih baik.
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 ));
}
}
}
Jawa
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 ));
}
}
ular piton
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 ))
Golang
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 ])
Serialisasi grafik objek Fury java mendukung kompatibilitas maju/mundur skema kelas. Rekan serialisasi dan rekan deserialisasi dapat menambah/menghapus bidang secara mandiri.
Kami berencana untuk menambahkan dukungan kompatibilitas skema serialisasi lintas bahasa setelah kompresi meta selesai.
Kami masih meningkatkan protokol kami, sehingga kompatibilitas biner tidak dijamin antara rilis besar Fury untuk saat ini. Namun, ini dijamin antara versi minor. Harap versioning
data Anda dengan versi utama Fury jika Anda akan meningkatkan Fury di masa mendatang, lihat cara meningkatkan kemarahan untuk detail lebih lanjut.
Kompatibilitas biner akan dijamin saat Fury 1.0 dirilis.
Serialisasi statis relatif aman. Namun serialisasi dinamis seperti serialisasi asli Java/python Fury mendukung deserialisasi tipe yang tidak terdaftar, yang memberikan lebih banyak dinamika dan fleksibilitas, tetapi juga menimbulkan risiko keamanan.
Misalnya, deserialisasi dapat memanggil konstruktor init
atau metode equals
/ hashCode
, jika badan metode berisi kode berbahaya, sistem akan berisiko.
Fury menyediakan opsi pendaftaran kelas yang diaktifkan secara default untuk protokol tersebut, hanya mengizinkan deserialisasi tipe terdaftar tepercaya atau tipe bawaan. Jangan nonaktifkan pendaftaran kelas kecuali Anda dapat memastikan lingkungan Anda aman .
Jika opsi ini dinonaktifkan, Anda bertanggung jawab atas keamanan serialisasi. Anda dapat mengonfigurasi org.apache.fury.resolver.ClassChecker
dengan ClassResolver#setClassChecker
untuk mengontrol kelas mana yang diizinkan untuk serialisasi.
Untuk melaporkan kerentanan keamanan yang ditemukan di Fury, silakan ikuti proses pelaporan kerentanan ASF.
Silakan baca panduan BUILD untuk petunjuk cara membangun.
Silakan baca panduan BERKONTRIBUSI untuk petunjuk tentang cara berkontribusi.
Berlisensi di bawah Lisensi Apache, Versi 2.0