Copyright Dimelo SA www.dimelo.com Rails performance: Controlled expiration on Fragment Caching Renaud MORVAN [email_addre...
Given a slow partial on a website Copyright Dimelo SA www.dimelo.com
Load is skyrocketing when traffic increase Copyright Dimelo SA www.dimelo.com
A known solution: fragment caching <ul><li>Easy to implement: </li></ul><ul><li><% cache(&quot;mycachekey&quot;) do %> </l...
Sweeping is hard <ul><li>« There are only two hard things in Computer Science: cache invalidation and naming things. » </l...
Sweeping is hard <ul><li>Memcache is the prefered way to do fragment caching </li></ul><ul><li>Memcache implement key expi...
But ... here is the load profile when traffic keep on increasing Copyright Dimelo SA www.dimelo.com
Fragment cache is no silver bullet <ul><li>It synchronizes cached part across process </li></ul><ul><li>The slower the cal...
Solution: backgrounded sweeping <ul><li>hard </li></ul><ul><li>messy </li></ul><ul><li>buggy </li></ul><ul><li>cron/observ...
My solution: Atomic fragment caching <ul><li>Don’t use memcached built-in expiration   </li></ul><ul><li>Use software expi...
Quick proposal: <ul><li>Trigger only one recalculation for all processes </li></ul><ul><li>Serve old cache during recalcul...
Upcoming SlideShare
Loading in …5
×

Improve behavior of Rails fragment caching at high volume

1,780 views
1,681 views

Published on

Rails fragment caching is one of simple tool against performance issue. Using memcache cache store you get a lean and scalable solution to cache part of request.

Memcached support time based cache expiry which reduce down to zero the need for plumbing code for cache sweeping, while providing a decent generic solution to a lot of case.

Yet when volumes is growing and fragment takes time to be generated it tends to create load of peak by synchronizing cache recalculation on multiple process, annihilating cache purposes and killing performance of the whole stack.

The purpose of this talk is to describe the problem and propose an alternative cache store that preserves the simplicity of rails fragment cache mechanism based on time expiry while offering atomic cache invalidation and refreshing.

This presentation was done during and for Paris.rb ruby user group on August '11. This should be considered experimental and open to discussion and improvement.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,780
On SlideShare
0
From Embeds
0
Number of Embeds
8
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Improve behavior of Rails fragment caching at high volume

  1. 1. Copyright Dimelo SA www.dimelo.com Rails performance: Controlled expiration on Fragment Caching Renaud MORVAN [email_address]
  2. 2. Given a slow partial on a website Copyright Dimelo SA www.dimelo.com
  3. 3. Load is skyrocketing when traffic increase Copyright Dimelo SA www.dimelo.com
  4. 4. A known solution: fragment caching <ul><li>Easy to implement: </li></ul><ul><li><% cache(&quot;mycachekey&quot;) do %> </li></ul><ul><li>All the topics in the system: </li></ul><ul><li><%= render :partial => &quot;topic&quot;, :collection => Topic.find(:all) %> </li></ul><ul><li><% end %> </li></ul><ul><li>But you have to sweep it !!! </li></ul>Copyright Dimelo SA www.dimelo.com
  5. 5. Sweeping is hard <ul><li>« There are only two hard things in Computer Science: cache invalidation and naming things. » </li></ul>Copyright Dimelo SA www.dimelo.com
  6. 6. Sweeping is hard <ul><li>Memcache is the prefered way to do fragment caching </li></ul><ul><li>Memcache implement key expirations </li></ul><ul><li><% cache(&quot;mycachekey&quot;, :expires_in => 3.minutes) do %> </li></ul><ul><li><% end %> </li></ul><ul><li>Great solution for medium term, no sweeper to manage </li></ul>Copyright Dimelo SA www.dimelo.com
  7. 7. But ... here is the load profile when traffic keep on increasing Copyright Dimelo SA www.dimelo.com
  8. 8. Fragment cache is no silver bullet <ul><li>It synchronizes cached part across process </li></ul><ul><li>The slower the calculation the worse the increase of the load </li></ul><ul><li>Multiple process try to recalculate key </li></ul><ul><li>def cache key, options = {}, &block </li></ul><ul><ul><li>unless Rails.cache.read key, options </li></ul></ul><ul><ul><li>yield.tap do |result| </li></ul></ul><ul><ul><li>Rails.cache.write key, result, options </li></ul></ul><ul><ul><li>end </li></ul></ul><ul><ul><li>end </li></ul></ul><ul><li>end </li></ul>Copyright Dimelo SA www.dimelo.com
  9. 9. Solution: backgrounded sweeping <ul><li>hard </li></ul><ul><li>messy </li></ul><ul><li>buggy </li></ul><ul><li>cron/observer debugging is painful </li></ul><ul><li>code is split between multiple files </li></ul>Copyright Dimelo SA www.dimelo.com
  10. 10. My solution: Atomic fragment caching <ul><li>Don’t use memcached built-in expiration </li></ul><ul><li>Use software expiration </li></ul><ul><li>When expiration time is reached, increase expiration and trigger cache recalculation </li></ul><ul><li>Short expired period => few concurrent recalculation </li></ul>Copyright Dimelo SA www.dimelo.com
  11. 11. Quick proposal: <ul><li>Trigger only one recalculation for all processes </li></ul><ul><li>Serve old cache during recalculation period </li></ul><ul><li>Synchronous OR backgrounded recalculation </li></ul><ul><li>Code just in one place, no plumbing </li></ul><ul><li>https://gist.github.com/1186564 </li></ul>Copyright Dimelo SA www.dimelo.com

×