Tonight’s keynote at RailsConfEurope 2008 was “Performance on Rails” by Jeremy Kemper of 37signals.
In the upcoming Rails2.2 release there are a lot of minor changes, not really big paradigm shifting changes. One of the things the core team has focused on is performance.
What is performance
Jeremy first asks the question “what is a performant application?”. To Jeremy a performant application is snappy for it’s users (it’s all about the user experience). To make the application snappy you could prematurely optimize your Rails app’s code, add more hardware to it etc.
Focus on the front-end first
It is more effective though to focus on the front-end / browser first;:
- look what is pulled to the client: firebug network tag, YSlow (checks rules at http://developer.yahoo.com/performance/rules.html)
- add expire headers (e.g. for all your assets with ExpiresActiveOn or FileETag in Apache), combine js and css files etc. (rails has facilities for this)
- multiple asset host (e.g. with config.action_controller.asset_host = “asset%d.myapp.com” in your Rails config)
- try not to put javascript inline, but use unobtrusive javascript (e.g. LowPro)
but the most useful thing is to look if your app can do less
Then measure and improve your Rails app
When you have done all that, then you can look at your Rails app. For this you need instrumentation. Where is the time spent, is it my Rails app, the database, the web?
- A nice new tool for this is New Relic RPM (overall performance)
- Another tool is FiveRuns TuneUp (code profiling)
- script/performance/request (shipped with Rails2.1 >), which plays an “integration test” script. Is a bit ad-hoc and results are hard to interpret. Following tool is more useful:
- Rails2.2 will support performance tests (/test/performance/*_test.rb) . Can be run with “rake test:benchmarks”. Saves results in csv file so benchmarks can be plotted over time and different ruby versions can be compared.
Another way to optimize is “conditional GETS” which fits nicely with the Rails REST philosophy. Works with Last-modified and ETag headers, which you can set yourself in the controller (see slides for examples), but Rails2.2 (I think it’s not in 2.1 yet ?) has support for this.But what about caching proxies? Jeremy admits that he might not know enough about them, but might be interesting for Rails apps.
Fixing the Garbage Collector
Another area that can be improved is the ruby garbage collector. This is setup for short lived processes, but in webapps the processes are long lived. Luckely there is a patch for the Ruby GC that lets you tweak it.
http://github.com/skaes/railsbench
For a typical webapp Jeremy recommends the following settings (to be sure, check the slides!):
RUBY_HEAP_MIN_SLOTS=6000000
RUBY_HEAP_FREE_MIN-100000
RUBY_HEAP_MALLOC_LIMIT=60000000
According to Jeremy this wil give you a (almost) free performance boost, so that might be worth looking into.
Caching
Problem is generating good cache keys (“Expect to get it wrong”).
So try to design for cacheability (see slides)
Rails performance?
To Jeremy the most performance gains can be found outside Rails (browser, caching etc.).
Resources
Slides: later on conference site