Varnish und Magento Full Page Cache im Detail
60fps
ms
Performance · Caching · Varnish · Magento 2
Varnish und Magento Full Page Cache im Detail
VCL, ESI und Cache-Debugging in der Praxis

Ein korrekt konfigurierter Varnish Full Page Cache liefert Magento-Seiten in wenigen Millisekunden aus, doch schon eine einzige falsch gesetzte Cookie-Regel kann die Hit-Rate auf null drücken. Dieser Artikel erklärt VCL-Grundlagen, Magentos default.vcl, ESI-Fragmente für personalisierte Blöcke und die häufigsten Cache-Busting-Fehler samt Debugging-Techniken.

16 Min. Lesezeit Varnish VCL · ESI · Cache-Debugging Magento 2.4.8 · Hyvä Theme

1. Warum Varnish vor Magento gehört

Varnish ist ein HTTP-Reverse-Proxy, der komplette Seiten als HTML im Arbeitsspeicher vorhält und Anfragen beantwortet, bevor sie überhaupt den PHP-Prozess erreichen. Für Magento bedeutet das: Statt bei jedem Seitenaufruf Layout-XML zu parsen, Blöcke zu rendern und Datenbankabfragen auszuführen, liefert Varnish eine bereits fertige HTML-Antwort in unter 5 Millisekunden aus. Der Unterschied zum PHP-Rendering-Pfad ist erheblich: Ein unkomprimiertes Kategorieseiten-Rendering über PHP-FPM kann je nach Katalogumfang 300 bis 800 Millisekunden benötigen, während dieselbe Seite aus dem Varnish-Cache in der Regel unter 10 Millisekunden zurückkommt.

Magento unterstützt seit Version 2.0 Varnish als offiziellen Full Page Cache (FPC) neben dem eingebauten Built-in-Cache. Der Built-in-Cache läuft im selben PHP-Prozess und spart zwar das Blockrendering, aber nicht den kompletten Bootstrap-Overhead von Magento - Varnish hingegen beantwortet Anfragen vollständig außerhalb des Applikationsservers. In produktiven Shops mit spürbarem Traffic ist Varnish deshalb praktisch immer die richtige Wahl, insbesondere bei Kategorieseiten und CMS-Inhalten mit hoher Wiederholrate.

2. VCL-Grundlagen: vcl_recv, vcl_backend_response, vcl_deliver

VCL (Varnish Configuration Language) ist eine domänenspezifische Sprache, die in mehreren benannten Subroutinen abgearbeitet wird, sobald eine Anfrage den Varnish-Prozess durchläuft. vcl_recv wird direkt nach Empfang der Client-Anfrage ausgeführt und entscheidet, ob eine Anfrage überhaupt gecacht werden darf - hier werden Cookies geprüft, Query-Parameter normalisiert und statische Assets von der Cache-Logik ausgenommen. Trifft vcl_recv die Entscheidung return (pass), wird die Anfrage direkt an Magento durchgereicht, ohne den Cache überhaupt zu konsultieren.

vcl_backend_response läuft, nachdem Varnish eine Antwort vom Magento-Backend erhalten hat, und legt fest, wie lange und ob diese Antwort im Cache gespeichert wird - gesteuert über die TTL sowie Response-Header wie Cache-Control und X-Magento-Tags, die Magento für die spätere gezielte Invalidierung nutzt. vcl_deliver schließlich wird unmittelbar vor Auslieferung der Antwort an den Client ausgeführt und ist der Ort, an dem Debug-Header wie X-Magento-Cache-Debug gesetzt und interne Header wieder entfernt werden, damit sie nicht versehentlich beim Endnutzer landen.


# Vereinfachte vcl_recv-Logik, wie sie Magento generiert
sub vcl_recv {
    # Statische Assets nie an das Backend weiterreichen, immer cachen
    if (req.url ~ "^/(media|static)/") {
        unset req.http.Https;
        set req.url = regsub(req.url, "\?.*$", "");
        return (hash);
    }

    # Bestimmte Cookies zwingen die Anfrage in den PASS-Modus
    if (req.http.cookie ~ "X-Magento-Vary=") {
        return (pass);
    }

    # POST, PUT, DELETE niemals cachen
    if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
    }

    # Admin- und Checkout-Routen grundsaetzlich vom Cache ausschliessen
    if (req.url ~ "^/(admin|checkout|customer/account)") {
        return (pass);
    }

    return (hash);
}

3. Hashing und der Cache-Key in vcl_hash

