Performance durch Caching

Fabrizio Branca
System Developer bei AOE media



Mail:      mail (at) fabrizio (minus) branca (dot) de
Twitter:   @fbrnc
Blog:      http://www.fabrizio-branca.de
Agenda


                          Reverse Proxy
  Ein-    Probleme und
                            Caching
führung   Optimierungen
                           mit Varnish
Agenda


                          Reverse Proxy
  Ein-    Probleme und
                            Caching
führung   Optimierungen
                           mit Varnish
Funktionsweise Cache

                 Mage::app()->getCacheInstance()
                 Mage_Core_Model_Cache


                 Mage::app()->getCache() oder
                 Mage::app()->getCacheInstance()->getFrontend()
                 Varien_Cache_Core




… extends
Zend_Cache_Backend
Two-Level Cache
        Mehr Details:
        http://www.fabrizio-branca.de/magento-caching-internals.html
Agenda


                          Reverse Proxy
  Ein-    Probleme und
                            Caching
führung   Optimierungen
                           mit Varnish
Alte Cache-Einträge entfernen




• Problem: Abgelaufene Cache-Einträge werden
  nicht gelöscht und sammeln sich an.
• Je größer der Cache, desto langsamer der
  Zugriff
Alte Cache-Einträge entfernen
• Lösung: Regelmäßig Cache aufräumen
 Mage::app()->getCache()->clean(Zend_Cache::CLEANING_MODE_OLD);

• Modul: Aoe_CacheCleaner
 http://www.fabrizio-branca.de/magento-automatic-cache-
 cleaner.html
• Github:
 https://github.com/fbrnc/Aoe_CacheCleaner
Alte Cache-Einträge entfernen
Alte Cache-Einträge entfernen
Probleme im Database Cache Backend:
• Fehlerhaftes SQL
  – Einige „?“ fehlen
• Tags werden nicht gelöscht
  – In 0.8.22 wurde ein Foreign-Key eingefügt, der die
    Tags „on delete“ löscht. In 0.8.27 wurde der Key
    wieder entfernt.
• Patch:
 https://gist.github.com/971318
Problem: Tag-Basiertes Löschen
• Wird innerhalb Magento sehr oft verwendet
• Wird vom APC Backend nicht unterstützt
• Kann extrem lange dauern, wenn das File
  Backend verwendet wird.
  – Lösung: Cache-Commands abfangen, in eine
    Queue schreiben und asynchron abarbeiten.
  – Beschleunigt außerdem auch den Import-
    Vorgang
  – http://www.fabrizio-branca.de/magento-
    asynchronous-cache.html
  – https://github.com/fbrnc/Aoe_AsyncCache
Bug: 1st-Level Cache Priorität
Bug: 1st-Level Cache Priorität
Bug: 1st-Level Cache Priorität
                                                            $priority = 10
class Varien_Cache_Core extends Zend_Cache_Core {
    […]
    public function save($data, $id = null, $tags = array(),
    $specificLifetime = false, $priority = 8) {
        $tags = $this->_tags($tags);
        return parent::save($data, $id, $tags, $specificLifetime, $priority);
    }
    […]
}



class Zend_Cache_Backend_TwoLevels […] {

    private function _getFastLifetime($lifetime, $priority, $maxLifetime = null) {
        […]
        $fastLifetime = (int) ($lifetime / (11 - $priority));
        […]
        return $fastLifetime;
    }

}
Bug: 1st-Level Cache Priorität




• Patch:
 https://gist.github.com/971320
Weitere Probleme
• Fast cache wird immer neu geschrieben
  auto_refresh_fast_cache = true
  => auto_refresh_fast_cache = false
• Kann inzwischen konfiguriert werden (default: false)


• Verzeichnistiefe des File Cache
  hashed_directory_level = 1
  => hashed_directory_level = 3


• APC-Parameter (Größe, apc.stat, apc.ttl)
  http://www.fabrizio-branca.de/wenn-der-apc-cache-
  volllaeuft.html
Agenda


                          Reverse Proxy
  Ein-    Probleme und
                            Caching
führung   Optimierungen
                           mit Varnish
