Page Caching Resurrected:

                   Ben Sco eld – Viget Labs




Sunday, March 22, 2009
Page Caching Resurrected:
                   A Fairy Tale
                   Ben Sco eld – Viget Labs




Sunday, March 22...
I’m a Rails guy


Sunday, March 22, 2009
and this is a Rails talk


Sunday, March 22, 2009
but this isn’t just for Rails


Sunday, March 22, 2009
the story


Sunday, March 22, 2009
Sunday, March 22, 2009
page caching



Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
class PigsController
                 caches_page :show

                   def show
                    @pig = Pig.find(pa...
Standard        1




                Page     3000




                                requests per second




Sunday, Ma...
public

                         dynamic
                         content

Sunday, March 22, 2009
action caching


Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
class PigsController
                 require_login :show
                 caches_action :show

                   def sho...
Standard        1



              Action     500



                Page     3000




                                req...
dynamic
                         content


Sunday, March 22, 2009
fragment caching

Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
<% cache(:key => 'index:piglist') do %>
                 <ul id=quot;pig-listquot;>
                  <% @pigs.each do |pi...
class PigsController
                 # ...

                   def update
                    @pig = Pig.find(params[:id])...
Standard        1


         Fragment        20


              Action     500


                Page     3000




       ...
efficiency


Sunday, March 22, 2009
the idea


Sunday, March 22, 2009
Rails 2.3

Sunday, March 22, 2009
hello, metal


Sunday, March 22, 2009
class BigBadWolf
                 def self.call(env)
                   if env[quot;PATH_INFOquot;] =~ /^/threaten/
      ...
high-performance endpoints


Sunday, March 22, 2009
AJAX


Sunday, March 22, 2009
so...


Sunday, March 22, 2009
javascript

Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
<script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/
     Event.observe(window, quot;loadquot;, fu...
<ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;>
     <li id=quot;welcome-usernamequot...
<noscript>
     <ul class=quot;nojs usernavquot;>
      <li>
       Please <a href=quot;/support/quot;>enable javascript</...
<ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;>
     <li id=quot;welcome-usernamequot...
Sunday, March 22, 2009
hulu is insane
                          don’t do it like they do




Sunday, March 22, 2009
<script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/
     Event.observe(window, quot;loadquot;, fu...
<script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/
     Event.observe(window, quot;loadquot;, fu...
the* right way


                               *a
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
the standard approach




Sunday, March 22, 2009
class ItemsController < ApplicationController
      def index
        @user = User.find_by_login(params[:user])
        @it...
class Item < ActiveRecord::Base
      has_many :pulls, :dependent => :destroy

       named_scope :released_on, lambda { |...
<h1>Releases</h1>

     <ul>
      <% @items.each do |item| %>
       <% content_tag_for :li, item do %>
        <%= image...
the hybrid approach




Sunday, March 22, 2009
class ItemsController < ApplicationController
      caches_page :index

      def index
       @items = Item.released_on(p...
require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless
      defined?(Rails)

     class PullList
    ...
class Pull < ActiveRecord::Base
      belongs_to :user
      belongs_to :item

      named_scope :by_user, lambda { |user_...
$(document).ready(function() {
       $.getJSON('/pulls', function(data) {
         $.each(data, function() {
           $...
the payoff


Sunday, March 22, 2009
Sunday, March 22, 2009
standard


Sunday, March 22, 2009
hybrid


Sunday, March 22, 2009
Standard        0.617




              Hybrid     0.039 0.096




                                       content load tim...
when to use it




Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
no shirt, no javascript, no service




Sunday, March 22, 2009
Thank You
      ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/speakers/44
Sunday, Mar...
Upcoming SlideShare
Loading in …5
×

Page Caching Resurrected: A Fairy Tale

1,018 views

Published on

Presentation given at the first Developer Day, in Durham NC on March 21st, 2009

Published in: Technology, News & Politics
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

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

No notes for slide




  • 3 minutes



  • super simple to use, but results in PUBLIC content




  • more framework-specific; solves auth-protected pages, etc. - cached content is not publicly available





  • caches only specific parts of the page, which are not publically available
  • expiration of each fragment, individually


  • 10 minutes








  • 15 minutes










  • 22 minutes






  • 26 minutes




  • 32 minutes



  • 135ms for hybrid, which is 21% of the standard

    lame tests I employed showed the same or greater effect
  • 34 minutes





  • Page Caching Resurrected: A Fairy Tale

    1. 1. Page Caching Resurrected: Ben Sco eld – Viget Labs Sunday, March 22, 2009
    2. 2. Page Caching Resurrected: A Fairy Tale Ben Sco eld – Viget Labs Sunday, March 22, 2009
    3. 3. I’m a Rails guy Sunday, March 22, 2009
    4. 4. and this is a Rails talk Sunday, March 22, 2009
    5. 5. but this isn’t just for Rails Sunday, March 22, 2009
    6. 6. the story Sunday, March 22, 2009
    7. 7. Sunday, March 22, 2009
    8. 8. page caching Sunday, March 22, 2009
    9. 9. Sunday, March 22, 2009
    10. 10. Sunday, March 22, 2009
    11. 11. class PigsController caches_page :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_page :action => :show end end Sunday, March 22, 2009
    12. 12. Standard 1 Page 3000 requests per second Sunday, March 22, 2009
    13. 13. public dynamic content Sunday, March 22, 2009
    14. 14. action caching Sunday, March 22, 2009
    15. 15. Sunday, March 22, 2009
    16. 16. Sunday, March 22, 2009
    17. 17. class PigsController require_login :show caches_action :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_action :action => :show end end Sunday, March 22, 2009
    18. 18. Standard 1 Action 500 Page 3000 requests per second Sunday, March 22, 2009
    19. 19. dynamic content Sunday, March 22, 2009
    20. 20. fragment caching Sunday, March 22, 2009
    21. 21. Sunday, March 22, 2009
    22. 22. Sunday, March 22, 2009
    23. 23. Sunday, March 22, 2009
    24. 24. Sunday, March 22, 2009
    25. 25. <% cache(:key => 'index:piglist') do %> <ul id=quot;pig-listquot;> <% @pigs.each do |pig| %> <li> <%= image_tag pig.house.photo %> <%= h pig.name %> </li> <% end %> </ul> <% end %> Sunday, March 22, 2009
    26. 26. class PigsController # ... def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_fragment :key => 'index:piglist' end end Sunday, March 22, 2009
    27. 27. Standard 1 Fragment 20 Action 500 Page 3000 requests per second Sunday, March 22, 2009
    28. 28. efficiency Sunday, March 22, 2009
    29. 29. the idea Sunday, March 22, 2009
    30. 30. Rails 2.3 Sunday, March 22, 2009
    31. 31. hello, metal Sunday, March 22, 2009
    32. 32. class BigBadWolf def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/threaten/ [ 200, {quot;Content-Typequot; => quot;text/htmlquot;}, quot;Little pig, little pig, let me in!quot; ] else [ 404, {quot;Content-Typequot; => quot;text/htmlquot;}, quot;Not Foundquot; ] end end end Sunday, March 22, 2009
    33. 33. high-performance endpoints Sunday, March 22, 2009
    34. 34. AJAX Sunday, March 22, 2009
    35. 35. so... Sunday, March 22, 2009
    36. 36. javascript Sunday, March 22, 2009
    37. 37. Sunday, March 22, 2009
    38. 38. Sunday, March 22, 2009
    39. 39. Sunday, March 22, 2009
    40. 40. Sunday, March 22, 2009
    41. 41. Sunday, March 22, 2009
    42. 42. Sunday, March 22, 2009
    43. 43. Sunday, March 22, 2009
    44. 44. <script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) && $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]>*/</script> Sunday, March 22, 2009
    45. 45. <ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;> <li id=quot;welcome-usernamequot; class=quot;firstquot;> Welcome </li> <li> <a href=quot;/profilequot; class=quot;utility-linkquot;>Profile</a> </li> <li> <a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;>Queue</a> </li> <li class=quot;sign-out-linkquot;> <a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;>Sign Out</a> </li> </ul> <ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot;> <li class=quot;first sign-out-linkquot;> <a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot; onclick=quot;Login.show($('top-login-form')); return false;quot;>Login</a> </li> <li class=quot;signin-border-leftquot;> <a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;>Forgot Password?</a> </li> <li class=quot;signin-border-leftquot;> <a href=quot;/signupquot; class=quot;utility-linkquot;>Sign Up</a> </li> </ul> Sunday, March 22, 2009
    46. 46. <noscript> <ul class=quot;nojs usernavquot;> <li> Please <a href=quot;/support/quot;>enable javascript</a> to log in. </li> </ul> </noscript> <div id=quot;top-login-formquot; class=quot;usernav login-formquot; style=quot;display:nonequot;> <form action=quot;https://secure.hulu.com/account/authenticatequot; method=quot;getquot; name=quot;login-formquot; onsubmit=quot;Login.submit(this); return false;quot;> <span class=quot;login-statusquot;></span> <input id=quot;loginquot; class=quot;active loginquot; type=quot;textquot; style=quot;display: none;quot; name=quot;usernamequot;/> <input id=quot;passwordquot; class=quot;active passwordquot; type=quot;passwordquot; style=quot;display: none;quot; name=quot;passwordquot;/> <input class=quot;inactive dummy loginquot; type=quot;textquot; value=quot;usernamequot; name=quot;dummy_loginquot; /> <input class=quot;inactive dummyquot; type=quot;textquot; value=quot;passwordquot; name=quot;dummy_passwordquot; /> <input alt=quot;Loginquot; class=quot;login-submitquot; src=quot;http://static.hulu.com/images/btn-signin-small.gif?1237361096quot; style=quot;width: 39px; height: 20;quot; type=quot;imagequot; /> <a href=quot;#quot;><img alt=quot;Cancelquot; border=quot;0quot; class=quot;hover-mequot; height=quot;20quot; id=quot;btn-x.gif123741536309506quot; onclick=quot;Login.cancel();return falsequot; src=quot;http://static.hulu.com/images/btn-x.gif?1237361096quot; width=quot;18quot; /></a> </form> <a href=quot;/signupquot; class=quot;utility-linkquot;>Sign Up</a> </div> Sunday, March 22, 2009
    47. 47. <ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;> <li id=quot;welcome-usernamequot; class=quot;firstquot;> Welcome </li> <li> <a href=quot;/profilequot; class=quot;utility-linkquot;>Profile</a> </li> <li> <a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;>Queue</a> </li> <li class=quot;sign-out-linkquot;> <a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;>Sign Out</a> </li> </ul> <ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot;> <li class=quot;first sign-out-linkquot;> <a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot; onclick=quot;Login.show($('top-login-form')); return false;quot;>Login</a> </li> <li class=quot;signin-border-leftquot;> <a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;>Forgot Password?</a> </li> <li class=quot;signin-border-leftquot;> <a href=quot;/signupquot; class=quot;utility-linkquot;>Sign Up</a> </li> </ul> Sunday, March 22, 2009
    48. 48. Sunday, March 22, 2009
    49. 49. hulu is insane don’t do it like they do Sunday, March 22, 2009
    50. 50. <script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) && $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]>*/</script> Sunday, March 22, 2009
    51. 51. <script type=quot;text/javascriptquot; charset=quot;utf-8quot;>/*<![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) && $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]>*/</script> Sunday, March 22, 2009
    52. 52. the* right way *a Sunday, March 22, 2009
    53. 53. Sunday, March 22, 2009
    54. 54. Sunday, March 22, 2009
    55. 55. the standard approach Sunday, March 22, 2009
    56. 56. class ItemsController < ApplicationController def index @user = User.find_by_login(params[:user]) @items = Item.released_on(params[:date]) end end Sunday, March 22, 2009
    57. 57. class Item < ActiveRecord::Base has_many :pulls, :dependent => :destroy named_scope :released_on, lambda { |date| date ||= Item.maximum(:released_on) {:conditions => {:released_on => date}, :order => 'name ASC'} } def pulled_by?(user) x = user.nil? ? false : !self.pulls.by_user(user.id).empty? end end Sunday, March 22, 2009
    58. 58. <h1>Releases</h1> <ul> <% @items.each do |item| %> <% content_tag_for :li, item do %> <%= image_tag 'cover.png', :alt => h(item.name), :class => 'cover' %> <%= image_tag('badge.png', :alt => 'pulling',:class => 'badge') if item.pulled_by?(@user) %> <p><%= h item.name %></p> <% end %> <% end %> </ul> Sunday, March 22, 2009
    59. 59. the hybrid approach Sunday, March 22, 2009
    60. 60. class ItemsController < ApplicationController caches_page :index def index @items = Item.released_on(params[:date]).all end end Sunday, March 22, 2009
    61. 61. require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless defined?(Rails) class PullList def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/pulls/ date = '2008-11-05' user = '1' [ 200, {quot;Content-Typequot; => quot;application/javascriptquot;}, [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]] else [404, {quot;Content-Typequot; => quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end Sunday, March 22, 2009
    62. 62. class Pull < ActiveRecord::Base belongs_to :user belongs_to :item named_scope :by_user, lambda { |user_id| {:conditions => {:user_id => user_id}} } named_scope :for_date, lambda { |date| {:include => :item, :conditions => {:items => {:released_on => date}}} } end Sunday, March 22, 2009
    63. 63. $(document).ready(function() { $.getJSON('/pulls', function(data) { $.each(data, function() { $('#item_'+this).addClass('pulled'); }); }); }); Sunday, March 22, 2009
    64. 64. the payoff Sunday, March 22, 2009
    65. 65. Sunday, March 22, 2009
    66. 66. standard Sunday, March 22, 2009
    67. 67. hybrid Sunday, March 22, 2009
    68. 68. Standard 0.617 Hybrid 0.039 0.096 content load time Sunday, March 22, 2009
    69. 69. when to use it Sunday, March 22, 2009
    70. 70. Sunday, March 22, 2009
    71. 71. Sunday, March 22, 2009
    72. 72. Sunday, March 22, 2009
    73. 73. Sunday, March 22, 2009
    74. 74. Sunday, March 22, 2009
    75. 75. Sunday, March 22, 2009
    76. 76. no shirt, no javascript, no service Sunday, March 22, 2009
    77. 77. Thank You ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/speakers/44 Sunday, March 22, 2009

    ×