Cache Me If You Can Shopware 6 Cache-Änderungen und Wege den http cache aufzuwärmen
HTTP-Cache in Kurze
Wie gezeigt, wird nur der zweite Aufruf aus dem Cache bedient. Um sicherzustellen, dass unsere Benutzer immer schnelle Antworten erhalten, wärmen wir unseren Cache vor, indem wir jede Seite im Voraus besuchen, ein Prozess, der als Cache-Warmup bekannt ist.
Weitere Informationen darüber, wie der Shopware-Cache funktioniert, finden Sie unter den folgenden Links:
Änderungen in Shopware ab SW6.5.8.0
- Entfernung des Objekt-Caches: Die meisten Objekt-Caches werden eliminiert und in die HTTP-Cache-Schicht verschoben.
- Vereinfachte Cache-Schlüssel-Permutation: Die Cache-Schlüssel-Permutation wird auf wesentliche Kontextregeln (Saleschannel-ID, Sprach-ID, Währungs-ID, Steuerstatus, Kundengruppen-ID) beschränkt, um die Trefferquote der Cache-Schlüssel zu verbessern.
- Verbesserte Cache-Invalidierung: Shopware wird standardmäßig verzögerte Cache-Invalidierung aktivieren und eine Soft-Purge im Cache implementieren.
- Einführung von ESI-Tags: Edge Side Includes (ESI) Tags werden für bestimmte Seitenbereiche wie das Footer- und Header-Menü eingeführt, um zu verhindern, dass der gesamte Cache bei Änderungen ungültig wird.
- Markierung vieler HTTP-Cache- und Reverse-Proxy-Klassen als @internal und deren Verschiebung in den Kern.
- Neuordnung des Kernel-Bootstrapping.
- Abschaffung der HTTP-Cache-Wärmer.
"Http cache warmer Wir haben alle Http-Cache-Wärmer veraltet, da sie mit dem neuen HTTP-Kernel nicht mehr nutzbar sein werden. Sie sind auch nicht geeignet für die neue Cache-Überarbeitung oder für Systeme, die einen Reverse-Proxy oder Load Balancer vor dem Shopware-System haben. Deshalb haben wir sie als veraltet markiert und werden sie in der nächsten Hauptversion entfernen. Stattdessen sollten Sie einen echten Website-Crawler verwenden, um Ihre gewünschten Seiten aufzuheizen, was viel besser und realistischer für Ihr System ist."
Warmup HTTP Cache in Shopware
Wir haben viele Informationen für unser wget2-Skript aus diesem Artikel entnommen: Simple Varnish Cache Warmer using wget2 - Byte Pursuits - Byte Pursuits Ein großes Dankeschön an Byte Pursuits.
Entwicklung eines Aufwärmskripts: Von "Es ist mega einfach" zu "Verdammt, da gibt es eine Menge zu beachten"
Testumgebung
APP_ENV=prod
SHOPWARE_HTTP_CACHE_ENABLED=1
SHOPWARE_HTTP_DEFAULT_TTL=7200
- 9 Kategorien
- 6 Produkte
- 10 Produktvarianten
- Sprache: EN
- Währung: EUR
- Sprachen: DE, EN
- Währungen: EUR, USD, GBP
Sales Channel 2 (9 Kategorien + 16 Produkte + 1 Landing Page) x 2 Sprachen x 3 Währungen sollten wir mindestens 156 Cache-Elemente im Cache haben.
v1_http-cache-warmup.sh
Mit diesem Skript weisen wir wget2 an, mit der Hauptdomain von Sales Channel 1 zu starten und alle Links dieses Shops zu folgen.
#!/bin/bash
wget2 -r \
--no-parent \
--level=0 \
--tries=3 \
--timeout=5 \
--spider \
--header "Accept-Encoding: br" \
--user-agent=diga-cachewarming-client \
--wait=0.5 \
--reject '*.js,*.css,*.txt,*.gif,*.jpg,*.jpeg,*.png,*.mp4,*.webp,*.mp3,*.woff2,*.pdf,*.tgz,*.flv,*.avi,*.mpeg,*.iso,*.zip,*.svg' \
--ignore-tags=img,link,script \
--robots=no \
--domains=local-devshop.com \
--no-check-certificate \
"https://local-devshop.com"
Dies sind die Optionen, die wir in der ersten Version verwendet haben.
Option | Description |
---|---|
-r | Recursively crawl the URL. |
--no-parent | Prevent crawling to parent directories. |
--level=0 | Unlimited depth; adjust if you need a different recursion depth. |
--tries=3 | Number of retry attempts on failure. |
--timeout=5 | Set timeout for each request to 5 seconds. |
--spider | Crawl without downloading the actual content, useful for cache warming. |
--delete-after | Delete downloaded files immediately (combined with --spider for efficiency). |
--header "Accept-Encoding: br" | Request Brotli-encoded responses. |
--user-agent | Set a custom user agent string. |
--wait=0.5 | Wait 0.5 seconds between requests to avoid overwhelming the server. |
--reject | Skip downloading specified file types to reduce unnecessary requests. |
--ignore-tags=img,link,script | Ignore specified HTML tags during parsing to prevent following links. |
--domains=domains-list | Set domains to be followed. Ensure no external links are followed by your wget. |
--robots=no | Ignore robots.txt rules, useful for prewarming internal caches. |
--no-check-certificate | Skip SSL certificate verification. This is just for localhost development. |
Nach dem Ausführen des Skripts in einer lokalen Testumgebung und dem Schreiben der wget2-Ausgabe in eine Datei zur weiteren Untersuchung:
./v1_http-cache-warmup.sh > warmup_v1.txt
Erhalten wir diese Ergebnisse:
- wget2: Heruntergeladen: 62 Dateien, 2,28M Byte, 5 Umleitungen, 0 Fehler
- Redis: Suche nach http-cache > 22 Ergebnisse
Wie wir sehen, haben wir weniger Cache-Elemente als erwartet. Durch Überprüfung der Logs von wget2 wird festgestellt, dass verschiedene Seiten heruntergeladen werden, die von Shopware nicht zwischenspeicherbar sind, wie /cart
, /account
und einige /widgets
. Trotzdem werden nicht alle erwarteten Seiten aufgewärmt.
Wir vermissen einige Varianten, die nicht aufgewärmt wurden, wie im Netzwerkprotokoll unten zu sehen ist.
Der Grund dafür ist, dass der Variantenwechsel in Shopware ein Form-Submit und kein Link ist, wget2 folgt jedoch nur Links. Ähnliche Probleme werden wir haben, wenn wir unseren zweiten Sales Channel mit verschiedenen Sprachen aufwärmen, da der Sprachwechsel in Shopware ebenfalls ein Form-Submit ist. Als Ergebnis wird nach Abschluss unseres Warmup-Skripts v1 nur eine Sprache aufgewärmt sein.
Deshalb müssen wir unser Skript erweitern, um Folgendes zu berücksichtigen:
- Varianten
- Mehrere Sprachen
v2_http-cache-warmup.sh
Leider haben wir keine Möglichkeit gefunden, dass wget Formularübermittlungen durchführt, um alle Varianten aufzuwärmen. Die einzige Lösung besteht darin, unsere Sitemap als Quelle für alle URLs zu verwenden. Für unsere mehrsprachige Herausforderung können wir entweder das Skript für jede Sprachdomain ausführen oder eine Schleife in unser Skript einfügen.
Shopware speichert die Sitemaps im Ordner [PROJECTROOT]/public/sitemap/ . Bitte beachten Sie, dass dies in einer Cluster-Umgebung unterschiedlich sein kann. In einer einfachen Umgebung können wir aus diesem Pfad die Sitemaps parsen und einen wget für jede URL aus der Sitemap ausführen. Ein zusätzlicher Vorteil ist, dass Shopware für jede Sprache eine Sitemap generiert, was auch unsere Mehrsprachigkeit Herausforderung adressiert. Sie müssen jedoch sicherstellen, dass Ihre Sitemap regelmäßig generiert wird. Weitere Details finden Sie in der Shopware-Dokumentation:
Hier ist unsere zweite Version, die Sitemaps parst und den Cache aufwärmt.
#!/bin/bash
sitemap_dir="../../public/sitemap"
# Function to process sitemap gz files
process_sitemaps() {
find "$sitemap_dir" -type f -name "*.xml.gz" | while read -r gz_file; do
echo "## $(date '+%d.%m.%Y %H:%M:%S') ## Processing sitemap: $gz_file"
# Decompress the .gz file to a temporary location
tmp_file=$(mktemp)
gunzip -c "$gz_file" > "$tmp_file"
# Extract URLs from the decompressed XML file
urls=$(grep -oP '(?<=)[^<]+' "$tmp_file")
# Crawl all extracted URLs at once
if [ -n "$urls" ]; then
wget2 -r \
--no-parent \
--level=1 \
--tries=2 \
--timeout=5 \
--spider \
--delete-after \
--header "Accept-Encoding: br" \
--header "x-local-prewarm: Evasion4-Wow-Visibly" \
--user-agent=diga-cachewarming-client \
--wait=0.5 \
--reject '*.js,*.css,*.txt,*.gif,*.jpg,*.jpeg,*.png,*.mp4,*.webp,*.mp3,*.woff2,*.pdf,*.tgz,*.flv,*.avi,*.mpeg,*.iso,*.zip,*.svg' \
--ignore-tags=img,link,script \
--domains=local-devshop.de,local-devshop.com \
--robots=no \
--no-check-certificate \
$urls
fi
# Cleanup temporary file
rm -f "$tmp_file"
done
}
# Process all sitemap gz files
process_sitemaps
Mit der aktuellen Version können wir unsere mehrsprachige, mult Verkaufskanal Shopware-Installation einschließlich Varianten aufwärmen, was ziemlich gut ist, aber wir sind noch nicht fertig. Wenn wir mehrere Währungen anbieten und ein Kunde die Währung wechselt, zeigt uns Shopware erneut die kalte Schulter.
Um die Währung aufzuwärmen, müssen wir die URLs mit einem sw-currency-Header aufrufen.
--header "cookie: sw-currency=0193e9b2ea6770cfa26cc46dc2019230"
Um dies zu demonstrieren, habe ich unser Skript modifiziert, um eine einzelne Sitemap zu parsen und dann das Aufwärmen für GBP durchzuführen. Sie finden die Währungs-ID in Shopware, indem Sie zu: Admin -> Einstellungen -> Währungen -> Ihre Währung öffnen und die ID in der URL sehen.
- Währungs-ID-URL: http://localhost/admin#/sw/settings/currency/detail/0193e9b2ea6770cfa26cc46dc2019230
Mit diesen Informationen können wir nun ein Shell-Skript erstellen, um aufzuwärmen:
- Varianten
- Shops mit mehreren Sprachen
- Shops mit mehreren Währungen
Es gibt jedoch einige Punkte zu beachten, wenn Sie diesen Ansatz verfolgen:
- Das Ausführen dieses Skripts auf Ihrem Produktionsserver erzeugt zusätzliche Last.
- Ihr Server muss wget2 unterstützen.
- Möglicherweise müssen Sie zusätzliche Komponenten in Ihre Infrastruktur einbeziehen.
- Sie finden es möglicherweise herausfordernd, Shell-Skripte zu pflegen und zu verstehen, so wie ich es tue.
Aus diesem Grund habe ich auch nach anderen Ansätzen und Bibliotheken gesucht, um Websites zu crawlen. Die nächsten Abschnitte geben eine kurze Einführung in eine davon.
Alternative Crawlee
Es gibt mehrere Frameworks, Dienste und GitHub-Repositories für das Crawling einer Seite. Eines, das ich gefunden und ausprobiert habe, ist Crawlee. Es ist ein kostenloses Open-Source-Projekt, das einfach einzurichten war. Und es war einfach, einen ersten Crawler zu erstellen.
Persönlich finde ich es viel besser, TypeScript-Code zu schreiben, um komplexe oder spezielle Warmup-Szenarien für Kunden zu bewältigen, anstatt Shell-Skripte zu verwenden. Ich finde es auch cool dass Crawlee auf Playwright aufbaut. Mit Crawlee haben wir viel mehr Möglichkeiten. Zum Beispiel könnten wir anstelle des Lesens von einer veralteten Sitemap die URLs für das Warmup granularer über eine API von Shopware erhalten. Auf diese Weise werden unter anderem spezielle Warmups für stark frequentierte Kategorieseiten ermöglicht. Anstatt einen einfachen Crawler zu verwenden, könnten wir ein kundenspezifisches Shop-Projekt mit Crawlee implementieren.
Hier ist meine erste Version eines Store-Warmups basierend auf Sitemaps, die Sprachen und Währungs-Header berücksichtigt.
// For more information, see https://crawlee.dev/
import { PlaywrightCrawler, Sitemap } from 'crawlee';
// Define the sitemaps and associated headers
const sitemaps = [
{
// Default EURO
url: 'https://local-devshop.de/en/sitemap.xml'
},
{
// Default EURO
url: 'https://local-devshop.de/sitemap.xml',
},
{
url: 'https://local-devshop.com/sitemap.xml'
},
{
url: 'https://local-devshop.de/sitemap.xml',
headersList: [
//Pfund
{ 'cookie': 'sw-currency=0193e9b2ea6770cfa26cc46dc2019230' },
// US-Dollar
{ 'cookie': 'sw-currency=0193e9b2ea6770cfa26cc46dc1df9aad' },
],
},
{
url: 'https://local-devshop.de/en/sitemap.xml',
headersList: [
//Pfund
{ 'cookie': 'sw-currency=0193e9b2ea6770cfa26cc46dc2019230' },
// US-Dollar
{ 'cookie': 'sw-currency=0193e9b2ea6770cfa26cc46dc1df9aad' },
],
}
];
// PlaywrightCrawler crawls the web using a headless
// browser controlled by the Playwright library.
const crawler = new PlaywrightCrawler({
// Function called for each URL SITEMAP TEST!!
async requestHandler({ request, log }) {
log.info(request.url);
},
preNavigationHooks: [
async ({ request, page, log }) => {
if (request.headers) {
log.info(`Setting headers for ${request.url} to ${JSON.stringify(request.headers)}`);
await page.setExtraHTTPHeaders(request.headers);
}
},
],
// Uncomment this option to see the browser window.
// headless: false,
launchContext: {
launchOptions: {
ignoreHTTPSErrors: true, // This bypasses certificate errors
},
},
});
(async () => {
for (const { url, headersList } of sitemaps) {
const { urls } = await Sitemap.load(url);
if (!urls || urls.length === 0) {
continue;
}
if (!headersList) {
// Add all URLs without headers
await crawler.addRequests(urls.map((pageUrl) => ({ url: pageUrl })));
} else {
// Add URLs with specific headers and unique keys
for (const headers of headersList) {
for (const pageUrl of urls) {
await crawler.addRequests([
{
url: pageUrl,
headers,
uniqueKey: `${pageUrl}-${JSON.stringify(headers)}`, // Ensure uniqueness
},
]);
}
}
}
}
// Run the crawler
await crawler.run();
})();
Unsere nächste Aufgabe besteht nun darin, herauszufinden, wie wir Crawlee am besten in einer Cloud-Umgebung bereitstellen oder auf einem Server hosten können. Außerdem möchte ich mein Crawlee-Projekt als Azure-Funktion ausführen, da dies mir eine einfach zu verwendende Zeitsteuerung bietet, die perfekt ist, um meine Warmup-Routine geplant auszuführen.
Problem beim Ausführen von Crawlee auf Windows 11, wmic fehlt
Ich hatte ein Problem, Crawlee unter Windows 11 auszuführen und musste WMIC aus den optionalen Funktionen aktivieren, danach hat alles andere funktioniert.
Zusammenfassung
Das effektive Aufwärmen des HTTP-Caches in Shopware 6 erfordert einen durchdachten Ansatz, insbesondere beim Umgang mit mehreren Verkaufskanälen, Sprachen und Währungen. Der anfängliche Versuch mit wget2 lieferte tiefe Einblicke in das Caching, reichte jedoch nicht aus, weil Shopware Formularübermittlungen statt Links verwendet, sodass wir wget ohne eine Sitemap nicht verwenden können. Das erweiterte Skript, das Sitemaps analysiert und Währungs-Header einbezieht, bietet eine umfassendere Lösung. Es ist jedoch wichtig, Ihre Infrastruktur und die Notwendigkeit einer regelmäßigen Sitemap-Generierung zu berücksichtigen.
Für diejenigen, die Schwierigkeiten mit dem Shell-Scripting haben, könnte es vorteilhaft sein, alternative Crawling-Bibliotheken zu erkunden. Das Warmhalten Ihres Caches ist entscheidend, um optimale Leistung aufrechtzuerhalten und schnelle Reaktionszeiten vom Server für die Benutzer zu gewährleisten.
Änderungen ab Shopware 6.5.8.0:
- Entfernung des Objekt-Caches.
- Vereinfachung der Cache-Schlüssel-Permutation.
- Verbesserte Cache-Invalidierung durch verzögerte Invalidierung und Soft-Purge.
- Einführung von ESI-Tags für Teile der Seite (z.B. Header, Footer).
Abkündigung des HTTP Cache Warmers:
- bin/console http:cache:warm:up funktioniert ab Version 6.5.8.0 nicht mehr
Verwendung von wget zum Aufwärmen des Caches:
- Shell-Skripte mit wget2 wurden verwendet, um den Cache aufzuwärmen.
- wget2 folgt nur Links, aber Shopware verwendet Formularübermittlungen für Varianten und Sprachwechsel.
- Verwendung der Sitemap, um alle URLs einschließlich Varianten zu erhalten
- Wichtig: Regelmäßige Sitemap-Generierung ist erforderlich
- Weiterhin sind zusätzliche Header erforderlich, um verschiedene Währungen aufzuwärmen
Alternative: Crawlee:
- Crawlee ist ein Open-Source-Projekt, basierend auf Playwright.
- Bietet mehr Flexibilität und Möglichkeiten als Shell-Skripte.
- Erlaubt granulare URL-Sammlung und spezielle Aufwärmszenarien.
Untersuchung, ob wir einen Cache-Hit oder Cache-Miss haben:
- Symfony-Werkzeugleiste (nur im Entwicklungsmodus verwenden!)
- Shopware Cache Helper: ditegra-GmbH/DigaShopwareCacheHelper