[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)