Jede gecachte Antwort wird intern über einen Hash-Key identifiziert, der in der Subroutine vcl_hash zusammengesetzt wird. Standardmäßig fließen die URL, der Host-Header und optional das Schema (HTTP/HTTPS) in diesen Hash ein. Magento erweitert diesen Hash zusätzlich um den Wert des X-Magento-Vary-Cookies, damit personalisierte Seitenvarianten - etwa unterschiedliche Preisgruppen im B2B-Kontext oder Store-View-spezifische Inhalte - getrennt voneinander gecacht werden, statt sich gegenseitig zu überschreiben.

Ein häufiger, teurer Fehler entsteht, wenn zu viele Variablen in den Hash einfließen: Wird beispielsweise der komplette User-Agent-String eingerechnet, entstehen für praktisch jeden Besucher eigene Cache-Einträge, weil Browser-Versionen und Betriebssysteme extrem vielfältig sind. Die Folge ist eine Hit-Rate, die trotz technisch funktionierendem Cache gegen null tendiert, weil kaum zwei Anfragen denselben Hash erzeugen. Der Cache-Key sollte deshalb so schlank wie möglich bleiben und nur Dimensionen enthalten, die tatsächlich unterschiedliche HTML-Ausgaben erzeugen - in der Praxis meist URL, Host und die Magento-eigene Vary-Dimension.


sub vcl_hash {
    # Base dimensions: URL and Host always go into the cache key
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }

    # Magento's own personalization dimension, kept intentionally narrow
    if (req.http.cookie ~ "X_Magento_Vary=") {
        hash_data(regsub(req.http.cookie, "^.*?X_Magento_Vary=([^;]*);*.*$", "\1"));
    }

    # Separate cache entries per scheme (HTTP vs HTTPS)
    if (req.http.X-Forwarded-Proto) {
        hash_data(req.http.X-Forwarded-Proto);
    }

    return (lookup);
}

4. Magentos default.vcl: Aufbau und Generierung

Magento liefert unter app/code/Magento/PageCache/etc/varnish/default.vcl eine VCL-Vorlage mit Platzhaltern für Backend-Host, Backend-Port, Zugriffskontrollen und TTL-Werte aus. Über bin/magento varnish:vcl:generate --access-list=192.168.0.1,localhost --backend-host=fastly.example --backend-port=80 --export-version=6 wird daraus eine konkrete, einsatzfähige varnish.vcl-Datei erzeugt, die dem Varnish-Prozess per -f-Flag übergeben wird. Der Parameter --export-version ist entscheidend, weil sich die VCL-Syntax zwischen Varnish 4, 5 und 6 unterscheidet und eine falsche Version zu Boot-Fehlern des Varnish-Daemons führt.

Die generierte Datei enthält bereits fertige Logik für Health-Checks des Backends, für den Umgang mit PURGE-Requests zur gezielten Cache-Invalidierung über Tags, und für die Grace-Period, während der eine abgelaufene, aber noch im Speicher vorhandene Antwort weiter ausgeliefert wird, während im Hintergrund eine frische Version geholt wird. Diese Grace-Period ist besonders unter Last wertvoll: Statt dass hunderte gleichzeitige Anfragen auf eine abgelaufene Seite alle gleichzeitig das PHP-Backend treffen (ein sogenannter Cache-Stampede), liefert Varnish weiter die alte Version aus, bis genau eine Anfrage die Aktualisierung übernommen hat.

5. ESI: personalisierte Fragmente im gecachten HTML

Edge Side Includes (ESI) lösen ein grundsätzliches Problem des Full Page Cache: Eine Seite ist zu 95 % für alle Besucher identisch, enthält aber einzelne Blöcke wie den Mini-Cart-Zähler oder die Kundenbegrüßung, die pro Nutzer unterschiedlich sind. Ohne ESI müsste entweder die gesamte Seite vom Cache ausgeschlossen werden, oder die personalisierten Bereiche würden fälschlich für alle Besucher gleich ausgeliefert. Magento löst das, indem personalisierte Blöcke im gecachten HTML durch ESI-Tags wie <esi:include src="/customer/section/load"/> ersetzt werden.

Varnish erkennt diese Tags beim Ausliefern der gecachten Seite und lädt die referenzierten Fragmente separat nach, entweder aus einem eigenen kleinen Cache-Eintrag oder direkt live von Magento. Jedes ESI-Fragment verursacht einen zusätzlichen internen Request-Roundtrip zwischen Varnish und dem Backend, typischerweise im Bereich von 5 bis 30 Millisekunden pro Fragment - vernachlässigbar gegenüber einem kompletten unkached Seitenrendering, aber bei zehn oder mehr ESI-Blöcken auf einer Seite durchaus spürbar. Deshalb gilt die Faustregel: ESI für wenige, gezielt personalisierte Blöcke einsetzen, nicht für jede kleine dynamische Komponente.


