Latest Update

Using MongoDB with Rack::Cache

January 18, 2012 at 11:33 am

One of the problems I have often had with caching is that it becomes more difficult the second you grow past a single server – and let’s face it, most sites these days either aren’t or shouldn’t be running on one box.

I’m a huge fan of Heroku, and could talk for a long time about how their service inspires developers to write things by taking away almost all of the complexity of actually running your creation. The downside of this is that you’re left with some expensive options for basic tasks. Whilst 5mb of Memcached is free, 100mb is $20/mo and 250mb is $40/mo. MongoDB offers a lot more storage for low/free cost – and is pretty fast to boot. Coupled with the fact that it is a persistent data-store, it is ideal for storing your cache entities in – these are the things that we don’t really want to have to rebuild very often, and when we scale a new dyno up, having access to essentially a warm cache right off the bat is ideal. There are, of course, a lot of SaaS Mongo providers out there, but you can get up to 240mb of storage for free…

To plug this easily into Rack::Cache, I’ve written a patch which supports MongoDB entitystores. I did not code the MetaStore functionality, as I believe that is better served from Redis or Memcached – which is likely to be a bit quicker. There is a pull request for this to be brought into Ryan Tomayko’s master, but until (if) that happens, you can get it from the “mongodb” branch at http://github.com/jgwmaxwell/rack-cache. To use this in an app, you can put the following in your Gemfile:

then to configure the MongoDB EntityStore, you can do one of 2 things where you configure the middleware:

With this you’re ready to go. Hope you find it useful, we are using it in production at Cambelt and it hasn’t missed a beat so far, with speed slightly faster than using the Disk EntityStore.

MRI Performance Shootout

January 9, 2012 at 8:45 am

Following on from my recent attempts at benchmarking Ruby VMs, I decided to test all the server options available for the MRI (1.9.3p0) platform against each other. This is still just running the simple “Hello World” Sinatra app, that uses an erb template so there is more processing involved than simply outputting a string. The Contenders: Thin 1.3.1, running in production Puma 0.9.3, running in production Mongrel 1.2.0.pre2, running in production Webrick 1.3.1, running in production Passenger 3.0.11 standalone, running in production Unicorn 4.1.1, 1 worker process, running in production The results are as below for “ab -n 10000 -c 1”: (higher is better) Additionally, we need to care about how long the slowest requests are taking, so I’ve taken the response times of the 98% percentile from the AB testing, and plotted these here: (lower is better) I’m quite surprised by this, if I’m honest. Unicorn certainly has a Read more…

Accelerating Ruby APIs

December 26, 2011 at 12:44 am

Collecting Data through an API I’ve been working on improving an API that collects stats for an application I run. Initially we were collecting data through Rails, as the rest of the application runs on rails, but I started thinking that this was surely overkill – after all this is simply stats data – what is needed is realtime, highly concurrent collection – which the advanced features of rails are not particularly suited to. Let’s face it – a packet describing a particular stat is unlikely to be wrongly formed, and the business consequences of saving a malformed packet are low in the extreme, and a background process can quite happily walk through the database removing invalid packages when the service is quiet – allowing eventual validity to occur. So, I started to re-factor, and more importantly re-think. A stat packet, collected either by a HTTP request – such as for Read more…

Quick Sinatra Tip #1

December 16, 2011 at 8:10 pm

It might seem obvious, but remember you can inherit from any class when making modular Sinatra apps, so if you find yourself repeating a large amount of functionality, then it is simple to DRY that up. Then just require and inherit from your new class – simple! Obviously not a very complex example, but it’s surprising how often I have to remind myself that simple can still be DRY.