Accelerate Your Rails Site with Automatic Generation-Based Action Caching


Published on

Published in: Technology
1 Like
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Accelerate Your Rails Site with Automatic Generation-Based Action Caching

  1. 1. Accelerate Your Rails Site with Automatic Generation-Based Action Caching Rod Cope, CTO and Founder OpenLogic, Inc. Wednesday, July 29, 2009
  2. 2. Goal Built-in caching is hard: Learn how to automate it to make the pain go away OpenLogic Company Confidential 2 Wednesday, July 29, 2009
  3. 3. Agenda Introduction Built-in caching Automatic generation-based caching Bonus material Conclusion & recommendations OpenLogic Company Confidential 3 Wednesday, July 29, 2009
  4. 4. Introduction Rod Cope CTO & Founder of OpenLogic 25 years of software development experience IBM Global Services, Anthem, Ericsson, many more OpenLogic, Inc. Governance, SLA support, security updates, and indemnification for over 500 Open Source packages Dozens of Fortune 500 customers OSS Census ( Global, community effort to catalog use of open source OpenLogic Company Confidential 4 Wednesday, July 29, 2009
  5. 5. No Spoon Feeding OpenLogic Company Confidential 5 Wednesday, July 29, 2009
  6. 6. Don’t Panic OpenLogic Company Confidential 6 Wednesday, July 29, 2009
  7. 7. Reasons for Caching Lots of hits, speed is king Google OpenLogic Company Confidential 7 Wednesday, July 29, 2009
  8. 8. OpenLogic Company Confidential 8 Wednesday, July 29, 2009
  9. 9. Reasons for Caching Lots of hits, speed is king Google Complex hits, richness is king OpenLogic’s OLEX OpenLogic Company Confidential 9 Wednesday, July 29, 2009
  10. 10. OpenLogic Company Confidential 10 Wednesday, July 29, 2009
  11. 11. Rails Caching Background Page caching Uberfast, little control Highly dynamic site? Move on. Action caching Fast, lots of control Expiration hell Fragment caching Expiration hell OpenLogic Company Confidential 11 Wednesday, July 29, 2009
  12. 12. Problems with Rails Caching Caching is easy to implement “Site’s borked again - turn off caching.” Hard to clear (the right) caches when you’re mixing and matching different types, styles, developers, plugins, etc. OpenLogic Company Confidential 12 Wednesday, July 29, 2009
  13. 13. Automatic Generation-Based Caching Generation-based Partition the cache so that every state change increments the “generation” Automatic Any action that could possibly change state bumps the count Let memcached overwrite old generations Very conservative No domain knowledge Don’t cache errors, AJAX, redirects, flash notices, etc. OpenLogic Company Confidential 13 Wednesday, July 29, 2009
  14. 14. Overview Non-cached Cached Rails Rails plumbing plumbing Your Cache code helper Render Database memcached View OpenLogic Company Confidential 14 Wednesday, July 29, 2009
  15. 15. Cache = Hash Key Value /packages/1 <html><body>Rails</body></html> /packages/2 <html><body>Ruby</body></html> OpenLogic Company Confidential Wednesday, July 29, 2009
  16. 16. Generational Cache Key Value /gen/1/packages/1 <html>Rails</html> /gen/1/packages/2 <html>Ruby</html> OpenLogic Company Confidential Wednesday, July 29, 2009
  17. 17. Generational Cache Key Value /gen/1/packages/1 <html>Rails</html> /gen/1/packages/2 <html>Ruby</html> /gen/2/packages/1 <html>Ruby on Rails</html> OpenLogic Company Confidential Wednesday, July 29, 2009
  18. 18. memcached is your friend Very fast Don’t worry about removing old entries memcached will automatically drop the oldest keys when it runs low on memory Run it on your web servers if you have the RAM OpenLogic Company Confidential 18 Wednesday, July 29, 2009
  19. 19. Cache Helper No cache-related code sprinkled throughout every model, view, and/or controller Use a global “around” filter Automatically increment (scoped) generation count upon POST, PUT, or DELETE Handle event recording and playback (optional) OpenLogic Company Confidential 19 Wednesday, July 29, 2009
  20. 20. Cache Helper Code (in “around” filter) key = make_auto_cache_key(request.request_uri) output = if output render :text => output return else yield unless response.redirected_to || flash[:notice] Rails.cache.write(key, response.body) end end OpenLogic Company Confidential 20 Wednesday, July 29, 2009
  21. 21. Cache Key def make_auto_cache_key(key) ol_gen = Rails.cache.fetch(OL_GEN) { "1" } "olex/#{ol_gen}" end OpenLogic Company Confidential 21 Wednesday, July 29, 2009
  22. 22. “Clear” the Cache POST, PUT, or DELETE “clears” the cache def maybe_clear_auto_cache return if request.get? gen = Rails.cache.fetch(OL_GEN) { "1" } Rails.cache.write(OL_GEN, (gen.to_i + 1).to_s) end OpenLogic Company Confidential 22 Wednesday, July 29, 2009
  23. 23. Controller Customization Some controllers may need special cache control (e.g., user-specific cache, disable cache for certain methods) olex_auto_cache_is_specific_to_user :only => :show Note: the cache may still need to be cleared when skipping cache usage! skip_filter :olex_auto_cache after_filter :maybe_clear_olex_auto_cache OpenLogic Company Confidential 23 Wednesday, July 29, 2009
  24. 24. Cache Partitioning Make it impossible for users of different corporations and permission levels to see each other’s stuff, access the same cache, clear somebody else’s cache, etc. Make sure any “global” changes clear all caches Use a cache hierarchy /olex/<gen #>/corp/<corp #>/<corp gen #>/roles/<role #s>/URL MD5 the key (memcached has a 250 char limit) Extra credit: Use the key as an etag OpenLogic Company Confidential 24 Wednesday, July 29, 2009
  25. 25. Partitioned Cache Global generation <html> /olex/13/corp/72/2/roles/2,7,19/packages/2 Rails (unsupported) </html> OpenLogic Company Confidential Wednesday, July 29, 2009
  26. 26. Partitioned Cache Corporate account ID <html> /olex/13/corp/72/2/roles/2,7,19/packages/2 Rails (unsupported) </html> OpenLogic Company Confidential Wednesday, July 29, 2009
  27. 27. Partitioned Cache Corporation #72’s generation <html> /olex/13/corp/72/2/roles/2,7,19/packages/2 Rails (unsupported) </html> OpenLogic Company Confidential Wednesday, July 29, 2009
  28. 28. Partitioned Cache Current user’s role IDs <html> /olex/13/corp/72/2/roles/2,7,19/packages/2 Rails (unsupported) </html> OpenLogic Company Confidential Wednesday, July 29, 2009
  29. 29. Partitioned Cache URL <html> /olex/13/corp/72/2/roles/2,7,19/packages/2 Rails (unsupported) </html> OpenLogic Company Confidential Wednesday, July 29, 2009
  30. 30. Partitioned Cache <html> /olex/13/corp/72/2/roles/2,7,19/packages/2 Rails (unsupported) </html> <html> /olex/13/corp/72/2/roles/2,7,19,22/packages/2 Rails (manager secret!) </html> <html> /olex/14/corp/72/2/roles/2,7,19/packages/2 Rails (supported) </html> /olex/14/guest/packages/2 <html>Rails</html> OpenLogic Company Confidential Wednesday, July 29, 2009
  31. 31. Cache Key def make_auto_cache_key(key, user = nil) ol_gen = Rails.cache.fetch(OL_GEN) { "1" } ol_prefix = "olex/#{ol_gen}" if user.nil? && self.respond_to?("current_user") user = current_user end ca = get_corporate_account(user) ... OpenLogic Company Confidential 31 Wednesday, July 29, 2009
  32. 32. Cache Key ... if user.is_corp_user? corp_gen = Rails.cache.fetch(corp_gen_key(ca)){"1"} final_key = make_corp_key(user, ca, key, corp_gen) else final_key = "guest#{key}" end OpenLogic Company Confidential 32 Wednesday, July 29, 2009
  33. 33. Corporate Cache Key def make_corp_key(user, ca, key, corp_gen) roles = role_string(user) "/corp/#{}/#{corp_gen}/roles/#{roles}#{key}" end def role_string(user) Rails.cache.fetch("roles/#{}") do user.role_string end end OpenLogic Company Confidential 33 Wednesday, July 29, 2009
  34. 34. Benefits Never have to explicitly expire anything Can’t get an expired page Generation numbers also stored in memcached Cache hierarchy is like a directory structure Easy to grok Can’t run out of “disk space”! OpenLogic Company Confidential 34 Wednesday, July 29, 2009
  35. 35. Does it really work? In production for over a year - a few minor issues See Gotchas Huge performance improvement for us, almost no developer pain e.g., needed cookie-based “Welcome Joe!” Great for “passive” caching Write caching code once, enjoy it forever Lots of room for more aggressive caching OpenLogic Company Confidential 35 Wednesday, July 29, 2009
  36. 36. Gotchas Easy to forget to make AJAX calls use REST method:'get','post', 'put', or 'delete' Test with and without caching, and test the caching itself! Caching doesn’t help the first hit Mitigate by pre-caching when feasible OpenLogic Company Confidential 36 Wednesday, July 29, 2009
  37. 37. Recommendations The “safety first” caching implementation - use it It’s still action caching, so don’t expect page caching performance Measure the result - not all pages will benefit and there is some overhead OpenLogic Company Confidential 37 Wednesday, July 29, 2009
  38. 38. Bonus Asynchronous pre-caching Event recording and playback OpenLogic Company Confidential 38 Wednesday, July 29, 2009
  39. 39. Async pre-caching pages at logon Use Workling/Starling for async When user logs on, make async call Async call runs through list of URL’s and hits them on behalf of the currently logged on user Need secret back-door logon in application.rb Use big scary session key in environment.rb OpenLogic Company Confidential 39 Wednesday, July 29, 2009
  40. 40. Event Recording Q: What if you want to record the fact that something happened even though the page was automatically cached and served? A: Watch it while being cached, record what happens in memcached, play it back later when serving cached version OpenLogic Company Confidential 40 Wednesday, July 29, 2009
  41. 41. Summary Rails built-in caching takes a lot of on-going work Easy to screw it up Automatic caching can be written once and enjoyed forever Much harder to screw up Still possible to use more aggressive techniques selectively OpenLogic Company Confidential 41 Wednesday, July 29, 2009
  42. 42. Any questions for Rod? OpenLogic Company Confidential 42 Wednesday, July 29, 2009
  43. 43. Resources memcached: Workling: master Starling: OLEX: OpenLogic Company Confidential 43 Wednesday, July 29, 2009
  44. 44. Credits Unless otherwise indicated, photos were licensed from OpenLogic Company Confidential 44 Wednesday, July 29, 2009
  45. 45. OpenLogic is hiring! Rails guru? Live near Denver, Colorado? Love Open Source? Come see me! OpenLogic Company Confidential 45 Wednesday, July 29, 2009