<!-- phtml-Ausschnitt: ESI-Include fuer den Mini-Cart-Block -->
<!-- Wird von Varnish erkannt und separat vom Backend nachgeladen -->
<esi:include src="/customer/section/load/?sections=cart,customer&format=json" />

<!-- Layout XML: Block als "private" markieren, damit er nie im FPC landet -->
<referenceBlock name="minicart.link">
    <arguments>
        <argument name="cache_lifetime" xsi:type="number">0</argument>
    </arguments>
</referenceBlock>

6. Cache Hit Ratio messen und überwachen

Die Cache Hit Ratio ist die zentrale Kennzahl für die Gesundheit eines Full Page Cache: Sie beschreibt den Anteil der Anfragen, die direkt aus dem Cache beantwortet werden konnten, ohne das Backend zu belasten. Für einen gesunden Magento-Shop mit überwiegend anonymem Traffic gilt eine Hit-Rate von 90 bis 95 % oder höher als gesunder Zielwert. Liegt die Rate deutlich darunter, etwa bei 60 bis 70 %, deutet das fast immer auf ein strukturelles Problem hin: zu kurze TTLs, ein zu breiter Cache-Key oder eine Cookie-Regel, die Anfragen unnötig in den PASS-Modus zwingt.

varnishstat liefert in Echtzeit die relevanten Zähler direkt aus dem Shared-Memory-Log von Varnish, insbesondere cache_hit, cache_miss und cache_hitpass. Die Hit-Rate berechnet sich als cache_hit / (cache_hit + cache_miss + cache_hitpass). Für kontinuierliches Monitoring lohnt sich ein Export dieser Metriken über den varnish_exporter nach Prometheus mit Grafana-Dashboard, da einmalige Stichproben durch Traffic-Schwankungen leicht in die Irre führen - ein Blick über 24 Stunden oder eine volle Woche zeigt verlässlicher, ob die Hit-Rate strukturell stimmt.


# Live-Statistik direkt im Varnish-Container abrufen
varnishstat -1 | grep -E "cache_hit|cache_miss|cache_hitpass"

# Beispiel-Ausgabe
# MAIN.cache_hit          8452341   1234.56 Cache hits
# MAIN.cache_miss          198320     28.91 Cache misses
# MAIN.cache_hitpass        94211     13.75 Cache hits for pass

# Hit-Rate manuell berechnen (hier: rund 96 %)
echo "scale=4; 8452341 / (8452341 + 198320 + 94211)" | bc

7. Häufige Cache-Busting-Bugs: Cookies und X-Magento-Vary

Die mit Abstand häufigste Ursache für eine eingebrochene Hit-Rate sind Cookies, die Varnish fälschlich in den PASS-Modus zwingen. Das PHPSESSID-Cookie ist der Klassiker: Sobald irgendeine Drittanbieter-Extension oder ein eigenes Modul eine PHP-Session auch für anonyme Besucher startet, etwa weil es $this->_session->getData() unbedacht aufruft, landet dieses Cookie im Request und die Standard-VCL-Regel greift, die Anfragen mit gesetztem PHPSESSID am Cache vorbeileitet. Genauso problematisch ist das persistent_shopping_cart-Cookie, das durch das "Warenkorb merken"-Feature gesetzt wird und ebenfalls einen PASS auslöst, sobald es im Request vorhanden ist.

Das X-Magento-Vary-Cookie selbst ist eigentlich eine Lösung, kein Bug - es signalisiert Varnish, welche Cache-Variante für den aktuellen Besucher gilt. Problematisch wird es erst, wenn dieses Cookie durch einen fehlerhaften Cache-Context-Provider bei jedem Request einen neuen, zufälligen Wert erhält: Dann erzeugt jeder einzelne Besuch einen eigenen Cache-Eintrag, der sofort wieder verwaist, und die Hit-Rate bricht faktisch auf null ein, obwohl Varnish technisch korrekt arbeitet. Ein Blick in die Cookie-Werte über mehrere Requests hinweg deckt dieses Muster meist innerhalb weniger Minuten auf.

8. Debugging mit X-Magento-Cache-Debug

