Fighting the Unicorns: Becoming a Thin Wizard on Heroku

December 30, 2011 at 5:11 pm

One of the cool things about Heroku is that it makes life really easy for those who use it – and for 99% of applications I love being able to simply forget about sysadmin tasks and just get on with writing code.

Lots of people have started using Unicorn to serve apps on Heroku, which allows you to fork off worker processes to absolutely maximise the computational power of each Dyno. There have been some great articles on this, such as this one on using Unicorn and this one on using resque workers in-dyno. This certainly can give you a performance boost, but I’ve never been a massive fan of Unicorn, much preferring Thin.

I’m not going to go into a full discussion of Thin vs Unicorn and the relative merits of each system, however normally the discussion is a Unicorn system with 3/4+ workers, vs a single instance of Thin per dyno.

This doesn’t have to be the case. I’ve put up a version of https://github.com/zapnap/toopaste running on heroku at http://thin-cluster.herokuapp.com - this is running on a cluster of 3 Thin servers, with load balancing done by an Event Machine (EM Proxy) reverse proxy, all in one dyno.

There is a limit to how much performance you can get out of a single dyno – and you have to be careful about how much you load onto one – there is only so much RAM and CPU available, but you can do some pretty cool things without going beyond the constraints of a single dyno.

The key to this is using the “spawn” or “fork” command as part of your initialisation script – this allows you to add processes to the dyno, rather than starting up a whole new dyno (and thus getting billed extra). I wouldn’t recommend doing this for heavy tasks, as you’re simply eating further into your resources, but for a lot of purposes then it works very well.

The final part to rolling your own solution like this is to remember that Heroku only supports connections coming in to your app through a single external port. If you try and bind other ports, even to localhost, they will fail and crash your app. This makes it a bit tricky to work out this proxying idea, as we can’t bind the servers in clusters to ports.

Fortunately there is a solution which is far better than binding to a TCP port anyway – Unix Sockets. Again, discussing how they work is outside the scope of this article, but Unix Sockets are a lot faster than binding to a TCP port – this is always a good upgrade to make. Remember though, unfortunately sockets are only for internal communication, and can’t be reached from outside the machine.

So, if you want to have a play:

Have a play and see what you can come up with – remember the Heroku platform is far more flexible than it appears at first!