The Quest for Greater Requests per Second
Posted by feydr | Posted in Uncategorized | Posted on 21-01-2010
View Comments
Was looking at an application the other day (that will rename nameless but any enterprising lad should be able to figure out what it is). It looked like we were clocking in at a whopping One point something requests/second. WHAT THE FUCK!?
I immediately focused my attention with mytop trying to find slow queries. Found quite a few and fixed them. I then started to cache out some of the problem areas and that is when I started to notice something very very unusual.
This particular application uses the merb framework which is sadly fast becoming ghostware with no promise from the powers that be to continue to integrate it into the upcoming rails 3 which was due out a year ago. Apologies, that I don’t have time myself to dedicate to this framework — so I can’t be too harsh, after all it is free software.
You see, we use datamapper as an ORM layer to our database and datamapper collections don’t fit well into memcached since they have procs that can’t be marshalled correctly — if I am wrong about this PLEASE LET ME KNOW.
Caching
So the typical way of caching your shit is to just call your finder from a helper in your view and cache the view. Simple enough I suppose — sounds like it should work. I then proceeeded to fragment cache everything I could.

When I was looking at items that would expire my cache (like a new blogpost upon a page that lists blog entries) I noticed that caching the entire page versus caching just a fragment or a partial of a page was noticeably faster. Now, we aren’t talking like “oh wow, that’s faster”… we are talking “HOLY FUCKING SHIT — that’s fucking faster than shit!”
Templating Performance
This drew me to the realization that makes the article’s purpose. Contrary to popular opinion — templating is a HUGE performance issue.
By caching our sql we gained 5-10X speedups (1 r/s to 5-10 r/s). By caching the entire damn page we went to 20 requests/second — a 20X speedup! That’s double what our best sql/fragment caching could do.
I needed to confirm this because everyone has told me that sql is by far a worse performance killer than templating engines. Well, my benchmarks say otherwise.
Let’s look at some of those benchmarks real quick. These were extremely simple to do and I invite you to replicate them — it’ll take 2 minutes of your time to see for yourself.
I benched all the requests using Apache Benchmark and they look like this:

Actually that is Alchesay, Apache was named cause back in the day when I had nothing to do but beat up on *nix boxen apache had more holes than the town whore.
feydr@mhu:~$ ab -c1 -n100 http://127.0.0.1:4567/hi
Everytime I used a haml template or put the equivalent HTML into the controller as a string it would look like this:
%h1
Hello World
%ul
%li
Blah 1
%li
Blah 2
%li
Blah 3
%li
Blah 4Note: I’m not trying to pick on haml — I really enjoy it — I just don’t want to be delluded that it’s all unicorns sprinting across rainbows shitting shooting stars when it comes to performance — because it is not — furthermore that kind of attitude in the community really aggravates me.

As a side note — anyone who uses the words like ‘tasty’ to describe code needs to go back to their frontpage bullshit.
| Framework | Conditions | Requests/Second |
|---|---|---|
| ————————————————————————————- | ||
| sinatra | with ‘hello world!’ | 838.19 |
| sinatra | with haml | 610.57 |
| merb | with ‘hello world!’ | 341.63 |
| merb | with haml | 271.13 |
| sinatra | w/template in controller | 1321.42 |
| sinatra | w/template and haml | 320.77 |
| merb | w/template in controller | 407.70 |
| merb | w/template and haml | 227.39 |
So what’s the conlusion to this testing? Tell markup languages to take a hike and only use css/html? Nope, we still use haml as I hate looking at html now because of it.
What I ended up doing was caching everything I could up front and then combining multiple renders myself.
Solution
I basically decided to stub out portions of my views that I knew were not easily cacheable like the user layout found on hulu:

Some Code:
You can see I stub out “{begin-login}” with whatever I’m going to replace it with later. This really is not necessary
and I could prob. save a few cycles by not doing this but whatever.
# user specific non-cacheable
# needs 2 renders
if session.authenticated? then
@cache = MMCACHE.clone
begin
@welcomehome = @cache.get("/welcome/homein")
rescue
@posts = Blogpost.all(:order => [:created_at.desc], :limit => 4)
# render our base layout without user-specific stuff
@welcomehome = render :layout => 'cachein'
@cache.set("/welcome/homein", @welcomehome, 0)
end
@cache.quit
# render user-specific stuff if logged in and tack it on
@loginshit = render :template => 'layout/_logout', :layout => false
@welcomehome = @welcomehome.gsub("\"{begin-login}\"", @loginshit)
# non-logged in user -- should only take 1 render
# we have a special section for a logged in user that
# shows their inbox and other things
else
@cache = MMCACHE.clone
begin
@welcomehome = @cache.get("/welcome/homeout")
rescue
@posts = Blogpost.all(:order => [:created_at.desc], :limit => 4)
@welcomehome = render :layout => 'cacheout'
@cache.set("/welcome/homeout", @welcomehome, 0)
end
@cache.quit
end
#output final render
@welcomehomeThis could probably be cleaned up a bit more and be stuffed into a helper but you get the drift.
I did not include any fetch_partial (merb-cache helper methods) benchmarks here but to suffice to say I gained 20 requests/second by NOT using them — YMMV.
Today’s rant/diatribe brought to you by:
- Roxy Music – Take a Chance With Me
- Kid Cudi – Pursuit of Happiness
- Blue Scholars – 50K Deep
So sorry, no crazy new utility to solve templating performance problems other than this hack but this does lay the foundation for more serious research in this category.
Let me know how you solve your templating performance problems in the comments below.