Magentos generierte VCL setzt standardmäßig den Response-Header X-Magento-Cache-Debug, sofern Cache-Control: no-cache im Backend-Response nicht explizit unterdrückt wurde. Dieser Header nimmt einen von drei Werten an: HIT bedeutet, die Antwort kam vollständig aus dem Varnish-Cache. MISS bedeutet, die URL war grundsätzlich cachebar, aber für diese spezifische Kombination aus URL und Hash-Key lag noch keine gültige Kopie vor, sodass Varnish das Backend kontaktiert und die Antwort anschließend cacht. PASS bedeutet, die Anfrage wurde laut VCL-Logik als grundsätzlich nicht cachebar eingestuft und geht bei jedem Aufruf erneut ans Backend.

Der praktische Debugging-Workflow beginnt fast immer mit curl -I gegen die betroffene URL, um den Header direkt einzusehen, gefolgt von einem zweiten identischen Request: Bleibt der Status bei wiederholten Aufrufen dauerhaft bei PASS, liegt die Ursache in der VCL-Logik selbst oder in einem mitgesendeten Cookie. Wechselt der Status zwischen MISS und HIT nie zu einem stabilen HIT, deutet das auf einen instabilen Cache-Key hin, häufig durch Session-abhängige oder zufällige Werte im Hash. Zusätzlich hilft varnishlog -g request, den kompletten Entscheidungsweg einer einzelnen Anfrage durch alle VCL-Subroutinen live mitzuverfolgen.


# Cache-Status einer Kategorieseite pruefen
curl -sI https://shop.example.com/damen/kleider.html | grep -i "x-magento-cache-debug"
# X-Magento-Cache-Debug: MISS

# Zweiter Request sollte nun einen HIT liefern
curl -sI https://shop.example.com/damen/kleider.html | grep -i "x-magento-cache-debug"
# X-Magento-Cache-Debug: HIT

# Mit Cookie: erzwingt PASS, auch wenn die Seite normalerweise cachebar ist
curl -sI --cookie "PHPSESSID=test123" https://shop.example.com/damen/kleider.html \
  | grep -i "x-magento-cache-debug"
# X-Magento-Cache-Debug: PASS

9. HIT, MISS und PASS im direkten Vergleich

Die drei Debug-Zustände unterscheiden sich stark in Latenz und Backend-Belastung. Die folgende Übersicht zeigt typische Fehlerursachen und die jeweils passende Korrektur.

Zustand Typische Ursache Latenz Empfohlene Korrektur
HIT Gecachte Seite, gültiger Hash-Key < 10 ms Zielzustand, keine Aktion nötig
MISS (dauerhaft) Instabiler Cache-Key, zufällige Cookie-Werte 300-800 ms Cache-Key bereinigen, Vary-Cookie fixieren
PASS (PHPSESSID) Session wird für anonyme Besucher gestartet 300-800 ms Session-Start für Gäste vermeiden
PASS (Checkout) Bewusster VCL-Ausschluss dynamischer Routen 200-500 ms Korrekt so, kein Fix nötig
HITPASS Backend liefert Cache-Control: no-cache dauerhaft 200-500 ms Block-TTL im Layout-XML korrigieren

In der Praxis treten diese Zustände selten isoliert auf: Ein fehlerhaftes Drittanbieter-Modul, das Sessions startet, erzeugt gleichzeitig PASS-Requests und verschlechtert durch den zusätzlichen Traffic auch die Antwortzeit für alle anderen Anfragen ans Backend. Wer den Cache-Status systematisch über mehrere Seitentypen hinweg prüft, findet solche Kettenreaktionen meist schneller als durch reines Hit-Rate-Monitoring allein.

Mironsoft

Varnish-Tuning, FPC-Konfiguration und Performance-Audits für Magento-Shops

Cache-Hit-Rate im Keller?

Wir analysieren eure VCL-Konfiguration, decken Cache-Busting-Bugs auf und richten ESI-Fragmente sauber für personalisierte Blöcke ein, damit euer Full Page Cache dauerhaft im grünen Bereich bleibt.

VCL-Audit

Vollständige Prüfung von vcl_recv, Hashing und TTL-Strategie

Cache-Busting-Fixes

Cookie-Ursachen identifizieren und Session-Starts vermeiden

Monitoring-Setup

varnishstat-Export nach Prometheus mit Hit-Rate-Alerts

10. Zusammenfassung

