Fastly mithilfe von GCP Cloud-Funktionen bereinigen
Häufig verwenden Kunden statische Objektspeicher wie Google Cloud Storage (GCS) als Backend für Fastly Services.Da sich Inhalte in diesen Speicherbehältern nicht oft ändern, kann Fastly üblicherweise lange Zeit cachen.Das ist zwar gut für die Performance, aber wie sorgen Sie dafür, dass eine Änderung für die Endnutzer schnell sichtbar ist, falls sich doch einmal etwas ändert?
Dies ist ein generelles Problem bei Inhalten, die sich nicht regelmäßig ändern. Oft besteht die Lösung darin, eine sehr kurze Cache-TTL im CDN einzustellen oder den gesamten CDN-Cache manuell zu bereinigen. Das bedeutet jedoch, dass Nutzer möglicherweise stunden- oder sogar tagelang alte Inhalte auf Ihrer Website sehen, bevor der CDN-Cache mit den neuesten Websiteinhalten aktualisiert ist.
Glücklicherweise bietet Fastly Instant Purge, das den gesamten Cache, einzelne Dateien und sogar Dateigruppen, die durch gemeinsame Tags (die wir Surrogate Keys nennen) identifiziert werden, innerhalb von wenigen Millisekunden invalidiert.Google Cloud Storage ermöglicht Ereignisse, die Cloud-Funktionen auslösen können – ein weiteres GCP Produkt, das zustandslose Logik on-demand ausführt.Wenn Sie diese Funktionen miteinander verbinden, kann die Edge-Cloud-Plattform von Fastly sofort und selektiv bereinigt werden, um sicherzustellen, dass Nutzer die aktualisierten Inhalte sofort sehen, selbst wenn die Objekte eine sehr lange Cache-Lebensdauer haben.
In diesem Beitrag zeige ich Ihnen, wie Sie die beiden miteinander verbinden und Ihr eigenes GCS Backend so konfigurieren können, dass es Fastly bereinigt, wenn Sie Ihre Inhalte ändern.
Bitte beachten Sie, dass die Ausführung der in diesem Beitrag beschriebenen Schritte dazu führen kann, dass Ihnen bei Google Gebühren entstehen.
So funktioniert’s
Das ist unser Ziel:
Ein Nutzer fordert eine Ressource von Ihrer Website an. Fastly holt sie aus Ihrem GCS Backend und cacht sie für eine lange Zeit auf der Edge (üblicherweise ein Jahr).
Sie aktualisieren diese Ressource, indem Sie eine neue Version im GCS hochladen.
Daraufhin wird ein GCS Ereignis ausgelöst, das eine Cloud-Funktion ausführt.
Die Funktion sendet eine Anfrage an die Fastly API, die Fastly anweist, das Objekt (die Ressource) zu invalidieren.
Ein anderer Endnutzer stellt dieselbe Anfrage.Fastly ignoriert das Objekt im Cache und holt stattdessen die neue Version aus dem GCS ab.
An dieser Stelle sollte erwähnt werden, dass die oben in Schritt 4 erwähnte Bereinigungsanfrage die Ressource normalerweise nicht aus dem Cache von Fastly löscht, sondern sie stattdessen als veraltet markiert. Dies ist insofern hilfreich, als Sie möglicherweise die Cache-Direktiven stale-while-revalidate oder stale-if-error verwenden möchten. Wenn Sie dies jedoch nicht tun, ist die Markierung eines Objekts als veraltet gleichbedeutend mit dessen Löschung.
Erste Schritte
Ich gehe davon aus, dass Sie bereits einen Fastly Service und ein Google Cloud Konto für ein Projekt haben, das einen GCS Bucket mit Ihren Dateien enthält. Dieser Bucket ist:
als Backend für Ihren Fastly Service eingerichtet.
Um diese miteinander verbinden zu können, müssen Sie auch die Cloud-Funktionen-API aktivieren.Hierfür ist es ratsam, Cloud SDK auf Ihrem System zu installieren und sicherzustellen, dass es auf dem neuesten Stand ist, damit Sie die gsutil
-CLI-Befehle ausführen können. Sie können aber auch auf Schaltflächen in der GCP Konsole klicken, wenn Ihnen das lieber ist.
Eine wichtige Voraussetzung ist, dass Sie das im GCS integrierte Caching deaktivieren. Legen Sie dazu die Objekt-Metadaten fest, wenn Sie das Objekt in den Bucket hochladen:
gsutil -m \
-h "Cache-Control: public, max-age=0" \
cp -r ~/[PATH_TO_CONTENT]/* gs://[BUCKET_NAME]
Sie können auch den Befehl setmeta verwenden, um die Objekt-Metadaten für bereits hochgeladene Objekte zu aktualisieren.
Wenn Sie den Bucket zum Zwecke dieses Tutorials einrichten, können Sie an dieser Stelle pausieren, um zu testen, ob Sie über HTTP auf die Probedatei zugreifen können:
curl -i "https://[BUCKET_NAME].storage.googleapis.com/[FILE_PATH]"
Sie sollten die HTTP-Header der Antwort zusammen mit dem Inhalt der von Ihnen hochgeladenen Datei sehen.Achten Sie insbesondere auf content-type
und cache-control
. Wenn diese nicht korrekt sind, korrigieren Sie sie wie oben beschrieben mithilfe von Objekt-Metadaten.Wenn Sie eine 403 Forbidden
-Fehlermeldung erhalten, überprüfen Sie, ob Ihr Bucket öffentlich zugänglich ist.
Eine konstante TTL für Fastly einrichten
Da alle von Fastly gecachten Objekte invalidiert werden, sobald sich diese ändern, kann die Cache-Lebensdauer aller Objekte identisch und für einen sehr langen Zeitrahmen eingerichtet sein. Wenn Sie Ihren Fastly Service in dieser Hinsicht nicht schon konfiguriert haben, können Sie mit den folgenden Schritten eine konstante TTL einrichten:
Klicken Sie im Abschnitt Konfiguration der Fastly Konsole auf Klonen, um eine bearbeitbare Version Ihres Services zu erstellen.
Wählen Sie in der Seitenleiste Einstellungen.
Klicken Sie auf Richten Sie Ihre erste Cache-Einstellung ein.
Geben Sie bei Name einen geeigneten Namen ein, beispielsweise „TTL auf ein Jahr setzen“.
Setzen Sie TTL (Sekunden) dann auf „31536000“ (dies entspricht einem Jahr in Sekunden).
Klicken Sie auf Einrichten.
Klicken Sie auf Aktivieren, um die aktualisierte Konfiguration auf Ihren Fastly Service anzuwenden.
Cloud-Funktion einrichten
Als Nächstes nehmen wir die Konfigurierung der Cloud-Funktion vor. Sie können sie auf Ihrem lokalen Rechner programmieren und mit dem Cloud SDK von Google bereitstellen. Zum Zwecke dieses Tutorials verwenden wir allerdings die Nutzeroberfläche. Starten Sie in der Cloud-Funktionskonsole und klicken Sie auf Funktion einrichten.
Wählen Sie einen Namen (wie „Fastly bereinigen“), legen Sie als Auslöser „Cloud Storage“ und als Event „Abschließen/einrichten“ fest (dazu müssen Sie den GCS Bucket, in dem Ihre Dateien gespeichert sind, durchsuchen und auswählen).
Geben Sie mithilfe des Inline-Editors den folgenden Code ein:
const fetch = require('node-fetch');
const FASTLY_PUBLIC_BASEURL = "https://www.example.com";
exports.fastlyPurge = async (obj, context) => {
const baseUrl = FASTLY_PUBLIC_BASEURL.replace(/\/+$/, '');
const fileName = obj.name.replace(/^\/+/, '');
const completeObjectUrl = `${baseUrl}/${fileName}`;
const resp = await fetch(completeObjectUrl, { method: 'PURGE'})
if (!resp.ok) throw new Error('Unexpected status ' + resp.status);
const data = await resp.json();
console.log(`Job complete for ${fileName}, purge ID ${data.id}`);
};
Die einzige Abhängigkeit, die wir hier verwenden, ist das Modul node-fetch, um HTTP-Anfragen etwas einfacher und vertrauter zu machen.Wechseln Sie zur Registerkarte package.json
und fügen Sie es als Abhängigkeit hinzu:
"dependencies": {
"@google-cloud/storage": "^1.6.0",
"node-fetch": "^2.6.0"
}
Zum Schluss setzen Sie die Funktion, die aufgerufen werden soll, auf fastlyPurge
und speichern Ihre Arbeit ab.
Es wird etwa eine Minute dauern, bis GCP Ihre Funktion geladen hat und sie aktiviert ist. Das war's auch schon! Immer wenn Sie Dateien in Ihrem GCS Bucket ändern, wird GCP Fastly in einer Benachrichtigung dazu anweisen, alle gecachten Kopien dieser Dateien von unseren Servern zu löschen. Dies dauert im Durchschnitt 150 Millisekunden (Stand: 31. Dezember 2019) für die gesamte Edge Cloud.
Testen
Überprüfen Sie zunächst, ob das Objekt von Fastly gecacht wird, indem Sie die folgende Anfrage wiederholt ausführen:
curl -is "https://your.fastly.domain/file/path" 2>&1 | grep -i "x-cache:"
Auf diese Weise sehen Sie den X-Cache
-Header der HTTP-Antwort, der durchgängig „HIT“ oder „HIT-CLUSTER“ anzeigen sollte (mit möglicherweiwe einem „MISS“ am Anfang):
x-cache: MISS
x-cache: HIT
x-cache: HIT
x-cache: HIT
Nehmen Sie nun eine Änderung an der Datei vor und laden Sie sie erneut in Ihren Bucket hoch.Das können Sie mit gsutil
tun (oder die Bucket-Explorer-Nutzeroberfläche verwenden, wenn Sie bevorzugen):
gsutil -m -h "Content-Type:text/css" -h "Cache-Control:public, max-age=0" cp -r ~/path-to-content/* gs://[BUCKET_NAME]
Führen Sie den cURL-Befehl erneut aus, um das Objekt von Fastly abzufragen. Wenn Sie dies zum ersten Mal abfragen, fällt die Antwortzeit vermutlich etwas länger aus und der X-Cache
zeigt „MISS“ oder „MISS-CLUSTER“.
Noch wichtiger zu sehen ist jedoch, dass sich die Datei geändert hat und die Änderung widerspiegelt, die Sie in Ihren Bucket hochgeladen haben (entfernen Sie den | grep-Teil des cURL-Befehls, um den Inhalt der Antwort sichtbar zu machen).
Den Code verstehen
Die Funktion wird mit den Begriffen obj
und context
aufgerufen.Ersterer ist ein Cloud-Storage-Objekt, Letzterer liefert Metadaten über das Ereignis.Die einzige Eigenschaft, die uns an diesen Begriffen interessiert, ist die Eigenschaft obj.name
. Sie enthält den Namen des Objekts, das im GCS Bucket erstellt, aktualisiert oder gelöscht wurde.Außerdem müssen wir auch wissen, über welche Domain Sie das Objekt in Ihrem Fastly Service bereitstellen, damit wir eine vollständige, für Fastly sinnvolle URL für das Objekt erstellen können:
const baseUrl = FASTLY_PUBLIC_BASEURL.replace(/\/+$/, '');
const fileName = obj.name.replace(/^\/+/, '');
const completeObjectUrl = `${baseUrl}/${fileName}`;
Bereinigungen für einzelne URLs werden in der API von Fastly als Sonderfall behandelt, da die Anfrage an die zu bereinigende URL und nicht an einen Fastly Endpunkt gesendet wird.Wir verwenden die Bibliothek „node-fetch“, um die Anfrage mittels der HTTP-Methode PURGE zu senden und die vom Fastly Server zurückgegebene Purge-ID zu melden.Falls Sie Hilfe vom Fastly Support benötigen, ist es sinnvoll, diese ID anzugeben.
const resp = await fetch(completeObjectUrl, { method: 'PURGE'})
const data = await resp.json();
console.log(`Job complete for ${fileName}, purge ID ${data.id}`);
Fehlersuche
Wenn sich die von Fastly bereitgestellte Datei nicht ändert, nachdem Sie sie bearbeitet und in das GCS hochgeladen haben, finden Sie hier einige Tipps zur Fehlersuche:
Erfolgreich hochgeladen?
Fordern Sie das Objekt direkt aus dem Bucket an und umgehen Sie Fastly, um sehen zu können, ob es sich im GCS geändert hat:
curl -i "https://[BUCKET_NAME].storage.googleapis.com/[PATH]"
Wenn dies nicht der Fall ist, könnte das Problem mit dem Hochladen der aktualisierten Datei in den Bucket oder mit dem im GCS integrierten Caching zusammenhängen. Wenn es sich geändert hat, liegt das Problem möglicherweise bei Ihrer Cloud-Funktion.
Wurde die Cloud-Funktion ausgeführt?
Überprüfen Sie Ihre Stackdriver-Protokolle, um herauszufinden, ob die Funktion korrekt ausgelöst wurde:
Rufen Sie die Google Cloud Funktionskonsole auf.
Klicken Sie auf den Namen der Funktion, den Sie erstellt haben.
Klicken Sie oben auf der Seite auf Protokolle anzeigen.
Überprüfen Sie den Zeitstempel des letzten Protokolleintrags und vergleichen Sie ihn mit dem Zeitpunkt, zu dem Sie Ihre Änderung in den Bucket hochgeladen haben.
Hat die API-Anfrage funktioniert?
Wenn die Protokolle zeigen, dass die Funktion aktiviert war, als Sie die Datei im Bucket aktualisiert haben, werfen Sie einen Blick auf den Inhalt der Protokolle, um zu prüfen, ob Fastly die Bereinigungsanfrage bestätigt hat. Im besten Fall sehen Sie:
Function execution started
Job complete for sample.css, purge ID 17953-1516801745-2111226
Function execution took 683 ms, finished with status: 'ok'
Wenn Sie diese Meldung nicht sehen, kann stattdessen ein Fehler protokolliert worden sein. Falls Sie weitere Hilfe benötigen, können Sie sich jederzeit in unserem Community-Forum oder per E-Mail unter support@fastly.com an uns wenden.
Nächste Schritte
Herzlichen Glückwunsch, jetzt haben Sie einen grundlegenden GCS Bucket, der von Fastly bei Änderung mit sofortiger Invalidierung bereitgestellt wird! Wie geht es nun weiter?
Liefern Sie eine ganze statische Website aus, nicht nur einzelne Assets.Obiger Vorgang funktioniert gut für Assets, aber für eine komplette Website benötigen Sie einen Standardverzeichnisindex (z. B.„index.html“), der für Verzeichnisanfragen verwendet werden kann, sowie eine Datei, die für „404 not found“-Fehler genutzt werden kann.Sie können dies auf der Google Cloud Platform tun, indem Sie Ihrem GCS Bucket eine nutzerdefinierte Domain zuweisen, oder bei Fastly, indem Sie einige zusätzliche Fastly VCL-Codezeilen schreiben.
Authentifizieren Sie den Zugriff auf GCS.Anstatt den öffentlichen Lesezugriff auf Ihren Bucket zuzulassen, erstellen Sie einen IAM-Nutzer, weisen Sie ihm die Rolle Storage Object Viewer zu und befolgen Sie unsere Anweisungen zum Generieren von „Token pro Anfrage“ für GCS.
Entfernen Sie alle x-goog-Header.Google fügt der HTTP-Antwort, die Sie von der Google Cloud Platform erhalten, eine Vielzahl von Headern hinzu.Um diese zu entfernen, können Sie entweder Ihrem Bucket eine nutzerdefinierte Domain zuweisen, die das statische Website-Hosting im GCS aktiviert, oder Ihren Fastly Service so konfigurieren, dass er sie für Sie entfernt.
Authentifizieren Sie Bereinigungen.Im unveränderten Zustand kann jeder eine HTTP-Anfrage an Ihre öffentliche Fastly Domain senden, um ein Element aus dem Cache zu bereinigen.Wenn Sie darüber besorgt sind und Ihre Cloud-Funktion authentifizieren möchten, sodass ausschließlich sie Bereinigungssignale senden kann, generieren Sie ein API-Token von Fastly mit Bereinigungsfunktion für Ihren Service, aktivieren Sie die authentifizierte Bereinigung und ändern Sie den Code Ihrer Cloud-Funktion so ab, dass ein
Fastly Key
Header mit dem Wert gesendet wird, der auf das von Ihnen generierte API-Token abgestimmt ist.Drücken Sie die Orchestrierung in Code aus.Erwägen Sie die Verwendung des HashiCorp Terraform Tools, um die Konfiguration der Google Cloud Platform und des Fastly Services in einer Datei zu erfassen, die Sie in der Versionskontrolle speichern können.
Ich bin in diesem Blogpost ziemlich ins Detail gegangen, aber im Grunde genommen beschränkt sich die Benachrichtigung über Änderungen an Ihren GCS Buckets auf eine einzige Codezeile in einer sehr einfachen Cloud-Funktion. Eine solch elegante Integration kann den Unterschied hinsichtlich der Performance und Effizienz Ihrer Website ausmachen und sowohl die Rendering-Zeit für Ihre Endnutzer als auch Ihre Google Rechnung für ausgehenden Datentransfer reduzieren.