Always use OJ for serialization (unless you’re using JRuby).
The out-of-the-box solution for serialization in ruby is either the built-in JSON or the binary Marshal format. The former has the advantage that it’s a human readable, standardized and universal format, while the Marshal format is specific to ruby and not very human readable.
I was under the impression that the choice between those two was a decision between JSON and fast. For ruby’s core and standard library this is certainly true. But let’s have a closer look at the alternatives.
--> Benchmarking an object of type Hash
JSON (using oj): 68.3 i/s
MessagePack: 62.7 i/s - 1.09x slower
BSON: 54.7 i/s - 1.25x slower
Marshal: 41.4 i/s - 1.65x slower
JSON (using Yajl): 31.3 i/s - 2.18x slower
JSON (built-in ruby): 26.9 i/s - 2.54x slower
YAML: 1.2 i/s - 59.15x slower
--> Benchmarking an object of type String
JSON (using oj): 344.6 i/s
BSON: 308.3 i/s - 1.12x slower
Marshal: 151.1 i/s - 2.28x slower
MessagePack: 127.8 i/s - 2.70x slower
JSON (built-in ruby): 99.2 i/s - 3.47x slower
JSON (using Yajl): 96.9 i/s - 3.55x slower
YAML: 4.7 i/s - 74.01x slower
--> Benchmarking an object of type Float
BSON: 332.6 i/s
JSON (using oj): 204.1 i/s - 1.63x slower
Marshal: 168.1 i/s - 1.98x slower
MessagePack: 124.3 i/s - 2.68x slower
JSON (built-in ruby): 83.8 i/s - 3.97x slower
JSON (using Yajl): 80.2 i/s - 4.15x slower
YAML: 4.5 i/s - 73.27x slower
So far OJ and BSON are the fast ones.
When evaluating a serializer it’s important that it’s a general purpose serializer, meaning that it can handle an arbitrary type without the need of modifying it. Most of the benchmarked serializers are eliminated by this requirement. The stereobooster/ruby-json-benchmark repository provides a nice overview of the capabilities of the different json implementations.
The next benchmark iteration focuses on the two fastest ones that can handle all types.
--> Benchmarking an object of type Float
JSON (using oj): 198.8 i/s
Marshal: 169.1 i/s - 1.18x slower
--> Benchmarking an object of type Hash
JSON (using oj): 70.9 i/s
Marshal: 44.4 i/s - 1.60x slower
--> Benchmarking an object of type String
JSON (using oj): 368.0 i/s
Marshal: 158.3 i/s - 2.33x slower
--> Benchmarking an object of type CustomClass
JSON (using oj): 195.2 i/s
Marshal: 87.4 i/s - 2.23x slower
Serializing a custom type is more than twice as fast with OJ than it is with Marshal.
Unless you are on JRuby I’d always use OJ. It is overall the fastest implementation and also provides the convenience of JSON. Additionally, if you’re using Ruby on Rails, you can use OJ as a drop in replacement for the standard implementation.
The benchmarks were made using benchmark-ips on a Lenovo X1 Carbon, Intel® Core™ i7-7600U CPU @ 2.80GHz, 16GB DDR3 RAM, running Ubuntu and running with ruby 2.5.0. Each iteration is performing a serialization and a subsequent deserialization.
The whole benchmark code is available as a gist.