Varnish und der Magento Full Page Cache lösen ein zentrales Performance-Problem: Statt jede Anfrage komplett durch den PHP-Rendering-Pfad zu schicken, liefert Varnish gecachte HTML-Antworten in wenigen Millisekunden aus. Die Grundlage dafür bildet ein sauberes Zusammenspiel aus vcl_recv, vcl_backend_response und vcl_deliver, ergänzt um einen schlanken Cache-Key aus vcl_hash, der nur tatsächlich relevante Dimensionen wie URL, Host und die Magento-Vary-Kennung enthält. ESI-Fragmente erlauben es, personalisierte Blöcke wie Mini-Cart oder Kundenbegrüßung gezielt aus dem gecachten HTML auszulagern, ohne die gesamte Seite vom Cache auszuschließen.

In der Praxis entscheidet sich die Qualität eines Full-Page-Cache-Setups selten an der grundsätzlichen Konfiguration, sondern an Details: einem Drittanbieter-Modul, das ungefragt PHP-Sessions startet, einem zu breiten Cache-Key oder einem falsch konfigurierten TTL-Wert für einzelne Blöcke. Der X-Magento-Cache-Debug-Header und varnishstat liefern die Werkzeuge, um solche Probleme innerhalb von Minuten statt Tagen zu identifizieren, und kontinuierliches Hit-Rate-Monitoring stellt sicher, dass Regressionen nach Deployments sofort auffallen.

Varnish und Magento Full Page Cache - Das Wichtigste auf einen Blick

VCL-Kernlogik

vcl_recv entscheidet über Cachefähigkeit, vcl_backend_response setzt die TTL, vcl_deliver liefert Debug-Header aus.

Ziel-Hit-Rate 90-95 %

Gemessen über varnishstat: cache_hit / (cache_hit + cache_miss + cache_hitpass).

ESI für Personalisierung

Mini-Cart und Kundenbegrüßung über esi:include auslagern, 5-30 ms Overhead pro Fragment.

Debugging

X-Magento-Cache-Debug: HIT/MISS/PASS per curl -I, Details via varnishlog -g request.

11. FAQ: Varnish und Magento Full Page Cache

1Was ist der Unterschied zwischen Varnish und Magentos Built-in Cache?
Varnish arbeitet vollständig außerhalb von PHP und liefert HTML in wenigen Millisekunden. Der Built-in-Cache läuft innerhalb von PHP und spart nur das Blockrendering, nicht den Magento-Bootstrap.
2Welche Aufgabe hat vcl_recv in der Varnish-Konfiguration?
Entscheidet direkt nach Empfang der Anfrage über Cachefähigkeit: Cookie-Prüfung, Query-Normalisierung und Ausschluss von Checkout/Admin-Routen.
3Wie generiere ich Magentos default.vcl für den eigenen Shop?
Über bin/magento varnish:vcl:generate mit Backend-Host, Backend-Port, Access-List und Export-Version, danach als -f-Flag an Varnish übergeben.
4Was sind ESI-Fragmente und wofür werden sie in Magento genutzt?
Erlauben es, personalisierte Blöcke wie Mini-Cart oder Kundenbegrüßung separat nachzuladen, statt die gesamte Seite vom Cache auszuschließen.
5Welche Cache Hit Ratio gilt als gesund für einen Magento-Shop?
90 bis 95 % oder höher bei überwiegend anonymem Traffic, gemessen über varnishstat mit cache_hit, cache_miss und cache_hitpass.
6Warum löst das PHPSESSID-Cookie einen Cache-Bypass aus?
Die Standard-VCL behandelt jede Anfrage mit gesetztem PHPSESSID als potenziell personalisiert und leitet sie im PASS-Modus direkt ans Backend.
7Was bedeutet das X-Magento-Vary-Cookie konkret?
Signalisiert Varnish, welche Cache-Variante für den Besucher gilt. Bei zufälligem Wert pro Request bricht die Hit-Rate ein, weil jeder Besuch einen eigenen Eintrag erzeugt.
8Wie lese ich den X-Magento-Cache-Debug-Header aus?
Über curl -I. HIT bedeutet aus dem Cache, MISS bedeutet cachefähig aber noch nicht gecacht, PASS bedeutet nicht cachefähig laut VCL oder Cookie.
9Was ist eine Grace-Period und wofür ist sie wichtig?
Erlaubt das Ausliefern einer abgelaufenen, aber gespeicherten Antwort, während im Hintergrund eine frische Version geholt wird. Verhindert einen Cache-Stampede.
10Wie viel Overhead verursacht ein ESI-Fragment?
Typischerweise 5 bis 30 Millisekunden pro Fragment durch den zusätzlichen internen Request. Deshalb nur für wenige, tatsächlich personalisierte Bereiche einsetzen.