Categorygithub.com/boguslaw-wojcik/encoding-benchmarks

# README

Encoding Benchmarks

A simple benchmark comparing Protobuf, AVRO and JSON encoding implementations in Go.

Why yet another benchmark?

  • You cannot directly compare performance of cross-platform technologies. You can only compare performance of their available implementations in a specific language. What is true for one language might not be the case for another. Most benchmarks I have initially found focus mostly on C and Java implementations and these not necessarily carry over to Go which is still relatively young.
  • Experience shows that very often unofficial implementations provide a game-changing performance boost being sometimes even ten times faster than a standard solution. Most benchmarks I have found compare official or standard implementations. On top of that, new improvements and solutions are being constantly developed. In some cases new version of the same library brought improvements eliminating previous performance gap that was not reflected in the old benchmarks.
  • Many of the published benchmarks tend to share two characteristics. First, they often focus on the message size, benchmarking large and small but mostly flat payloads, ignoring message complexity arising from nested structures. Secondly, some benchmarks entirely skip the model-mapping part of the encoding/decoding process, which results in hiding the CPU and memory cost we will have to eventually pay in all our applications. Wherever required I have provided custom code to complete mapping process in order to measure cost of the entire process.

Decoding Performance

FormatLibrarySamplePerformanceMemoryAllocationsCustom Work
Protobufgogo/protobuf2000000579 ns/op439 B/op7 allocs/opno
Protobufgolang/protobuf (official library)2000000827 ns/op360 B/op10 allocs/opno
AVROactgardner/gogen-avro10000001335 ns/op472 B/op35 allocs/opno
JSONjson-iterator/go10000001341 ns/op64 B/op4 allocs/opno
AVROlinkedin/goavro (map)10000002101 ns/op1776 B/op39 allocs/opno
AVROlinkedin/goavro (struct)5000002637 ns/op2016 B/op44 allocs/opyes
JSONbuger/jsonparser5000003647 ns/op669 B/op15 allocs/opyes
JSONencoding/json (standard library)2000007914 ns/op320 B/op19 allocs/opno

Encoding Performance

FormatLibrarySamplePerformanceMemoryAllocationsCustom Work
Protobufgogo/protobuf10000000225 ns/op160 B/op2 allocs/opno
Protobufgolang/protobuf (official)3000000560 ns/op160 B/op2 allocs/opno
AVROlinkedin/goavro (map)2000000722 ns/op320 B/op11 allocs/opno
AVROactgardner/gogen-avro10000001526 ns/op501 B/op7 allocs/opno
JSONjson-iterator/go10000001659 ns/op360 B/op3 allocs/opno
AVROlinkedin/goavro (struct)10000002294 ns/op1856 B/op37 allocs/opyes
JSONencoding/json (standard library)5000002566 ns/op352 B/op2 allocs/opno

Payload Size

FormatSize
AVRO100 B
AVRO + wire105 B
Protobuf116 B
JSON302 B
Note: In order to benefit from AVRO forward compatibility you need to always transmit messages with unique ID of schema held in a schema registry, which adds additional 5 bytes to the beginning of each payload as per its universally adopted wire format.

Highlights

  • Winning gogo/protobuf library is in general over 12 times faster than standard JSON library but really only a bit over 2 times faster than json-iterator/go in decoding. While these are still incredible results, they slightly contrast with commonly exaggerated opinions.
  • Both AVRO implementations are generally on par with best available JSON solution in terms of performance while utilizing more memory for each operation. It is important to note that despite slightly better overall performance, actgardner/gogen-avro cannot be easily used in system relying on forward compatibility of transmitted payloads, which in turn makes LinkedIn solution preferable.
  • At any time any strongly typed binary format such as Protobuf or AVRO should be chosen over JSON for internal communication - if not for performance boost then at least because of 3 times smaller payloads.
  • Sometimes considered the fastest JSON decoding library buger/jsonparser lives up to this expectation only if a set of specific conditions are met. In typical use cases, while still being huge improvement over standard library, it falls short of json-iterator/go. That being said it is still a great library which is a life-saver when you have to parse just one or two fields out of the entire JSON payload or you are dealing with an unsafe and unstable third party API.

Tested libraries

How to run the benchmark locally?

$ git clone [email protected]:boguslaw-wojcik/encoding-benchmarks.git
$ cd encoding-benchmarks
$ go get
$ go test -bench=.

Reference Message

All benchmarks have been performed with following reference message containing mix of textual, numeric and logical attributes combined with nested object in a collection.

{
  "id": 234765,
  "affiliation_id": 9867,
  "name": "Wolverine",
  "life": 85.25,
  "energy": 32.75,
  "powers": [
    {
      "id": 2345,
      "name": "Bone Claws",
      "damage": 5,
      "energy": 1.15,
      "passive": false,
    },
    {
      "id": 2346,
      "name": "Regeneration",
      "damage": -2,
      "energy": 0.55,
      "passive": true
    },
    {
      "id": 2347,
      "name": "Adamant skeleton",
      "damage": -10,
      "energy": 0,
      "passive": true
    }
  ]
}

Contributions welcomed

Feel free to report issue or create a pull request.

# Packages

No description provided by the author
No description provided by the author
No description provided by the author