Vom kalten Redis-Cache zur stabilen ersten Minute
Nach jedem Magento-Deployment ist der Redis-Cache leer, und die ersten Requests treffen die Datenbank ungebremst. Dieser Artikel zeigt, warum dieser Traffic-Spike entsteht, wie Warmup-Crawler und Cache-Preload-Skripte ihn verhindern, und wie sich Warmup sauber in die Deployment-Pipeline integrieren laesst.
Inhaltsverzeichnis
- 1. Das Problem: kalter Cache nach dem Deployment
- 2. Thundering Herd: wenn viele Requests gleichzeitig laden
- 3. Warmup-Crawler: den Full-Page-Cache gezielt fuellen
- 4. Die richtigen URLs fuer den Warmup auswaehlen
- 5. Objektcache-Preload fuer Kategorien und Konfiguration
- 6. Warmup in die Deployment-Pipeline integrieren
- 7. Blue-Green-Deployments und vorgewaermter Cache
- 8. Erfolg messen: Hit-Rate und Ladezeiten ueberwachen
- 9. Warmup-Strategien im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Das Problem: kalter Cache nach dem Deployment
Jedes Magento-Deployment, das bin/magento cache:flush ausfuehrt oder den Konfigurationscache neu generiert, leert den Redis-Objektcache und haeufig auch den Full-Page-Cache. Der erste Request auf jede Kategorie- oder Produktseite nach dem Deployment trifft dann nicht mehr auf einen gefuellten Cache, sondern muss die komplette Seite neu rendern: Produktdaten aus MySQL laden, Preise berechnen, Layout zusammenbauen und erst am Ende das Ergebnis in Redis ablegen. Diese Cold-Start-Requests dauern oft das Zehn- bis Zwanzigfache eines Cache-Hits.
Bei niedrigem Traffic faellt dieser Effekt kaum auf, weil sich die Cache-Fuellung langsam ueber die ersten Minuten nach dem Deployment verteilt. Bei Shops mit konstant hohem Traffic oder waehrend einer Kampagne ist das Bild ein anderes: innerhalb von Sekunden treffen hunderte oder tausende Requests gleichzeitig auf denselben leeren Redis-Cache, und jeder einzelne davon loest eine eigene, vollstaendige Datenbankabfrage aus. Das Ergebnis ist ein kurzzeitiger, aber massiver Lastspitze auf der Datenbank, die im schlimmsten Fall zu Timeouts oder sogar zu einem kompletten Ausfall fuehrt, genau in dem Moment, in dem ein Deployment eigentlich unauffaellig ablaufen sollte.
Der Kern des Problems liegt darin, dass ein leerer Redis-Cache und echter Nutzer-Traffic gleichzeitig aufeinandertreffen. Cache-Warmup loest dieses Problem, indem der Cache proaktiv gefuellt wird, bevor echte Nutzer die Seite aufrufen, sodass die Datenbank die Last kontrolliert und sequenziell statt schlagartig und parallel abbekommt.
2. Thundering Herd: wenn viele Requests gleichzeitig laden
Der technische Fachbegriff fuer das beschriebene Phaenomen ist Thundering Herd: viele gleichzeitige Anfragen erkennen alle denselben fehlenden Cache-Eintrag und starten parallel dieselbe teure Berechnung, obwohl nur eine einzige Berechnung noetig waere. Ohne Schutzmechanismus fuehrt eine populaere Produktseite nach dem Deployment dazu, dass zehn oder mehr parallele PHP-Prozesse gleichzeitig dieselben Produktdaten aus der Datenbank laden, dieselbe Preisberechnung durchfuehren und am Ende alle denselben Wert in Redis schreiben.
Magentos Full-Page-Cache-Layer mit Redis als Backend bietet von Haus aus keinen vollstaendigen Schutz vor diesem Effekt, wenn viele Requests im selben Millisekunden-Fenster eintreffen. Ein wirksames Gegenmittel ist ein Lock-Mechanismus auf Anwendungsebene: der erste Request, der einen Cache-Miss feststellt, setzt einen kurzlebigen Lock-Key in Redis mit SET key value NX EX 5, berechnet den Wert und gibt den Lock danach frei. Weitere Requests, die denselben Lock vorfinden, warten kurz oder liefern eine leicht veraltete Version aus, statt die teure Berechnung erneut auszufuehren.
Warmup-Strategien loesen das Thundering-Herd-Problem indirekt, indem sie den Cache fuellen, bevor echter paralleler Traffic ueberhaupt entsteht. Ein systematischer Crawler, der Seiten nacheinander statt parallel abruft, erzeugt genau eine Datenbankabfrage pro Seite und vermeidet die Duplikation, die bei echten Nutzern in Kombination mit einem leeren Cache entstehen wuerde.
3. Warmup-Crawler: den Full-Page-Cache gezielt fuellen
Ein Warmup-Crawler ist ein Skript, das nach dem Deployment automatisch eine Liste wichtiger URLs aufruft und dabei den Redis-Full-Page-Cache fuellt, ohne dass echte Nutzer die erste, langsame Anfrage ausloesen muessen. Fuer Magento gibt es dafuer mehrere Ansaetze: das offizielle bin/magento cache:enable in Kombination mit einem externen HTTP-Crawler, spezialisierte Warmer-Module, oder ein einfaches Bash-Skript mit curl, das sequenziell oder mit begrenzter Parallelitaet durch eine Sitemap oder URL-Liste iteriert.
Wichtig ist, dass der Crawler echte Requests mit denselben Headern schickt wie ein Browser, insbesondere den Accept-Encoding-Header und einen realistischen User-Agent, weil Magentos Varnish- oder Full-Page-Cache-Layer unterschiedliche Cache-Eintraege fuer unterschiedliche Kontexte anlegen kann. Ein Crawler, der diese Header ignoriert, fuellt unter Umstaenden einen Cache-Eintrag, den echte Browser gar nicht nutzen, weil ihre Anfrage geringfuegig anders aussieht.
#!/usr/bin/env bash
# warmup.sh: sequential Redis cache warmup crawler for Magento
set -euo pipefail
BASE_URL="https://shop.example.com"
URL_LIST="/var/www/deploy/warmup-urls.txt"
CONCURRENCY=4
LOG_FILE="/var/log/magento/warmup-$(date +%Y%m%d-%H%M%S).log"
echo "[INFO] Starting cache warmup with concurrency=${CONCURRENCY}" | tee "$LOG_FILE"
# xargs runs requests with bounded parallelism, avoiding a new thundering herd
cat "$URL_LIST" | xargs -P "$CONCURRENCY" -I {} \
curl -s -o /dev/null -w "%{http_code} %{time_total}s {}\n" \
-H "Accept-Encoding: gzip, deflate" \
-H "User-Agent: Mozilla/5.0 (compatible; MironsoftWarmupBot/1.0)" \
"${BASE_URL}{}" >> "$LOG_FILE"
echo "[INFO] Warmup complete. Requests logged to ${LOG_FILE}"
4. Die richtigen URLs fuer den Warmup auswaehlen
Ein Warmup-Crawler, der versucht, den kompletten Katalog nach jedem Deployment durchzugehen, verschwendet Zeit und Ressourcen. Sinnvoller ist eine priorisierte URL-Liste, die auf tatsaechlichen Traffic-Daten basiert: die Startseite, die wichtigsten Kategorieseiten, die meistbesuchten Produktseiten und statische Seiten wie AGB oder Checkout-Einstiegsseiten. Diese Liste laesst sich automatisiert aus den Zugriffszahlen von Google Analytics oder aus den Access-Logs des Webservers der letzten 30 Tage ableiten.
Fuer sehr grosse Kataloge mit hunderttausenden Produkten ist es weder praktikabel noch noetig, jede einzelne Seite vorzuwaermen. Die Pareto-Regel greift hier zuverlaessig: meist erzeugen 20 Prozent der Seiten 80 Prozent des Traffics, und ein Warmup, der genau diese Top-URLs abdeckt, reduziert die Datenbank-Last nach dem Deployment bereits um den Grossteil, ohne den Crawler-Lauf unnoetig in die Laenge zu ziehen. Die restlichen, seltener aufgerufenen Seiten fuellen sich organisch durch echten Nutzer-Traffic, allerdings mit einer geringeren Wahrscheinlichkeit fuer gleichzeitige parallele Zugriffe und damit einem geringeren Thundering-Herd-Risiko.
# Generate a prioritized warmup URL list from the last 30 days of Nginx access logs
awk '{print $7}' /var/log/nginx/shop.example.com-access.log \
| grep -E '^/(catalog|category|checkout|customer)?' \
| sort | uniq -c | sort -rn \
| head -n 500 \
| awk '{print $2}' > /var/www/deploy/warmup-urls.txt
wc -l /var/www/deploy/warmup-urls.txt
5. Objektcache-Preload fuer Kategorien und Konfiguration
Neben dem Full-Page-Cache lohnt sich ein gezielter Preload des Magento-Objektcaches in Redis, insbesondere fuer Daten, die auf fast jeder Seite gebraucht werden: die Kategoriebaum-Struktur, die Store-Konfiguration, aktive Layered-Navigation-Attribute und Layout-XML-Merges. Diese Daten aendern sich selten, werden aber bei jedem Request gelesen, weshalb ein fehlender Eintrag hier besonders teuer ist, weil er von praktisch jedem Seitentyp gleichzeitig betroffen ist.
Ein einfaches PHP-Skript, das ueber die Magento-Bootstrap-Klasse laeuft, kann diese kritischen Objektcache-Eintraege gezielt vorab befuellen, indem es die entsprechenden Repository-Methoden einmal aufruft, noch bevor der Crawler startet. Das stellt sicher, dass selbst der allererste Full-Page-Cache-Warmup-Request bereits auf einen teilweise gefuellten Objektcache trifft und nicht zusaetzlich die Basisdaten neu laden muss.
<?php
// bin/warmup-object-cache.php: preload frequently used object cache entries
require __DIR__ . '/../app/bootstrap.php';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
$objectManager = $bootstrap->getObjectManager();
$state = $objectManager->get(\Magento\Framework\App\State::class);
$state->setAreaCode('frontend');
$storeManager = $objectManager->get(\Magento\Store\Model\StoreManagerInterface::class);
$categoryRepository = $objectManager->get(\Magento\Catalog\Api\CategoryRepositoryInterface::class);
foreach ($storeManager->getStores() as $store) {
echo "[INFO] Warming category tree for store: {$store->getCode()}\n";
// Touching the root category forces Magento to rebuild and cache the tree
$categoryRepository->get((int) $store->getRootCategoryId(), $store->getId());
}
echo "[INFO] Object cache preload complete\n";
6. Warmup in die Deployment-Pipeline integrieren
Warmup sollte kein manueller Schritt sein, sondern fester Bestandteil der Deployment-Pipeline, unmittelbar nach dem Cache-Flush und vor der Freigabe des Traffics auf die neue Version. In der klassischen Reihenfolge steht Warmup direkt nach bin/magento cache:flush und vor dem Entfernen einer eventuell aktiven Maintenance-Page oder dem Umschalten des Load Balancers auf den neuen Deployment-Slot.
Ein haeufiger Fehler ist, den Warmup-Schritt zeitlich zu knapp zu bemessen oder ihn im Hintergrund laufen zu lassen, waehrend der Traffic bereits freigegeben wird. Das unterlaeuft den ganzen Zweck der Massnahme, weil echte Nutzer dann parallel zum Crawler auf denselben leeren Cache treffen. Sauberer ist es, den Maintenance-Modus erst nach erfolgreichem Abschluss des Warmup-Laufs zu deaktivieren, sodass zum Zeitpunkt der Freigabe bereits ein signifikanter Teil des Caches gefuellt ist.
#!/usr/bin/env bash
# deploy-with-warmup.sh: deployment sequence with cache warmup before traffic release
set -euo pipefail
echo "[STEP 1] Enabling maintenance mode"
bin/magento maintenance:enable
echo "[STEP 2] Running setup upgrade and flushing cache"
bin/magento setup:upgrade
bin/magento cache:flush
echo "[STEP 3] Preloading object cache"
php bin/warmup-object-cache.php
echo "[STEP 4] Running full-page-cache warmup crawler"
./warmup.sh
echo "[STEP 5] Verifying warmup coverage before releasing traffic"
HIT_RATIO=$(redis-cli -n 1 info stats | grep keyspace_hits | cut -d: -f2)
echo "[INFO] Current keyspace_hits: ${HIT_RATIO}"
echo "[STEP 6] Disabling maintenance mode, traffic is released"
bin/magento maintenance:disable
7. Blue-Green-Deployments und vorgewaermter Cache
Bei Blue-Green-Deployments laesst sich das Kaltstart-Problem noch eleganter loesen: die neue Version laeuft parallel zur alten auf einer separaten Infrastruktur, mit einem eigenen, zunaechst leeren Redis-Cache. Der Warmup-Crawler laeuft gegen diese neue Umgebung, waehrend die alte Version weiterhin den gesamten Produktivtraffic bedient. Erst wenn der Cache der neuen Umgebung ausreichend gefuellt ist, schaltet der Load Balancer den Traffic um.
Dieser Ansatz eliminiert das Thundering-Herd-Problem fast vollstaendig, weil zu keinem Zeitpunkt echter Nutzer-Traffic auf einen leeren Cache trifft. Die Kosten dafuer sind zusaetzliche Infrastruktur, die parallel betrieben werden muss, und ein etwas laengeres Deployment-Fenster, weil der Warmup vor dem Umschalten abgeschlossen sein muss. Fuer Shops mit hohem Umsatz pro Minute ist dieser Mehraufwand meist gerechtfertigt, weil ein einziger fehlgeschlagener Deployment-Traffic-Spike deutlich teurer sein kann.
8. Erfolg messen: Hit-Rate und Ladezeiten ueberwachen
Ob ein Warmup-Lauf tatsaechlich wirkt, laesst sich direkt an der Redis-Hit-Rate ablesen. Der Befehl INFO stats liefert keyspace_hits und keyspace_misses, aus denen sich die Trefferquote berechnen laesst. Direkt nach einem erfolgreichen Warmup sollte die Miss-Rate fuer die vorgewaermten URLs nahe null liegen, waehrend sie ohne Warmup in den ersten Minuten nach dem Deployment deutlich ueber 50 Prozent liegen kann.
Zusaetzlich zur reinen Hit-Rate lohnt sich die Beobachtung der Antwortzeiten in den ersten fuenf Minuten nach jedem Deployment, etwa ueber Application-Performance-Monitoring-Tools. Ein wirksamer Warmup zeigt sich darin, dass die p95-Antwortzeit direkt nach der Freigabe nahe am normalen Niveau bleibt, statt kurzzeitig anzusteigen. Diese Metrik eignet sich gut als automatisierter Check in der Pipeline, der ein Deployment als fehlgeschlagen markiert, wenn die Antwortzeiten nach dem Warmup nicht innerhalb eines definierten Schwellwerts liegen.
# Compute Redis hit ratio before and after a warmup run
before_hits=$(redis-cli -p 6381 info stats | grep -oP 'keyspace_hits:\K\d+')
before_miss=$(redis-cli -p 6381 info stats | grep -oP 'keyspace_misses:\K\d+')
./warmup.sh
after_hits=$(redis-cli -p 6381 info stats | grep -oP 'keyspace_hits:\K\d+')
after_miss=$(redis-cli -p 6381 info stats | grep -oP 'keyspace_misses:\K\d+')
echo "Hits before: ${before_hits}, misses before: ${before_miss}"
echo "Hits after: ${after_hits}, misses after: ${after_miss}"
# Fail the pipeline if miss rate stays too high after warmup
delta_miss=$(( after_miss - before_miss ))
if (( delta_miss > 500 )); then
echo "[ERROR] Warmup coverage insufficient: ${delta_miss} new misses" >&2
exit 1
fi
9. Warmup-Strategien im Vergleich
Je nach Shop-Groesse, Traffic-Muster und Infrastruktur eignen sich unterschiedliche Warmup-Ansaetze. Die folgende Tabelle vergleicht die gaengigsten Strategien fuer Magento-Shops mit Redis als Cache-Backend.
| Strategie | Aufwand | Thundering-Herd-Schutz | Geeignet fuer |
|---|---|---|---|
| Kein Warmup | Keiner | Kein Schutz | Nur Traffic-arme Testumgebungen |
| Einfacher Sequential-Crawler | Gering | Gut | Kleine bis mittlere Shops |
| Priorisierter Top-URL-Crawler | Mittel | Sehr gut | Grosse Kataloge, hoher Traffic |
| Objektcache-Preload-Skript | Mittel | Ergaenzend | Shops mit vielen Kategorien/Attributen |
| Blue-Green mit Vorab-Warmup | Hoch | Exzellent | Umsatzstarke Shops, hohe SLAs |
Die meisten Magento-Shops kommen mit einem priorisierten Top-URL-Crawler in Kombination mit einem Objektcache-Preload-Skript bereits sehr weit. Blue-Green-Deployments mit vollstaendigem Vorab-Warmup lohnen sich vor allem dann, wenn jede Minute mit erhoehten Ladezeiten direkt messbaren Umsatzverlust bedeutet.
10. Zusammenfassung
Ein kalter Redis-Cache nach dem Deployment ist kein Randproblem, sondern eine der haeufigsten Ursachen fuer Datenbank-Lastspitzen und Performance-Einbrueche direkt nach einem Release. Warmup-Crawler, die priorisierte URL-Listen sequenziell oder mit begrenzter Parallelitaet abrufen, fuellen den Full-Page-Cache proaktiv, bevor echter Nutzer-Traffic auf die neue Version trifft. Ergaenzend sorgt ein gezieltes Objektcache-Preload-Skript dafuer, dass Basisdaten wie Kategoriebaum und Store-Konfiguration bereits vor dem ersten Request verfuegbar sind.
Die entscheidende Regel lautet: Warmup gehoert vor die Traffic-Freigabe, nicht danach. Ob per klassischem Maintenance-Mode-Fenster oder per Blue-Green-Deployment mit separater Warmup-Umgebung, in beiden Faellen soll kein echter Nutzer jemals auf einen leeren Redis-Cache treffen. Monitoring von Hit-Rate und Antwortzeiten in den ersten Minuten nach jedem Deployment macht sichtbar, ob die Warmup-Strategie tatsaechlich wirkt.
Cache-Warmup-Strategien fuer Magento: Das Wichtigste auf einen Blick
Das Problem
Kalter Redis-Cache nach Deployment trifft echten Traffic gleichzeitig, was zu Datenbank-Lastspitzen fuehrt.
Warmup-Crawler
Priorisierte Top-URL-Liste sequenziell oder begrenzt parallel abrufen, bevor Traffic freigegeben wird.
Objektcache-Preload
Kategoriebaum und Store-Konfiguration gezielt vorab befuellen, bevor der Full-Page-Cache-Warmup laeuft.
Pipeline-Integration
Warmup zwischen Cache-Flush und Traffic-Freigabe, idealerweise mit Blue-Green-Deployment.