Apache Fury (กำลังบ่มเพาะ) คือเฟรมเวิร์กซีเรียลไลเซชันหลายภาษาที่รวดเร็วเหลือเชื่อ ซึ่งขับเคลื่อนโดย JIT (การคอมไพล์แบบทันเวลา) และ Zero-Copy ซึ่งให้ประสิทธิภาพสูงสุด 170 เท่าและใช้งานง่ายที่สุด
https://fury.apache.org
สำคัญ
Apache Fury (การฟักตัว) เป็นความพยายามที่อยู่ระหว่างการบ่มเพาะที่ Apache Software Foundation (ASF) ซึ่งได้รับการสนับสนุนจาก Apache Incubator PMC
โปรดอ่านข้อจำกัดความรับผิดชอบและคำอธิบายทั้งหมดของ "การบ่มเพาะ"
นอกเหนือจากการทำให้เป็นอนุกรมข้ามภาษาแล้ว Fury ยังมีคุณสมบัติที่:
writeObject
/ readObject
/ writeReplace
/ readResolve
/ readObjectNoData
/ Externalizable
APIrecord
ก็รองรับเช่นกันFury ออกแบบและปรับใช้โปรโตคอลไบนารีหลายตัวสำหรับสถานการณ์ที่แตกต่างกัน:
สามารถเพิ่มโปรโตคอลใหม่ได้อย่างง่ายดายโดยอิงตามบัฟเฟอร์ การเข้ารหัส เมตา โค้ดเจน และความสามารถอื่นๆ ที่มีอยู่ของ Fury ทั้งหมดใช้ฐานรหัสเดียวกัน และการเพิ่มประสิทธิภาพสำหรับโปรโตคอลหนึ่งสามารถนำมาใช้ซ้ำโดยอีกโปรโตคอลหนึ่งได้
กรอบงานการออกหมายเลขซีเรียลที่แตกต่างกันเหมาะสำหรับสถานการณ์ที่แตกต่างกัน และผลลัพธ์การวัดประสิทธิภาพที่นี่มีไว้เพื่อการอ้างอิงเท่านั้น
หากคุณต้องการเปรียบเทียบประสิทธิภาพสำหรับสถานการณ์เฉพาะของคุณ ตรวจสอบให้แน่ใจว่าเฟรมเวิร์กการทำให้ซีเรียลไลซ์ทั้งหมดได้รับการกำหนดค่าอย่างเหมาะสมสำหรับสถานการณ์นั้น
เฟรมเวิร์กซีเรียลไลเซชันแบบไดนามิกรองรับความหลากหลายและการอ้างอิง แต่มักจะมาพร้อมกับต้นทุนที่สูงกว่าเมื่อเทียบกับเฟรมเวิร์กซีเรียลไลเซชันแบบคงที่ เว้นแต่ว่าจะใช้เทคนิค JIT เช่นเดียวกับที่ Fury ทำ เพื่อให้มั่นใจถึงสถิติการวัดประสิทธิภาพที่แม่นยำ ขอแนะนำ ให้วอร์ม ระบบก่อนที่จะรวบรวมข้อมูลเนื่องจากการสร้างโค้ดรันไทม์ของ Fury
ในแผนภูมิด้านล่าง ชื่อที่มี "เข้ากันได้" แสดงถึงโหมดที่เข้ากันได้กับสคีมา: เปิดใช้งานความเข้ากันได้ประเภทไปข้างหน้า/ย้อนกลับ ในขณะที่ชื่อที่ไม่มี "เข้ากันได้" แสดงถึงโหมดที่สอดคล้องกันของสคีมา: สคีมาคลาสจะต้องเหมือนกันระหว่างการทำให้เป็นอนุกรมและการดีซีเรียลไลซ์
โดยที่ Struct
เป็นคลาสที่มีฟิลด์พื้นฐาน 100 ช่อง MediaContent
เป็นคลาสจาก jvm-serializers และ Sample
เป็นคลาสจากเกณฑ์มาตรฐาน kryo
ดูเกณฑ์มาตรฐานสำหรับเกณฑ์มาตรฐานเพิ่มเติมเกี่ยวกับความเข้ากันได้ของประเภทไปข้างหน้า/ย้อนกลับ การสนับสนุนนอกฮีป การทำให้เป็นอนุกรมเป็นศูนย์
ภาพรวมตอนกลางคืน:
< 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 ));
}
}
หลาม
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 รองรับความเข้ากันได้ของคลาสสคีมาไปข้างหน้า/ข้างหลัง เพียร์การทำให้ซีเรียลไลซ์และเพียร์การดีซีเรียลไลซ์สามารถเพิ่ม/ลบฟิลด์ได้อย่างอิสระ
We plan to add the schema compatibility support of cross-language serialization after meta compression is finished.
เรายังคงปรับปรุงโปรโตคอลของเรา ดังนั้นจึงไม่มีการรับประกันความเข้ากันได้แบบไบนารีระหว่าง Fury รุ่นหลักในตอนนี้ อย่างไรก็ตาม รับประกันระหว่างเวอร์ชันรอง โปรด versioning
ข้อมูลของคุณตามเวอร์ชันหลักของ Fury หากคุณจะอัปเกรด Fury ในอนาคต โปรดดูวิธีอัปเกรด Fury สำหรับรายละเอียดเพิ่มเติม
รับประกันความเข้ากันได้ของไบนารีเมื่อ Fury 1.0 เปิดตัว
การทำให้เป็นอนุกรมแบบคงที่ค่อนข้างปลอดภัย แต่การทำให้ซีเรียลไลซ์แบบไดนามิก เช่น Fury java/python การทำให้ซีเรียลไลซ์แบบเนทีฟรองรับการดีซีเรียลไลซ์ประเภทที่ไม่ได้ลงทะเบียน ซึ่งให้ไดนามิกและความยืดหยุ่นมากกว่า แต่ยังนำมาซึ่งความเสี่ยงด้านความปลอดภัยด้วย
ตัวอย่างเช่น การดีซีเรียลไลเซชันอาจเรียกใช้ตัวสร้าง init
หรือวิธี equals
/ hashCode
หากเนื้อหาของวิธีการมีโค้ดที่เป็นอันตราย ระบบจะตกอยู่ในความเสี่ยง
Fury มีตัวเลือกการลงทะเบียนคลาสที่เปิดใช้งานตามค่าเริ่มต้นสำหรับโปรโตคอลดังกล่าว โดยอนุญาตเฉพาะประเภทที่ลงทะเบียนที่เชื่อถือได้หรือประเภทในตัวเท่านั้น อย่าปิดใช้งานการลงทะเบียนชั้นเรียน เว้นแต่คุณจะสามารถมั่นใจได้ว่าสภาพแวดล้อมของคุณปลอดภัย
หากปิดใช้งานตัวเลือกนี้ คุณจะต้องรับผิดชอบต่อความปลอดภัยในการซีเรียลไลซ์ คุณสามารถกำหนดค่า org.apache.fury.resolver.ClassChecker
โดย ClassResolver#setClassChecker
เพื่อควบคุมคลาสที่ได้รับอนุญาตให้ทำซีเรียลไลซ์
หากต้องการรายงานช่องโหว่ด้านความปลอดภัยที่พบใน Fury โปรดปฏิบัติตามกระบวนการรายงานช่องโหว่ ASF
โปรดอ่านคู่มือ BUILD เพื่อดูคำแนะนำเกี่ยวกับวิธีการสร้าง
โปรดอ่านคู่มือการมีส่วนร่วมเพื่อดูคำแนะนำเกี่ยวกับวิธีการมีส่วนร่วม
ได้รับอนุญาตภายใต้ Apache License เวอร์ชัน 2.0