RailsConf Panel: Rails Application Optimization Techniques & Tools (With Stefan Kaes)

“www.railsexpress.de”:www.railsexpress.de

!http://static.flickr.com/75/173400476_35563faaf5_m.jpg!:http://flickr.com/photos/kastner/173400476/

Before the panel even started, the room was totally filled to capacity. I’m really looking forward to this talk. The other big one going on right now is “Monitoring Rails Apps in Production Environments with Steven Smith”

!http://static.flickr.com/59/173402175_7e76184fae_m.jpg!:http://flickr.com/photos/kastner/173402175/

*The short version:*
Great talk, but WAY TOO FAST. He had a TON of info, and not enough time.

h3. A tiny piece of history.

Stefen started by writing a recipe app (not sexy, but a good start). He wasn’t happy with the performance with the app, so he learned how to optimize it and that is what this talk is about.

Performance Paramaters:
* How fast can you answer a request
* Throughput – requests / second
* Utilization – Servers used enough, but not too much?
* Cost efficiencey

When you compute – get mean, min, max and standard dev.

Benchmarking Tools:
* Rails log files (debug level >= Logger::DEBUG)
* Rails Analyzer Tools (you have to be logging to syslog for this to work)
* Rails benchmarker script (script/benchmarker)
* Tools provided by your DB vendor
* Apache bench (ab)
* httpperf
* “railsbench”:http://rubyforge.org/projects/railsbench/

h3. Railsbench

This tool measures request processing.
Setup is easy – config/benchmarks.yml

default:
uri: /

all: default, empty, welcom, cat, letter@

config/benchmarks.rb


RAILS.BENCHMAKER = RailsBenchmarkWithActiveRecordStoe.new
require 'user'
RAILS_BENCHMARKER.session_data = {:user_id => 23}

@perf_run 100 “-bm=welcom options” [data_file]@

h3. Ruby Profiling

The best one is Ruby Performance Validator commercial and windows only.
with railsbench:
@run_ruls 100 -svlPV -bm=welcome …@
starts RPVL and run the named benchmark with the given options

RPV:
!http://static.flickr.com/66/173411504_6e270f7eda_m.jpg!:http://flickr.com/photos/kastner/173411504/

h3. Top Rails Performance Problems:

* show helper methods
Keep helpers short
* complicated routes
routes are a problem, keep them simple
* associations
The proxy object is expensive
* too much data from the DB
Get what you need!
* slow session storage
Using ActiveRecordStore is SLOW (humm..)

DB isn’t usually the problem in his experience. AR is more of a problem

h4. Session conatiners:

* In Memory – fast, but lose on restart
* File system
Easy setup, one file per session, scales in NFS, but slower then ar
* Database/ActiveRecordStore
* “Database/SQLSessionStore”:http://railsexpress.de/blog/articles/2005/12/19/roll-your-won-sql-session-store
Uses ARStore session table format but does all procession using raw SQL queries.
* memecached
Faster then SQLSessionStore. Should scale best. Very tunable – harder to get stats
* DrbStore
used where memcached isn’t an option

h3. Caching

* Pages
Fastest, complete pages are stored and served wholey
* Actions
Second fastest. Caches the RESULTS of invoking actions on controllers
* Fragments
Useful for caching small fragments of HTML produced during request procession. They can be made user aware.

Action caching is just a special case of fragment caching.

h3. Components

Don’t use them. Not really any good uses (anybody?) Each embeded component is it’s own request (a whole process). And they can usually be rewritten using helper methods and partials.

h3. ActionView Issues

Instance variables
For each request, one controller instance and one view instance will be instanched
So avoid passing what you don’t need

h3. Slow Helper Methods

@pluralize(n,’post’)@
versus
@pluralize(n,’post’,’posts’)@
The first one instanciates Inflector. The second doesn’t.

link_to and url_for are slow. They have to do the whole route generation (which is a slow sub-process).
They are some of the slowest helper methods.
Either hand code when you need speed – or wait for his template optimizer!

h3. ActiveRecord Issues

* Associations
:include makes it faster
for has_one or belongs_to
@piggy_back :autor_name, :from => :author, :attributes => [:name]@
@article = Article.find (:first, :piggy => :author)@
(google search for “piggybacking with rails”)
piggy_back is an extension he wrote. It makes them strings – like article.author_name
Also, cache converted types. Converting is slow.

Cache textalize calls if you can (a second column would be a good idea)

h3. Ruby’s interpreter is slow

not JIT, no bytecode.

Therefore, complexity of ruby elements
Locals: O(1)
Instance vars: O(1)
Method call: O(1)
Don’t add methods that you don’t need.

Local vars are cheap

h3. Memory Managment

* Designed for batch scripts, not big server apps (bad for rails!)
* tries to minimize memory use
* simple GC (mark and sweep)
* uses malloc to manage contigous blocks of Ruby objects
* complex data structures

Ruby’s GC is not optimal for Rails
For rails, 4096 is too small for heap slots – 200,000 is a much better lower bound
@RailsFCGIHandler.process! nil,50@
will disable ruby gc and call gc.start after 50 requests.
However, small and large requests are treated the same :(

Patch Ruby’s GC (someone? please?)

h3. Template Optimizer

@< %= end_form_tag %>@ can be cached as </form>
even if you don’t know it all, it’s possible to cache some of it (what you DO know)

SICK speedup. Will be released later. He’s also releasing a book next year from Addison Wesley’s “Professional Ruby”