[HN Gopher] Fury - Fast multi-language serialization framework p...
___________________________________________________________________
Fury - Fast multi-language serialization framework powered by JIT
and Zero-copy
Author : chaokunyang
Score : 130 points
Date : 2023-10-08 06:42 UTC (16 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| egamirorrim wrote:
| OOI, in a 'modern' app, what would you be using this kind of
| serialisation and deserialisation for? Some kind of complex RPC?
| [deleted]
| chaokunyang wrote:
| There are 3 kinds of scenarios are serialization bounded: 1.
| RPC for large microservices application, which are
| latency&throughput sensitive. The domain model can be huge,
| serialization will be the bottleneck. Some domain object graph
| may contains thousands of objects, serializing using jdk will
| take seconds, and the serialization result may be 50~100kb.
| Take Order as an example, imagine you need to process an order
| which has 500 items.
|
| 2. Data transfer for bigdata distributed systems: bigdata
| systems will handle much data, the data needs be transfered
| between workers. The serialization can be the bottleneck too.
| Spark RDD,Flink DataStream all have this bottleneck. The use
| bianry format such as arrow/tungsten format to reduce
| serialization overhead. But it's limited, sql oritiened, and
| can't express complex logic such as graph/event/domain.
|
| 3. Task scheduling: Image you have a mpp distributed systems,
| you need to schedule thounds of tasks in a process every sub-
| seconds. Serialization will be the bottleneck too.
| specialist wrote:
| Yes and: Kyro was motivated by building multi player games.
| chaokunyang wrote:
| Yes, Game is another scenario, it's very latency sensitive.
| Fury is very suitable too. Actually the java implememtation
| has been featured by some game developers. And there has
| always been a demand within the community for FURY to
| support C#: https://github.com/alipay/fury/issues/686 . I
| don't have experience for c#, so it's not supported. Hope
| c# can be supported with the help of the community
| neonsunset wrote:
| Given it's a binary serialization framework, it should
| not be _too_ difficult, because the domain is well-
| explored and numerous libraries exist in C# which address
| same goals that Fury does.
|
| More popular/newer examples are
| https://github.com/Cysharp/MemoryPack (which is similar
| to Fury with its own spec, C#-code first schema),
| https://github.com/MessagePack-CSharp/MessagePack-CSharp
| or even gRPC / Protobuf tooling
| https://github.com/grpc/grpc-dotnet
| chaokunyang wrote:
| Glad to see those great libraries. Can't wait to make
| fury support c#. One of the biggest difference for fury
| is that if support circular/shared reference and
| polymorphism. It's different from many other libraries.
| fakecrusade wrote:
| Interesting, I work in the same company but have never heard of
| it
| chaokunyang wrote:
| haha, maybe it's time to use it now. It's used wisely in
| distributed systems at our company. I posted several blogs in
| our internal ata bbs, you can search it
| chaokunyang wrote:
| Fury is also the fastest jvm serialization framework in the
| https://github.com/eishay/jvm-serializers/wiki
| marginalia_nu wrote:
| Weird they aren't emphasizing competitiveness with Protobuf and
| Avro, which is what I'd look at long before java serialization
| if I wanted fast object serialization.
| chaokunyang wrote:
| Protobuf/Avro doesn't support polymorphism and circular
| references, maybe that's one of thge reason? But even
| compared with protobuf, fury is 3.2x faster. When comparing
| with avro, fury is 5.3x faster
| RantyDave wrote:
| Great that it's fast - but I'm not sure it would make all that
| much difference in Python code.
| usrusr wrote:
| Just imagine the project landscape you'd need to be in to
| consider starting this worthwhile, given all uncertainty of
| success and so on. Or a very large middle finger to YAGNI, but I
| doubt it's that.
| chaokunyang wrote:
| But I want to say that Fury will be continuously maintained. I
| created it 4 years ago, open sourced it in 2023.07. I've
| maintained it with little credits for 4 years. Now with it
| open-sourced, it will just make me put more efforts on it.
|
| But on the other hand, the success of fury does not depend on
| whether I put in enough effort but on whether I can build a
| thriving community to involve more people to join us. I must
| admit that I am still learning in this area and have a long way
| to go.
| chaokunyang wrote:
| Good point! The success of a project is not only determined by
| what it can do, but more determined by what it chooses not to
| do. Only with clear and simple goals can we focus on what truly
| matters, while also attracting more developers to join our
| community.
| npstr wrote:
| The comparison to JDK serialization is surprising me. Noone
| should be using it for anything serious in production. Even the
| Chief Architect of the Java platform has called it a "horrible
| mistake". https://www.infoworld.com/article/3275924/oracle-plans-
| to-du...
| pron wrote:
| Just to be clear, though, the mistake that Mark Reinhold refers
| to isn't the particular _implementation_ of the JDK 's core
| serialization, but the _design_ that allows arbitrary objects
| to be deserialized while bypassing their constructors (and so
| their established invariants). Unfortunately, many other
| serialization libraries -- faster or slower -- are repeating
| the same mistake. I.e., any serialization library that can
| serialize any class that implements Serializable suffers from
| _all_ the same flaws of core serialization.
|
| Correct serialization can only be done for classes that are
| designed for it by having a well-known construction protocol,
| which are currently basic collections, enums, Strings, records,
| and classes that register specific serialization code.
| chaokunyang wrote:
| I see, totally agreed! If any objects can be serialized, the
| deserialization will introduce security issue too. For
| example, `constructor/equals/hashCode` may contains malicious
| code, which introduce the deserialization risks.
|
| Fury put much work on this to avoid the open dynamic
| deserialization risks.
|
| But although `basic collections, enums, Strings, records, and
| classes that register specific serialization code` are the
| only objects should be allowed for serialization, and they
| are serialized by the construction protocol in fury already.
| There are so many applications has used the existing
| serialization protocol assumption, we have to keep
| compatible, otherwise most of application can't use fury.
| mkleczek wrote:
| Why?
|
| Zero copy state transfer is a viable and high performance
| alternative.
|
| Security and integrity can (should?) be implemented at a
| different layer.
| chaokunyang wrote:
| We must realize there always a tradeoff here. If you define
| a dsl for serialization data and generate the code like
| protobuf, the security issue will be much less. But it
| comes with the cost. Protobuf generated class are not the
| domain class, and can't be used for domain-driven
| application developemnt, and it doesn't support circular
| references too. What fury does it provide better
| performance and provide better usability.
| mumblemumble wrote:
| > Zero copy state transfer is a viable and high performance
| _alternative_.
|
| Completely agreed, but also, adding my own emphasis there.
|
| The technique has has enough gotchas, edge cases, and
| additional security considerations that it should really be
| an alternative that people can opt for when they need it,
| and never be the default approach.
| pron wrote:
| But the only reason core serialization is considered a
| "horrible mistake" has nothing to do with performance or
| with any aspect of the technical implementation. It is
| considered a mistake only because serialising arbitrary
| classes breaks invariants in a way that has serious
| correctness and security implications.
| mkleczek wrote:
| The point is that security and bypassing constructors are
| completely orthogonal as serialisation by memcpy is
| completely viable strategy and is no less secure than
| calling constructors on objects.
| chaokunyang wrote:
| Not exactly. For java serialization, you can serialize java
| native object directly without define dsl and compile the
| schema, which are mush more easy to use. But it also means
| the deserialization will need to create the user-defined
| class, which may contains malicious coode in
| `constructor/queals/hashCode`. So the security can't be
| done at a different layer unless you are in a intra-net
| which no attack will happen which may be implemented at a
| different layer but we can't ensure that.
|
| The
| LispSporks22 wrote:
| There's also a chapter on JDK serialized in Bloch's "Effective
| Java" worth a read: Item 85: Prefer
| alternatives to Java serialization Item 86: Implement
| Serializable with great caution Item 87: Consider using
| a custom serialized form Item 88: Write readObject
| methods defensively Item 89: For instance control,
| prefer enum types to readResolve Item 90: Consider
| serialization proxies instead of serialized instances
| chaokunyang wrote:
| Those pattern are all supported in fury. And it seems fury
| are the only framework which implement the jdk `writeObject/r
| eadObject/writeReplace/readResolve/readObjectNoData` methods
| except jdk iteself. Other java serialization will jsut ignore
| those methods, and get incorect results. But today I'll
| suggest to avoid to use JDK `riteObject/readObject/`. Since
| to be compatible with JDK serialization API behaviour, it
| will introduce performance and space overhead. We can
| register custom Serializer by
| fury.registerSerializer(xxx.class, XXXSerializer.class).
|
| `writeReplace/readResolve` are an useful pattern, and can be
| used when needed.
| chaokunyang wrote:
| There are too many java serialization libraries, I compared
| fury with jdk/kryo/fst/protostuff/protobuf/flatbuffers/thrift/m
| sgpack/canproto/acro/jackson/json. Fury are fastest too. See
| https://github.com/eishay/jvm-serializers/wiki for detailed
| benchmark results.
|
| It's a hard choice to select one for the title, so I use JDK
| for it, which may be not a good choice.
|
| BTW, fury support jit serialization for jdk17 record, which is
| super fast compared to other serialization frameworks such as
| kryo
| arnold_palmur wrote:
| No comparisons to SBE in the benchmarks?
| chaokunyang wrote:
| SBE needs to define the xml for the java bean, and generated
| the code. It need lots of work to implement a multiple-layer
| nested objects serialization. So I don't added it for now.
| jarym wrote:
| I wonder how this compares with Microstream One which looked to
| have quite slick serialisation capabilities
| chaokunyang wrote:
| I benchmarked with Microstream using jmh and jvm-serializers
| data. Hare are the results: 1) fury is 43x faster for the
| speed. 2) Fury is 5x smaller for serialized binary size
|
| Here is the code for reproduction:
| https://github.com/chaokunyang/fury-benchmarks#fury-vs-micro...
| jarym wrote:
| Oh nice!! I will certainly try this out. Much of my work
| these days is Java (Kotlin), C# and Python so a good
| serialization framework is always helpful.
| vlovich123 wrote:
| How does Fury compare to static schema serialization
| frameworks that aren't Java focused? For example, flat
| buffers, alkahest, protobuf etc.
| chaokunyang wrote:
| Compared with protobuf, fury is 3.2x faster. When comparing
| with avro, fury is 5.3x faster. Compared with flatbuffers,
| fury is 4.8x faster. See https://github.com/eishay/jvm-
| serializers/wiki for detailed benchmark data
| vlovich123 wrote:
| * on the JVM
|
| Right? Flatbuffers supposedly being slower than protobufs
| is circumspect since most benchmarks I've seen for it in
| C++/Rust show it outperforming, especially since it too
| does zero-copy deser.
| chaokunyang wrote:
| Yes, on the jvm. Haven't tested it for native languages,
| C++/Rust should be faster since it doesn't compress data
| and it's zero-copy
| Game_Ender wrote:
| Two questions:
|
| - Does Fury support versioning?
|
| - What is source of truth for the schema when dealing with
| multiple languages and the same data?
| SpaghettiCthulu wrote:
| I'm curious, why do you appear to generate and compile Java
| source code at runtime instead of generating bytecode directly or
| using `MethodHandle`s?
| chaokunyang wrote:
| Good question! Part of code are generated using `MethodHandle`
| such as some field getters, or constructor. But the overall
| code are generated as source code first at runtime instead of
| bytecode. This is because binary protocol are very complicated.
| Generated the bytecode directly will make the troubleshooting
| more difficult. but it's possible to generated the bytecode
| techniquely. We have an IR abstraction, it's possible to change
| it to generate the bytecode
| aardvark179 wrote:
| The danger with generating source code is that you now depend
| on source rules which may have changed, never applied to your
| source language, or are made more complicated by class
| loading refs. I'd definitely go for byte code generation, and
| possibly using constant dynamic to handle any really tricky
| constants, over source code any day.
| gigatexal wrote:
| can someone help a noob like me understand where i would use
| something like this? is this a way to get faster json parsing?
| knutwannheden wrote:
| Interesting. I will be curious to see how it stacks up against
| Jackson Smile, both in terms of features and performance. Since
| it appears to support both polymorphism and back-references, it
| looks like it already has some advanced features.
| chaokunyang wrote:
| See https://medium.com/@shawn.ck.yang/fury-a-blazing-fast-
| multi-... for fury implementation details
___________________________________________________________________
(page generated 2023-10-08 23:01 UTC)