Redis: Crystal vs Ruby vs Node vs ...
Recently, I have published a Redis client library for Crystal called Crystal-Redis. Since the major reason to use Redis and Crystal is performance, I wanted to make Crystal-Redis fast.
In order to know where I stand with the library, I needed to compare Crystal-Redis with other client libraries in other programming languages. I built a simple benchmark and ported it.
First I measured Crystal against Ruby and C, but then I enjoyed the process and compared also against Go, Node.js and Java. The results are fascinating.
The Benchmark
The benchmark does the following: It connects to Redis and performs 1,000,000 Redis commands SET foo bar
in pipeline mode.
Pipelining means that the client queues up all requests, sends them in one big batch, and then receives all responses in another batch. This is great for a benchmark because it minimizes the impact of the operating system. It focuses the measurement on the overhead caused by the client library and by the programming language.
Performance Tweaks
Initially, I measured Crystal-Redis against Ruby and C. As hoped and expected, Crystal was much faster than Ruby, and slightly slower than C.
Since I was learning Go on the side, I ported this benchmark to two Go clients. Surprisingly, Go with the Redigo library outperformed C with Hiredis, the officially recommended client library for C.
Ary, the Crystal founder, was so friendly to help with Crystal-Redis' performance and tweaked Crystal itself - which improved the result greatly.
Results
After these improvements and measuring more clients/languages, the results are:
Language | Client | Commands per Second |
---|---|---|
C | Hiredis | 338,000 |
Crystal | Crystal-Redis | 685,000 |
Go | Radix | 92,000 |
Go | Redigo | 497,000 |
Java | Jedis | 387,000 |
io.js (Javascript) | ioredis | 93,000 |
Node.js (Javascript) | ioredis | 88,000 |
Ruby | redis-rb | 37,000 |
Ruby | redis-rb/hiredis | 153,000 |
This graph makes the numbers easier to grasp:
Crystal-Redis takes the performance crown... awesome!
But also the other results I find fascinating. Go's performance is just great.
Ruby's redis-rb client supports different drivers and performs accordingly. Using redis-rb with a plain Ruby driver is sad. Fortunately, the C/Hiredis driver changes the picture.
For Javascript, I tried both Node.js and io.js. Disappointingly Javascript wasn't capable of executing the benchmark as described and I had to split the 1,000,000 commands in 10 pipelines of 100,000 commands each.
On the other hand Java performed very well - better than C.
In theory, C with Hiredis should be the top performer. Why it gets defeated by other clients I can only guess. I assume this is caused by the printf style API.
Please mind that the benchmark is very simple and therefore can not support statements like "Crystal is faster than C" or something like that.
Crystal's performance combined with the beautiful syntax and the new great concurrency primitives (spawn / channels just like Go) make the language very promising for me.
Source Code
To make it easy to reproduce my results, I have published the source code for my benchmark including instructions and version numbers on GitHub. I measured on a MacBook Air 13 inch from 2014, intel Core i7 / 1.7 GHz, Yosemite 10.10.3, 8 GB ram with Redis 3.0.1.