Your SlideShare is downloading. ×
0
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Page Caching Resurrected
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Page Caching Resurrected

1,531

Published on

This is the revised version of my Page Caching Resurrected presentation, as given to CVREG in April 2009.

This is the revised version of my Page Caching Resurrected presentation, as given to CVREG in April 2009.

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

No Downloads
Views
Total Views
1,531
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
41
Comments
0
Likes
6
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide





  • super simple to use, but results in PUBLIC content
  • super simple to use, but results in PUBLIC content




  • more framework-specific; solves auth-protected pages, etc. - cached content is not publicly available
  • 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






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

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



  • 66ms for hybrid v2, 10.6% of standard and 48% of hybrid
  • 34 minutes









  • Transcript

    1. Page Caching Resurrected Ben Sco eld – Viget Labs
    2. Page Caching Resurrected: A Fairy Tale Ben Sco eld – Viget Labs
    3. three little pigs
    4. three little pigs
    5. page caching
    6. 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
    7. 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
    8. 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
    9. standard 1 page 3000 requests per second
    10. public dynamic content
    11. action caching
    12. 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
    13. 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
    14. 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
    15. standard 1 action 500 page 3000 requests per second
    16. dynamic content
    17. fragment caching
    18. <% 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 %>
    19. <% 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 %>
    20. class PigsController # ... def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_fragment :key => 'index:piglist' end end
    21. class PigsController # ... def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_fragment :key => 'index:piglist' end end
    22. standard 1 fragment 20 action 500 page 3000 requests per second
    23. eficiency
    24. the idea
    25. Rails 2.3
    26. hello, metal
    27. 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
    28. high-performance endpoints
    29. AJAX
    30. so...
    31. javascript
    32. 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
    33. 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
    34. 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
    35. noscript ul class=quot;nojs usernavquot; li Please a href=quot;/support/quot;enable javascript/a to log in. /li /ul /noscript
    36. 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
    37. 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
    38. 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
    39. hulu is insane don’t do it like they do
    40. 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
    41. 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
    42. the* right way *a
    43. the standard approach
    44. class ItemsController ApplicationController def index @user = User.find_by_login(params[:user]) @items = Item.released_on(params[:date]) end end
    45. 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
    46. h1Releases/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
    47. the hybrid approach
    48. class ItemsController ApplicationController caches_page :index def index @items = Item.released_on(params[:date]).all end end
    49. 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
    50. 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
    51. $(document).ready(function() { $.getJSON('/pulls', function(data) { $.each(data, function() { $('#item_'+this).addClass('pulled'); }); }); });
    52. standard
    53. hybrid
    54. standard 0.617 hybrid 0.039 0.096 content load time
    55. hybrid approach - version 2
    56. class SessionsController ApplicationController def new; end def create # ... session[:pulls] = @user.pulls.map {|i| i.item_id} redirect_to items_path end end
    57. 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;}, [env['rack.session'][:pulls].to_json] ] else [404, {quot;Content-Typequot; = quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end
    58. hybrid v2
    59. standard 0.617 hybrid 0.039 0.096 hybrid v2 0.043 0.023 content load time
    60. when to use it
    61. when not to use it
    62. accessibility
    63. accessibility
    64. noscript ul class=quot;nojs usernavquot; li Please a href=quot;/support/quot;enable javascript/a to log in. /li /ul /noscript
    65. Thank You ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/bsco eld

    ×