Thin is getting thinner by the day


Labels: , , , , ,

It seems that macournoyer is in a frenzy of releases for Thin!. He just released the 0.6.1 sweet cheesecake release (what's up with the release names? I'm trying to control my diet here!). The new release uses less memory than Mongrel which is a very good thing IMHO. It also uses the same config files used for Mongrel Cluster. The big bang is the ability to use UNIX sockets to connect to the load balancer instead of TCP connections. This decreases the overhead of nginx sending requests and getting responses back from the upstream servers.

These are good news, though I will have to test if this will translate to noticeable performance increase in a full fledged Ruby on Rails application

I will redo my tests with this new setup and come back with more numbers

Stay tuned

Coding around the globe


Yesterday I was doing lots of testing and I had to install and reinstall many components between tests. apt-get install and gem install were next only to ab and httperf in command usage frequency yesterday. I was setting up the stack several times and when I realized the following:

I was using the nginx web server (authored by a Russian)
I tested against Mongrel application server (authored by an American) and Thin application server (authored by a Canadian)
I built the test application using the Rails application framework (authored by a Danish)
I was programming this app in the Ruby language (authored by a Japanese)
All work was done on Linux OS (originally authored by a Finnish)
I was doing all this work in Egypt for a service partner located in UAE

Not to mention the authors of the numerous tools I worked with in that particular day. I suddenly felt connected with all of them. I was thankful to live in a time were people from every where could contribute to a particular problem. It is amazing to see the culmination of efforts of many who are seemingly separated but in the end they seem all to be working in an unintended harmony. I felt that our little service is composed of bits and pieces from all over the globe. I only knitted them together with amazing results.

The numbers are in, Thin is (sort of) faster than Mongrel for production apps.


Labels: , , , ,

I have been playing with the Thin + nginx combo for a while now. I did a lot of stress testing using an actual application that is ready to go for production soon. I played with both Thin and Mongrel to see if there is a big difference.

I need not mention that I didn't bother testing Apache as a proxy balancer instead of nginx, I am getting an earth shaking 7900 req/s for static requests using nginx on an application serving unit.

Our application serving units are xen virtual servers with a quad core processor each. It runs The nginx web server and the web application cluster (Mongrel currently, but may be Thin too). The cluster runs 10 Mongrels and 4 nginx workers. Any application can scale its front end by adding more of those application serving units.

While testing I was surprised that after a certain test Thin was giving me results that were slower than Mongrel. Repeating the tests or letting the system load cool down didn't help. What I found was that I hit the memory limit and the system started swapping. I shut down one Thin server and suddenly they started to outperform (albeit by a small margin) the Mongrel cluster again.

I tested against three of the very heavy pages. The results were the average of three runs for each page in the specified concurrency/connections pair

So here are the numbers (using Apache Bench):
100/1000 200/1000 200/10000
Thin 104.3req/s 115.7req/s 123.1req/s
Mongrel 100.6req/s 113.2req/s 121.6req/s

The figures speak for themselves; while Thin is constantly faster than Mongrel, the difference is negligible. I am assuming that this is due to the fact that most of the time is spent in processing the Rails stack and doing IO with memcached then sending the actual repsonse back. The raw differences between Thin and Mongrel are dwarfed by the time spent in Rails. You will see a good advantage for Thin when you are doing very small requests that do little processing and send small responses. While this is not the case for this particular test, it is typical in many Ajax intensive applications. And since this application is full of Ajax requests, I believe that we might opt for Thin at the end.

I have to say that I was very happy with the results so far. Mongrel and Thin are both robust and nginx is a true gem ;). The application is expected to generate lots of traffic and I am confident that scaling would only be a matter of adding more boxes. My next challenge is to get more performance out of those boxes. Which is a possibility since Evan is working on a much better memcached client for Ruby. Knowing that Evan is working on Mongrel too is reassuring me regarding its future.

Thin, the thin server that can!


Labels: , , , ,

I did some testing for the new kid on the block. The Thin Ruby web server. I used 4 instances and Nginx as my proxy server.

Thin is based on tried and true components (best in their class if you ask me). It's got its parser from Mongrel, IO management by Eventmachine and finally it connects to your favorite Ruby framework via Rack. It's amazing how one can achieve much just by blending the right components together.

For static page serving, I got a whopping ~2500 req/s on my 2GHZ Core 2 Duo machine. (vs ~900 req/s for the same machine running Mongrels). That's for 1000 concurrent users using Apache Bench

I also managed to achieve ~1200 req/s for a dynamic request in Rails that prints out 'Hello world!'. For the same 1000 concurrent users.

I will put it to real test in the coming days in more real world scenarios. I hope to be able to post the results here soon.

Restful Pagination in Rails


Labels: , ,

Have you ever tried to cache your paginated lists? Sadly, vanilla Rails wont help much as they ignore the url query parameters when caching and hence the page=x value is not honored and Rails caching (action or page caching) will simply stick to the first page rendered for all requests.

One might come with a solution that overrides the cache key generation to incorporate the query string, which will work, but will result in very long and ugly hash keys.

Luckily there is a better approach, if you simply defined routs for pages (for the paginated resources) and name them page parameter with the same name you give it in the paginator then Rails will pick up the route when creating paginated links.

In your routes.rb
map.resources    :users
map.paged_users '/users/pages/:page'
map.formatted_paged_users '/users/pages/:page.:format'

once the above routes are in place, all you need is to make sure your paginators are using 'page' as the page parameter name and you will see the pagination links created like this:

Don't forget the formatted route to support pagination with various formats so you can use routes like:

These urls are very cache friendly and adhere to REST much more than the default parameters based ones.

Happy caching (with pagination)