Apache Fury (инкубация) — это невероятно быстрая многоязычная среда сериализации, основанная на JIT (компиляция «точно в срок») и нулевом копировании , обеспечивающая повышение производительности до 170 раз и максимальную простоту использования.
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, кодирования, мета-кодирования и других возможностей. Все они используют одну и ту же кодовую базу, и оптимизация для одного протокола может быть повторно использована другим протоколом.
Различные платформы сериализации подходят для разных сценариев, а результаты тестов приведены здесь только для справки.
Если вам нужно провести тестирование для вашего конкретного сценария, убедитесь, что все платформы сериализации правильно настроены для этого сценария.
Платформы динамической сериализации поддерживают полиморфизм и ссылки, но они часто обходятся дороже по сравнению со структурами статической сериализации, если только они не используют методы JIT, как это делает Фьюри. Чтобы обеспечить точную статистику тестов, рекомендуется прогреть систему перед сбором данных из-за генерации кода во время выполнения 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 ])
Сериализация графа объектов Java Fury поддерживает прямую/обратную совместимость схемы классов. Одноранговый узел сериализации и одноранговый узел десериализации могут добавлять/удалять поля независимо друг от друга.
Мы планируем добавить поддержку совместимости схем межъязыковой сериализации после завершения метасжатия.
Мы все еще совершенствуем наши протоколы, поэтому двоичная совместимость между основными выпусками Fury на данный момент не гарантирована. Однако это гарантируется между минорными версиями. Пожалуйста, versioning
ваших данных по основной версии Fury, если вы обновите Fury в будущем. Дополнительные сведения см. в разделе «Как обновить Fury».
Бинарная совместимость будет гарантирована после выхода Fury 1.0.
Статическая сериализация относительно безопасна. Но динамическая сериализация, такая как встроенная сериализация Java/Python Fury, поддерживает десериализацию незарегистрированных типов, что обеспечивает большую динамику и гибкость, но также создает риски для безопасности.
Например, десериализация может вызвать конструктор init
или метод equals
/ hashCode
. Если тело метода содержит вредоносный код, система окажется под угрозой.
Fury предоставляет опцию регистрации классов, которая включена по умолчанию для таких протоколов, позволяя десериализацию только доверенных зарегистрированных типов или встроенных типов. Не отключайте регистрацию классов, если вы не можете гарантировать безопасность своей среды .
Если эта опция отключена, вы несете ответственность за безопасность сериализации. Вы можете настроить org.apache.fury.resolver.ClassChecker
с помощью ClassResolver#setClassChecker
, чтобы контролировать, какие классы разрешены для сериализации.
Чтобы сообщить об уязвимостях безопасности, обнаруженных в Fury, следуйте процедуре сообщения об уязвимостях ASF.
Пожалуйста, прочитайте руководство по сборке, чтобы получить инструкции по сборке.
Пожалуйста, прочтите руководство «Внесение вклада», чтобы получить инструкции о том, как внести свой вклад.
Лицензия Apache, версия 2.0.