Working Efficiently with JSON in Go

Image for post
Image for post

JSON (JavaScript Object Notation) is the most popular format for exchanging data between a server and a client. It is scalable, flexible and supported in most programming languages using powerful libraries.

At TourRadar, we use JSON as a communication format between microservices. With more and more services sending data back and forth, the question of speeding up JSON processing becomes increasingly relevant. Speed is our main factor because it affects customer experience and SEO.

According to the official Go documentation, to decode or encode JSON data we should use the Unmarshal and Marshal functions respectively. So in this manual, the terms marshalling and encoding are used interchangeably.

In this article, we compare the most popular and effective fast encoding and decoding techniques in Go that we use in the company.

Accelerating encoding/json using json-iterator/go

Golang has a standard package, encoding/json, that allows easy encoding and decoding. However, this package relies heavily on reflection, which leads to low performance in high-load systems.

Just like the standard package, json-iterator/go is based on reflection, but it claims to have better performance and speed. It acts as a drop-in replacement of the standard library.

Unlike encoding/json, though, this library is customizable and it has some configuration presets. For example, using jsoniter.ConfigFastest it is even more performant.

Fast decoding of defined structures using easyjson

If we have defined structures, we can use the binary encoder — easyjson. Instead of using reflection, it generates structure-specific marshal/unmarshal functions using a built-in tool. This library aims to keep the generated Go code simple enough so that it can be easily optimized or fixed.

Using the following command we can generate encoding/decoding functions:

Decoding JSON without schema, reflection and code generation using fastjson

We can speed up JSON encoding/decoding using a direct string splitting technique. The following approach doesn’t implement marshalling and unmarshalling, it just performs functions for working with string variables in JSON format.

Fastjson parses arbitrary JSON without code generation, schema, and reflection. It quickly extracts part of the original JSON with Value.Get(…) and supports raw JSON manipulation. It can parse arrays containing values of distinct types (aka non-homogenous types) — for example, it easily parses the following JSON array [123, “foo”, [456], {“k”: “v”}, null].

Usage example:

Benchmarks

To test the speed of each library we used our personal laptops — MacBook Pro (13-inch, 2018), 2,3 GHz Intel Core i5, 16 GB RAM.

We took a simple tour data API response — 15 items (1.2 MB) — and decoded it using different libraries to compare the speed. We also compared it to PHP’s json_decode function.

Image for post
Image for post
Speed comparison of different libraries and languages

Conclusion

Our past experience of working with all of the aforementioned libraries and benchmarks leads us to conclude that the choice of marshalling/unmarshalling method heavily depends on the type of data we’re going to work with. And we recommend mixing different methods depending on the use-cases. In a nutshell:

  • encoding/json (standard library) is a good solution for working with small objects.
  • easyjson is the perfect solution if we have a well-defined structure with a lot of data.
  • fastjson helps improve the speed when we only need some parts of the JSON structure. However, it can’t decode JSON into objects, it just creates a fieldset.
  • json-iterator can help replace the standard library when we have big objects.

These conclusions helped us to fix some of our own bottlenecks during JSON encoding/decoding:

  • fastjson helped us to go from 15 to 1 ms during ElasticSearch terms aggregations decoding.
  • easyjson saved us 50% of the time for decoding of ElasticSearch results.
  • easyjson helped us to encode a JSON response in 2 ms instead of 30 ms.
  • json-iterator saved 30% of the time on encoding/decoding items cached in Redis.
  • Every denormalized tour object has all the available departures. We use fastjson to find the relevant ones for the search and parse only needed information. It increased the speed by 50%.

Hopefully, this has helped you gain a better understanding of how to work with JSON efficiently in Go. And we would love to hear about your experience in the comments.

UPDATE (2019.12.23). Another drop-in replacement for encoding/json was recommended by the Reddit communityhttps://github.com/segmentio/encoding. It encodes in 4.5 ms (-40% compared to json-iterator/go) and decodes in 7.7 ms (-13% compared to json-iterator/go).

UPDATE (2019.12.24).By re-using fastjson.ParserPool we went from 5.1 ms to 1.6 ms thanks to the recommendation from Reddit.

TourRadar

TourRadar’s the world’s largest online travel agency for…

Alexander Yaremchuk

Written by

Senior Software Engineer / TourRadar

TourRadar

TourRadar

TourRadar’s the world’s largest online travel agency for multi-day tours. Housing over 2,000 tour operators, we offer more than 40,000 tours in 200 countries.

Alexander Yaremchuk

Written by

Senior Software Engineer / TourRadar

TourRadar

TourRadar

TourRadar’s the world’s largest online travel agency for multi-day tours. Housing over 2,000 tour operators, we offer more than 40,000 tours in 200 countries.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store