Reverse proxy caching




              Request

Browser                  Magento
                         (Apache + PHP + Mysql)
              Response
Reverse proxy caching




Browser      Varnish    Magento
                        (Apache + PHP + Mysql)
Reverse proxy caching




Browser        Nginx              Varnish   Magento
                                            (Apache + PHP + Mysql)



          -Verschlüsselung /
          Entschlüsselung (SSL)
          -Kompression
Reverse proxy caching




Browser   Nginx   Varnish   Magento
                            (Apache + PHP + Mysql)
Varnish


   HTTP         Caching         Load     Failover
Accelerator   Reverse Proxy   Balancer   system




       „Varnish makes websites fly“
Varnish
• Entwickelt von Poul-Henning Kamp
• Varnish Configuration Language (VCL)
  – DSL, wird intern in C Code übersetzt und
    dann compiliert
• Varnish überlässt die Thread- und
  Speicherverwaltung dem Betriebssystem
• Weitere Tools: varnishtop, varnishlog,…
• Online-Dokumentation:
  http://www.varnish-cache.org/docs/2.1/
Installation
• In Ubuntu:
sudo apt-get install varnish
sudo vi /etc/default/varnish
START=yes
sudo /etc/init.d varnish start
• Wird in Zukunft automatisch gestartet
• Läuft per default auf Port 6081
• Verwendet per default 127.0.0.1:8080 als
  Backend
• /etc/varnish/default.vcl
Request Lifecycle (vereinfacht)




                Kompletter Workflow: http://www.varnish-cache.org/trac/wiki/VCLExampleDefault
Cachebare Seiten
•   cms_index_index (Startseite)
•   cms_page_view (CMS Seiten)
•   catalog_product_view (Produkt-Singleviews)
•   catalog_category_view (Produkt-Listen)
(Muss ggf. an die Anforderungen und Besonderheiten des Shops angepasst
   werden)



                                                aller Page-Requests
                                                (geschätzt)
Dynamische
(benutzerspezifische)
      Inhalte
Platzhalter für dynamische Teile
<layout>
   <default>
      <reference name="right">

         <block type="core/text" name="ph_cart" before="-">
            <action method="setText"><param><![CDATA[
               <div id="cart_sidebar" class="placeholder"
               rel="cart_sidebar">Placeholder Cart</div>
            ]]></param></action>
         </block>

         <action method="unsetChild"><param>cart_sidebar</param></action>

      </reference>
   </default>
</layout>
Modul „Aoe_Static“
• Sendet HTTP Header um Varnish zu
  steuern.
• Bindet JavaScript ein, das die
  dynamischen Inhalte holt und die
  Platzhalter ersetzt.
• Controller, der die dynamischen Inhalte
  ausliefert.
• https://github.com/fbrnc/Aoe_Static
• https://github.com/fbrnc/Aoe_StaticDemo
Ablauf cachebare Seiten
 Browser                                    Varnish                                     Magento

           Seite anfordern (HTTP Request)
                                                               Seite anfordern


                                                       Statische Seite wird ausgeliefert.
                   Statische Seite wird                Platzhalter für dynamische Teile.
                       ausgeliefert                          Cache-Control Header
      Seite wird
      gerendert
                            Ajax Request fordert dynamische Inhalte an
                           und übermittelt gerade angesehenes Produkt



                                JSON Response mit dynamischen Inhalten

      Platzhalter werden ersetzt
      Session Cookie wird geschrieben
Ablauf nicht-cachebare Seiten
 Browser                                    Varnish                     Magento

           Seite anfordern (HTTP Request)
                                                      Seite anfordern




               Seite wird ausgeliefert

      Seite wird
      gerendert
VCL
sub vcl_recv {
    if (req.http.x-forwarded-for) {
        set req.http.X-Forwarded-For =
        req.http.X-Forwarded-For ", " client.ip;
    } else {
        set req.http.X-Forwarded-For = client.ip;
    }
    if (req.request != "GET" && req.request != "HEAD" && req.request != "PUT"
        && req.request != "POST" && req.request != "TRACE"
        && req.request != "OPTIONS" && req.request != "DELETE") {
        /* Non-RFC2616 or CONNECT which is weird. */
        return (pipe);
    }
    if (req.request != "GET" && req.request != "HEAD") {
        /* We only deal with GET and HEAD by default */
        return (pass);
    }
    if (req.http.Authorization || req.http.Cookie) {
        /* Not cacheable by default */
        return (pass);
    }
    return (lookup);
}
VCL

