We’re probably late to that game, but one of our goals for December was to switch to Ruby 1.9. We use a lot of Ruby at Superfeedr. Some people claim (and some of them are right) that Ruby has a poor performance compared to other languages in the same category. It probably doesn’t matter much if the global architecture allows for horizontal scaling. That’s how we built Superfeedr.
Yet, making each of the node perform better is also a way to increase performance per dollar spent. Additionally, it’s also important to stick with the most active developer community. Even though we haven’t heard of many gems that are not 1.9 compatible, it’s now clear that 1.9 is the “base” for most of the Ruby development. Superfeedr is following this trend too!
To be fair, we were slightly scared of this and expected a few days of work to port our code from 1.8.7 (Enterprise Edition) to Ruby 1.9. It was actually much smoother than expected. All the gems we use were actually 1.9 ready, which allowed us to focus only on our own code.
One of the 2 issues we had was the fact that
Array::to_s has a different implementation in 1.9. Replacing by
Array::join is the way to fix it. Easy.
The 2nd issue was much more complex. Like everyone else, we struggled with Encodings_. Ruby 1.9 is much much better at dealing with encodings than 1.8. Yet, it also requires more work and is a lot more demanding, specially when your app actually ingests a lot of external data, for which you do not control the encoding. Luckily the web has a lot of resources, and I particularly liked James Gray’s series. No matter what, do not use
force_encoding, unless you exactly know and understand what you’re doing. Also, don’t forget that you can use options when converting from one encoding to the other9 to avoid errors. Of course, when dealing with evented libraries (like we do), it’s possible that the buffer on which you receive content will only deal with bytes, and not characters, so you want to be very careful with the data that you get from these buffers, as some characters may be truncated.
I didn’t even mentioned it but, RVM is the way to go on your local development machines if you’d like to switch from a flavor to another.
No surprise here, Ruby 1.9 is much much better than 1.8.7 MRI and 1.8.7 REE. We’re CPU bound, which means that it was our focus, rather than memory.
To make a little benchmark, we pulled 60 feeds from our database, with different formats, different encodings, different sizes (short entries or very long entries), and we ran a our parser on them 20 times each, in a random order, 12 times for each version. We removed outliers and you can find the results here. As you can see the average performance gain is over 35%, which is quite good.
We also measure what we the reactor latency of our different evented applications. As you probably know these use the reactor pattern, which is nothing but an infinite loop that checks sockets, timers and a few other things. From there, it’s easy to use a periodic timer of 1sec and measure exactly how much time was actually spent until we fired it. In a perfect world, this should be exactly 1sec. In reality, when our reactors are actually computing things, they can be slightly slower and we may see a little bit over 1sec. With our Ruby 1.8, the average latency was about 0.1. With 1.9, it’s actually closer to 0.07 which proves once again that our reactors are faster at processing the same code.
Finally, our memory tests proved us that we gained about 20%. Not sure if it’s related to the fact that our code runs faster and hence doesn’t need to use as much memory as it used to, or if it’s just that data-structures are slightly more efficient in 1.9.2, but it’s a decent gain there too.