Save 37% off PRO during our Black Friday Sale! »

Varnish your application - Make it fly!

Varnish your application - Make it fly!

Apply varnish to a pre-existing application to improve performance and scalability. Delivered at #phpnw11

7ad4c8a7218e44fdf1600b4ebc451738?s=128

Alistair Stead

October 08, 2011
Tweet

Transcript

  1. VARNISH YOUR APPLICATION Make it fly!

  2. WHO AM I • Alistair Stead - @alistairstead • Technical

    Team Lead @ Ibuildings UK • Over 12 years commercial experience developing in PHP and other technologies. • http://joind.in/3591
  3. PERFORMANCE AND SCALABILITY Is a hot topic for clients and

    developers alike.
  4. PERFORMANCE Vs CONVERSION RATE These are directly linked!

  5. PERCEIVED PERFORMANCE Vs PHYSICAL PERFORMANCE Is there an easy route

    to performance?
  6. VARNISH http://www.varnish-cache.org/

  7. PRELIMINARY LOAD TESTS What can Varnish do for us?

  8. +4,000,000 Requests per hour

  9. REVERSE PROXY? Yeah okay... tell me more!

  10. CACHING PROXY? It is...

  11. LOAD BALANCER? It can do that too!

  12. HTTP ACCELERATOR It may just be magic!

  13. WHERE TO APPLY VARNISH Apply thinly over your apache cluster

    Client Browser Varnish Port 80 Backend Apache Port 8080 Backend Apache Port 8080 Client Browser Client Browser
  14. INSTALLATION Packages available for most platforms http://bit.ly/pPB7x5

  15. "WITH GREAT POWER COMES GREAT RESPONSIBILITY"

  16. HOW TO CONTROL CACHING Additional caching layers need to be

    coordinated
  17. RFC 2616 HTTP 1.1 http://bit.ly/pLtSl0 http://bit.ly/oORXf3

  18. HTTP 1.1 $ curl -I magentocommerce.com

  19. HTTP/1.1 200 OK Server: nginx Date: Sun, 05 Jun 2011

    17:40:56 GMT Content-Type: text/html; charset=UTF-8 Connection: keep-alive X-Powered-By: PHP/5.2.17 Set-Cookie: PHPSESSID=j1cdbj2617abbl8ccsbkd2mt44; path=/ Expires: Mon, 26 Jul 1997 05:00:00 GMT Cache-Control: no-store, no-cache, must- revalidate, post-check=0, pre-check=0 Pragma: no-cache Last-Modified: Sun, 05 Jun 2011 17:40:56 GMT $ curl -I magentocommerce.com
  20. HTTP 1.1 HEADERS Request modifiers / Response parameters

  21. CACHEING WITH HTTP 1.1 Has two models Expiration & Validation

  22. EXPIRATION MODEL How long may I use this resource for?

  23. EXPIRATION HEADERS • Cache-Control • Expires

  24. VALIDATION MODEL Is this resource still okay to use?

  25. VALIDATION HEADERS • Last-Modified • If-Modified-Since • ETag • If-None-Match

  26. HTTP CACHE HEADERS Should only work with safe HTTP verbs

    GET & HEAD
  27. HTTP 1.1 REQUEST FLOW

  28. Client Application Client Cache GET / HTTP1.1 Host: mystore.com GET

    / HTTP1.1 Host: mystore.com HTTP1.1 200 OK HTTP1.1 200 OK
  29. Client Application Client Cache GET / HTTP1.1 Host: mystore.com GET

    / HTTP1.1 Host: mystore.com HTTP1.1 200 OK Cache-Control: max- age=20 HTTP1.1 200 OK Cache-Control: max- age=20 HTTP1.1 200 OK Cache-Control: max-age=20
  30. Client Application Client Cache GET / HTTP1.1 Host: mystore.com HTTP1.1

    200 OK Cache-Control: max- age=20 HTTP1.1 200 OK Cache-Control: max-age=20
  31. Client Application Client Cache GET / HTTP1.1 Host: mystore.com GET

    / HTTP1.1 Host: mystore.com HTTP1.1 200 OK Etag: abcde HTTP1.1 200 OK Etag: abcde HTTP1.1 200 OK Etag: abcde
  32. Client Application Client Cache GET / HTTP1.1 Host: mystore.com GET

    / HTTP1.1 Host: mystore.com If-None-Match: abcde HTTP1.1 304 Not Modified HTTP1.1 304 Not Modified HTTP1.1 200 OK Etag: abcde
  33. EXPIRATION ALLOWS YOU TO SCALE VALIDATION SAVES BANDWIDTH Fewer requests

    hitting your server and client speed is better too!
  34. OUR GOAL IS TO NEVER GENERATE THE SAME RESPONSE TWICE

  35. LEVERAGE HTTP CACHE IN MAGENTO With an event observer this

    is simple.
  36. <?php class Disclosure_Varnish_Model_Observer extends Disclosure_Varnish_Model_Observer_Abstract { /** * Update the

    headers transmitted to allow greater varnish cache hits * * @param $observer */ public function processPreDispatch(Varien_Event_Observer $observer) { if (!$this->isVarnishEnabled()) { return $this; } $routeTtls = $this->_config->getRouteTtls(); $routeName = Mage::app()->getRequest()->getRequestedRouteName(); if (isset($routeTtls[$routeName])) { $observer->getResponse()->setHeader('Cache-Control', $routeTtls[$routeName] ['cache_control'], false); } return $this; } }
  37. <?xml version="1.0" encoding="UTF-8"?> <config> <ttls> <routes> <cms> <name>cms</name> <cache_control>public, max-age=3600</cache_control>

    </cms> <catalog> <name>catalog</name> <cache_control>public, must-revalidate, max-age=0</cache_cont <actions> <index> <cache_control>private, max-age=0</cache_control> </index> </actions> </catalog> </routes> </ttls>
  38. VARNISH RESPECTS CACHE CONTROL Dispatch the headers that fit your

    application
  39. Client Application Client Cache Reverse Proxy Cache GET / HTTP1.1

    Host: mystore.com GET / HTTP1.1 Host: mystore.com HTTP1.1 200 OK Cache-Control: max- age=20 HTTP1.1 200 OK Cache-Control: max- age=20 HTTP1.1 200 OK Cache-Control: max-age=20
  40. Client Application Client Cache Reverse Proxy Cache GET / HTTP1.1

    Host: mystore.com HTTP1.1 200 OK Cache-Control: max- age=20 HTTP1.1 200 OK Cache-Control: max-age=20
  41. Client Application Client Cache Reverse Proxy Cache GET / HTTP1.1

    Host: mystore.com GET / HTTP1.1 Host: mystore.com HTTP1.1 200 OK Cache-Control: max- age=20 HTTP1.1 200 OK Cache-Control: max- age=20 HTTP1.1 200 OK Cache-Control: max-age=20 Client Client Cache GET / HTTP1.1 Host: mystore.com HTTP1.1 200 OK Cache-Control: max- age=20
  42. Client Application Client Cache Reverse Proxy Cache Client Client Cache

    Gateway Cache Network Proxy Cache max-age s-maxage max-age s-maxage max-age s-maxage max-age max-age
  43. VARNISH IS CONFIGURED USING VCL Send the correct headers you

    should not need to do much.
  44. backend www1 { .host = "192.168.100.2"; .port = "8080"; }

    backend www2 { .host = "192.168.100.3"; .port = "8080"; } ........ director backend_director random { .retries = 5; { .backend = www1; .weight = 1; } { .backend = www2; .weight = 1; } { .backend = www3; .weight = 1; } { .backend = www4; .weight = 1; } { .backend = www5; .weight = 1; } { .backend = www6; .weight = 1; } { .backend = www7; .weight = 1; } }
  45. sub vcl_deliver { # Set a cache header to allow

    us to inspect the response # headers during testing if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; set resp.http.X-Cache-Hits = obj.hits; } else { set resp.http.X-Cache = "MISS"; } }
  46. EDGE SIDE INCLUDES http://bit.ly/nITuFP

  47. sub vcl_recv { set req.http.Surrogate-Capability = "magento=ESI/1.0"; return (lookup); }

    sub vcl_fetch { if (beresp.http.Surrogate-Control ~ "ESI/1.0") { # unset beresp.http.Surrogate-Control; esi; } return (deliver); }
  48. max-age=3600 max-age=86400

  49. max-age=3600 max-age=86400

  50. ESI TAGS <esi:include src="/varnish/esi?attributes=%s"/>

  51. /** * Render ESI tags for the block if needed

    * * @param Varien_Event_Observer $observer */ public function renderBlockEsiTag(Varien_Event_Observer $observer) { if (!$this->isEsiEnabled() || !$this->isVarnishEnabled()) { return $this; } $block = $observer->getEvent()->getBlock(); $transport = $observer->getEvent()->getTransport(); $tag = Mage::getModel('varnish/esi_tag_factory')- >create($block); if ($transport && $tag) { $transport->setHtml($tag->getHtml()); } return $this; }
  52. /** * Render the html for the ESI tag *

    * @return string * @author Alistair Stead **/ public function getHtml() { return sprintf( '<esi:include src="/varnish/esi?attributes=%s"/>', $this->getAttributeHash() ); }
  53. class Disclosure_Varnish_EsiController extends Mage_Core_Controller_Front_Action { public function indexAction() { $attributes

    = unserialize(base64_decode($this->getRequest()- >getParam('attributes'))); $context = Mage::getModel('varnish/esi_context'); $context->setData($attributes); $processor = Mage::getModel('varnish/esi_processor', $context); // Initialize the layout $this->loadLayout(); Mage::dispatchEvent('varnish_controller_esi_appendbody_before', array("response" => $this->getResponse())); $this->getResponse()->appendBody($processor->render()); Mage::dispatchEvent('varnish_controller_esi_appendbody_after', array("response" => $this->getResponse())); } }
  54. FINAL PERFORMANCE RESULTS How much traffic did these modifications let

    us serve
  55. TRAFFIC SAMPLE • Product Details page: 58k views per hour

    • Homepage: 50k requests per hour • Main Search : 70k requests per hour • Refined Search (via facets): 20k requests per hour • Add to Basket: 11k requests per hour • Login: 11k requests per hour • Category Pages: 46k requests per hour • Checkout: 6k requests per hour
  56. Homepage Category Listings Product Detail Add to cart Login Search

    Purchase 0 375000 750000 1125000 1500000 Client Baseline Magento Baseline Magento Compiler Magento + Varnish FINAL PERFORMANCE RESULTS
  57. NON CACHEABLE TRANSACTIONS Add to cart Purchase 0 7500 15000

    22500 30000 Client Baseline Magento Baseline Magento Compiler Magento + Varnish
  58. None
  59. THE TARGET ~ 300K REQUEST We achieved almost 14 x

    that with little effort.
  60. IS VARNISH THE BEST SOLUTION? What do we need to

    consider?
  61. VARNISH LIMITATIONS • Prior to V3 ESI not supported with

    GZIP • Cookies need to be managed carefully • Still need SSL endpoint • Beware cache stampede • ESI must have a TTL greater than the parent page • Only implements a subset of ESI • Shared cache consider using s-maxage with max-age
  62. STALE WHILE Maintain a compromised UI while resolving content

  63. ALTERNATE WHILE Provide alternate content will content is being resolved

  64. ESI ANTI PATTERNS

  65. MAGNIFY THE LOAD Multiple ESI requests in a page all

    directed at the same application Client Browser Varnish Port 80 Backend Apache Port 8080
  66. CACHE BUSTING Static assets that out stay their welcome

  67. REFERENCES http://bitly.com/pw3HXm

  68. IMAGE CREDITS http://www.flickr.com/photos/bondgirly/4520060395/sizes/o/in/ photostream/

  69. THANK YOU! • Email: astead@ibuildings.com • Skype: astead-ibuildings • Twitter:

    @alistairstead
  70. QUESTIONS? http://joind.in/3591

  71. WE ARE HIRING! http://www.ibuildings.co.uk/about/careers/