sub vcl_hash {
    set req.hash += req.url;
    if (req.http.host) {
        set req.hash += req.http.host;
    } else {
        set req.hash += server.ip;
    }
    return (hash);
}
VCL
sub vcl_fetch {
    if (beresp.status == 302 || beresp.status == 301 || beresp.status == 418) {
        return (pass);
    }

    if (beresp.http.aoestatic == "cache") {
        remove beresp.http.Set-Cookie;
        remove beresp.http.X-Cache;
        remove beresp.http.Server;
        remove beresp.http.Age;
        set beresp.grace = 2m;
        set beresp.http.X_AOESTATIC_FETCH = "Removed cookie in vcl_fetch";
    }

    if (!beresp.cacheable) {
        return (pass);
    }

    return (deliver);
}
VCL


sub vcl_deliver {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.Server = "Varnish (HIT)";
    } else {
        set resp.http.X-Cache = "MISS";
        set resp.http.Server = "Varnish (MISS)";
    }
}
Demo
Benchmarks                                  416,67
                                           Seiten/Sekunde




          0,85                2,4
                          Seiten/Sekunde
       Seiten/Sekunde


        Magento          Magento mit        Magento
       ohne Cache       APC+File Cache     mit Varnish
Erweitert
• Anstatt AJAX:
  Edge Side Includes „ESI“ (W3C)
 <esi:include src="phone/call/getBlock/id/cart_sidebar" />
  – Nachteil: langsamer, aufwendiger

• Caching dynamischer Inhalte unter
  Berücksichtigung der Session-Id
  – Nachteil: weniger Cache Hits

• „Purge“ um geänderte Inhalte zu
  aktualisieren
Weitere Informationen
• Varnish (inkl. Dokumentation)
  http://www.varnish-cache.org
• Poul-Henning Kamp über Varnish
  http://vimeo.com/16676188

• http://www.fabrizio-branca.de
• https://github.com/fbrnc
Fragen?



Mail:      mail (at) fabrizio (minus) branca (dot) de
Twitter:   @fbrnc
Blog:      http://www.fabrizio-branca.de

