Apache Fury (المحتضن) هو إطار عمل تسلسلي متعدد اللغات فائق السرعة مدعوم بواسطة JIT (التجميع في الوقت المناسب) والنسخة الصفرية ، مما يوفر أداءً يصل إلى 170x وسهولة استخدام مطلقة.
https://fury.Apache.org
مهم
Apache Fury (الاحتضان) هو جهد يخضع للاحتضان في مؤسسة Apache Software Foundation (ASF)، برعاية Apache Incubator PMC.
يرجى قراءة إخلاء المسؤولية والشرح الكامل لكلمة "الاحتضان".
بالإضافة إلى التسلسل عبر اللغات، يتميز Fury أيضًا بما يلي:
writeObject
/ readObject
/ writeReplace
/ readResolve
/ readObjectNoData
/ Externalizable
API.record
Java 17+ أيضًا.قام Fury بتصميم وتنفيذ بروتوكولات ثنائية متعددة لسيناريوهات مختلفة:
يمكن إضافة بروتوكولات جديدة بسهولة استنادًا إلى المخزن المؤقت الحالي لـ Fury، والتشفير، والفوقية، وcodegen والإمكانيات الأخرى. كل هؤلاء يشتركون في نفس قاعدة التعليمات البرمجية، ويمكن إعادة استخدام التحسين لبروتوكول واحد بواسطة بروتوكول آخر.
تعد أطر التسلسل المختلفة مناسبة لسيناريوهات مختلفة، والنتائج المعيارية هنا هي للإشارة فقط.
إذا كنت بحاجة إلى قياس أداء السيناريو المحدد الخاص بك، فتأكد من تكوين جميع أطر عمل التسلسل بشكل مناسب لهذا السيناريو.
تدعم أطر عمل التسلسل الديناميكي تعدد الأشكال والمراجع، ولكنها غالبًا ما تأتي بتكلفة أعلى مقارنة بأطر عمل التسلسل الثابتة، ما لم تستخدم تقنيات JIT مثل Fury. لضمان إحصائيات مرجعية دقيقة، يُنصح بتسخين النظام قبل جمع البيانات بسبب إنشاء كود وقت تشغيل Fury.
في هذه المخططات أدناه، تمثل العناوين التي تحتوي على "متوافق" وضعًا متوافقًا مع المخطط: اكتب التوافق للأمام/للخلف ممكّنًا؛ بينما تمثل العناوين التي لا تحتوي على "متوافق" الوضع المتسق للمخطط: يجب أن يكون مخطط الفئة هو نفسه بين التسلسل وإلغاء التسلسل.
حيث أن Struct
عبارة عن فئة تحتوي على 100 حقل بدائي، فإن MediaContent
عبارة عن فئة من تسلسلات jvm، و 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 التوافق مع مخطط الفئة إلى الأمام/الخلف. يمكن لنظير التسلسل ونظير إلغاء التسلسل إضافة/حذف الحقول بشكل مستقل.
نحن نخطط لإضافة دعم توافق المخطط للتسلسل عبر اللغات بعد الانتهاء من ضغط التعريف.
ما زلنا نعمل على تحسين بروتوكولاتنا، وبالتالي فإن التوافق الثنائي غير مضمون بين إصدارات 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 للحصول على تعليمات حول كيفية البناء.
يرجى قراءة دليل المساهمة للحصول على تعليمات حول كيفية المساهمة.
مرخص بموجب ترخيص أباتشي، الإصدار 2.0