Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Alistair Stead

October 08, 2011
Tweet

More Decks by Alistair Stead

Other Decks in Programming

Transcript

  1. 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
  2. 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
  3. 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
  4. Client Application Client Cache GET / HTTP1.1 Host: mystore.com GET

    / HTTP1.1 Host: mystore.com HTTP1.1 200 OK HTTP1.1 200 OK
  5. 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
  6. 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
  7. 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
  8. 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
  9. EXPIRATION ALLOWS YOU TO SCALE VALIDATION SAVES BANDWIDTH Fewer requests

    hitting your server and client speed is better too!
  10. <?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; } }
  11. <?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>
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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; } }
  17. 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"; } }
  18. 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); }
  19. /** * 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; }
  20. /** * 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() ); }
  21. 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())); } }
  22. 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
  23. 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
  24. NON CACHEABLE TRANSACTIONS Add to cart Purchase 0 7500 15000

    22500 30000 Client Baseline Magento Baseline Magento Compiler Magento + Varnish
  25. 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
  26. MAGNIFY THE LOAD Multiple ESI requests in a page all

    directed at the same application Client Browser Varnish Port 80 Backend Apache Port 8080