Performance durch Caching

  • 1.
    Performance durch Caching FabrizioBranca System Developer bei AOE media Mail: mail (at) fabrizio (minus) branca (dot) de Twitter: @fbrnc Blog: http://www.fabrizio-branca.de
  • 2.
    Agenda Reverse Proxy Ein- Probleme und Caching führung Optimierungen mit Varnish
  • 3.
    Agenda Reverse Proxy Ein- Probleme und Caching führung Optimierungen mit Varnish
  • 4.
    Funktionsweise Cache Mage::app()->getCacheInstance() Mage_Core_Model_Cache Mage::app()->getCache() oder Mage::app()->getCacheInstance()->getFrontend() Varien_Cache_Core … extends Zend_Cache_Backend
  • 5.
    Two-Level Cache Mehr Details: http://www.fabrizio-branca.de/magento-caching-internals.html
  • 6.
    Agenda Reverse Proxy Ein- Probleme und Caching führung Optimierungen mit Varnish
  • 7.
    Alte Cache-Einträge entfernen •Problem: Abgelaufene Cache-Einträge werden nicht gelöscht und sammeln sich an. • Je größer der Cache, desto langsamer der Zugriff
  • 8.
    Alte Cache-Einträge entfernen •Lösung: Regelmäßig Cache aufräumen Mage::app()->getCache()->clean(Zend_Cache::CLEANING_MODE_OLD); • Modul: Aoe_CacheCleaner http://www.fabrizio-branca.de/magento-automatic-cache- cleaner.html • Github: https://github.com/fbrnc/Aoe_CacheCleaner
  • 9.
  • 10.
    Alte Cache-Einträge entfernen Problemeim Database Cache Backend: • Fehlerhaftes SQL – Einige „?“ fehlen • Tags werden nicht gelöscht – In 0.8.22 wurde ein Foreign-Key eingefügt, der die Tags „on delete“ löscht. In 0.8.27 wurde der Key wieder entfernt. • Patch: https://gist.github.com/971318
  • 11.
    Problem: Tag-Basiertes Löschen •Wird innerhalb Magento sehr oft verwendet • Wird vom APC Backend nicht unterstützt • Kann extrem lange dauern, wenn das File Backend verwendet wird. – Lösung: Cache-Commands abfangen, in eine Queue schreiben und asynchron abarbeiten. – Beschleunigt außerdem auch den Import- Vorgang – http://www.fabrizio-branca.de/magento- asynchronous-cache.html – https://github.com/fbrnc/Aoe_AsyncCache
  • 12.
  • 13.
  • 14.
    Bug: 1st-Level CachePriorität $priority = 10 class Varien_Cache_Core extends Zend_Cache_Core { […] public function save($data, $id = null, $tags = array(), $specificLifetime = false, $priority = 8) { $tags = $this->_tags($tags); return parent::save($data, $id, $tags, $specificLifetime, $priority); } […] } class Zend_Cache_Backend_TwoLevels […] { private function _getFastLifetime($lifetime, $priority, $maxLifetime = null) { […] $fastLifetime = (int) ($lifetime / (11 - $priority)); […] return $fastLifetime; } }
  • 15.
    Bug: 1st-Level CachePriorität • Patch: https://gist.github.com/971320
  • 16.
    Weitere Probleme • Fastcache wird immer neu geschrieben auto_refresh_fast_cache = true => auto_refresh_fast_cache = false • Kann inzwischen konfiguriert werden (default: false) • Verzeichnistiefe des File Cache hashed_directory_level = 1 => hashed_directory_level = 3 • APC-Parameter (Größe, apc.stat, apc.ttl) http://www.fabrizio-branca.de/wenn-der-apc-cache- volllaeuft.html
  • 17.
    Agenda Reverse Proxy Ein- Probleme und Caching führung Optimierungen mit Varnish
  • 18.
    Reverse proxy caching Request Browser Magento (Apache + PHP + Mysql) Response
  • 19.
    Reverse proxy caching Browser Varnish Magento (Apache + PHP + Mysql)
  • 20.
    Reverse proxy caching Browser Nginx Varnish Magento (Apache + PHP + Mysql) -Verschlüsselung / Entschlüsselung (SSL) -Kompression
  • 21.
    Reverse proxy caching Browser Nginx Varnish Magento (Apache + PHP + Mysql)
  • 22.
    Varnish HTTP Caching Load Failover Accelerator Reverse Proxy Balancer system „Varnish makes websites fly“
  • 23.
    Varnish • Entwickelt vonPoul-Henning Kamp • Varnish Configuration Language (VCL) – DSL, wird intern in C Code übersetzt und dann compiliert • Varnish überlässt die Thread- und Speicherverwaltung dem Betriebssystem • Weitere Tools: varnishtop, varnishlog,… • Online-Dokumentation: http://www.varnish-cache.org/docs/2.1/
  • 24.
    Installation • In Ubuntu: sudoapt-get install varnish sudo vi /etc/default/varnish START=yes sudo /etc/init.d varnish start • Wird in Zukunft automatisch gestartet • Läuft per default auf Port 6081 • Verwendet per default 127.0.0.1:8080 als Backend • /etc/varnish/default.vcl
  • 25.
    Request Lifecycle (vereinfacht) Kompletter Workflow: http://www.varnish-cache.org/trac/wiki/VCLExampleDefault
  • 26.
    Cachebare Seiten • cms_index_index (Startseite) • cms_page_view (CMS Seiten) • catalog_product_view (Produkt-Singleviews) • catalog_category_view (Produkt-Listen) (Muss ggf. an die Anforderungen und Besonderheiten des Shops angepasst werden) aller Page-Requests (geschätzt)
  • 28.
  • 29.
    Platzhalter für dynamischeTeile <layout> <default> <reference name="right"> <block type="core/text" name="ph_cart" before="-"> <action method="setText"><param><![CDATA[ <div id="cart_sidebar" class="placeholder" rel="cart_sidebar">Placeholder Cart</div> ]]></param></action> </block> <action method="unsetChild"><param>cart_sidebar</param></action> </reference> </default> </layout>
  • 30.
    Modul „Aoe_Static“ • SendetHTTP Header um Varnish zu steuern. • Bindet JavaScript ein, das die dynamischen Inhalte holt und die Platzhalter ersetzt. • Controller, der die dynamischen Inhalte ausliefert. • https://github.com/fbrnc/Aoe_Static • https://github.com/fbrnc/Aoe_StaticDemo
  • 31.
    Ablauf cachebare Seiten Browser Varnish Magento Seite anfordern (HTTP Request) Seite anfordern Statische Seite wird ausgeliefert. Statische Seite wird Platzhalter für dynamische Teile. ausgeliefert Cache-Control Header Seite wird gerendert Ajax Request fordert dynamische Inhalte an und übermittelt gerade angesehenes Produkt JSON Response mit dynamischen Inhalten Platzhalter werden ersetzt Session Cookie wird geschrieben
  • 32.
    Ablauf nicht-cachebare Seiten Browser Varnish Magento Seite anfordern (HTTP Request) Seite anfordern Seite wird ausgeliefert Seite wird gerendert
  • 33.
    VCL sub vcl_recv { if (req.http.x-forwarded-for) { set req.http.X-Forwarded-For = req.http.X-Forwarded-For ", " client.ip; } else { set req.http.X-Forwarded-For = client.ip; } if (req.request != "GET" && req.request != "HEAD" && req.request != "PUT" && req.request != "POST" && req.request != "TRACE" && req.request != "OPTIONS" && req.request != "DELETE") { /* Non-RFC2616 or CONNECT which is weird. */ return (pipe); } if (req.request != "GET" && req.request != "HEAD") { /* We only deal with GET and HEAD by default */ return (pass); } if (req.http.Authorization || req.http.Cookie) { /* Not cacheable by default */ return (pass); } return (lookup); }
  • 34.
    VCL sub vcl_hash { set req.hash += req.url; if (req.http.host) { set req.hash += req.http.host; } else { set req.hash += server.ip; } return (hash); }
  • 35.
    VCL sub vcl_fetch { if (beresp.status == 302 || beresp.status == 301 || beresp.status == 418) { return (pass); } if (beresp.http.aoestatic == "cache") { remove beresp.http.Set-Cookie; remove beresp.http.X-Cache; remove beresp.http.Server; remove beresp.http.Age; set beresp.grace = 2m; set beresp.http.X_AOESTATIC_FETCH = "Removed cookie in vcl_fetch"; } if (!beresp.cacheable) { return (pass); } return (deliver); }
  • 36.
    VCL sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; set resp.http.Server = "Varnish (HIT)"; } else { set resp.http.X-Cache = "MISS"; set resp.http.Server = "Varnish (MISS)"; } }
  • 37.
  • 38.
    Benchmarks 416,67 Seiten/Sekunde 0,85 2,4 Seiten/Sekunde Seiten/Sekunde Magento Magento mit Magento ohne Cache APC+File Cache mit Varnish
  • 39.
    Erweitert • Anstatt AJAX: Edge Side Includes „ESI“ (W3C) <esi:include src="phone/call/getBlock/id/cart_sidebar" /> – Nachteil: langsamer, aufwendiger • Caching dynamischer Inhalte unter Berücksichtigung der Session-Id – Nachteil: weniger Cache Hits • „Purge“ um geänderte Inhalte zu aktualisieren
  • 40.
    Weitere Informationen • Varnish(inkl. Dokumentation) http://www.varnish-cache.org • Poul-Henning Kamp über Varnish http://vimeo.com/16676188 • http://www.fabrizio-branca.de • https://github.com/fbrnc
  • 41.
    Fragen? Mail: mail (at) fabrizio (minus) branca (dot) de Twitter: @fbrnc Blog: http://www.fabrizio-branca.de