Erzwingen Sie, dass die Anforderung den Cache verpasst, aber die Antwort trotzdem speichert

7

Ich habe eine langsame Web-App, vor der ich Varnish platziert habe. Alle Seiten sind statisch (sie variieren nicht für einen anderen Benutzer), müssen jedoch alle 5 Minuten aktualisiert werden, damit sie aktuelle Daten enthalten.

Ich habe ein einfaches Skript ( wget --mirror), das alle 15 Minuten die gesamte Website crawlt. Jeder Crawl dauert ungefähr 5 Minuten. Der Zweck des Crawls besteht darin, jede Seite im Lack-Cache zu aktualisieren, damit ein Benutzer nie auf die Generierung der Seite warten muss (da alle Seiten kürzlich dank der Spinne generiert wurden).

Die Zeitleiste sieht folgendermaßen aus:

  • 00:00:00: Cache geleert
  • 00:00:00: Spider beginnt zu crawlen, um den Cache mit neuen Seiten zu aktualisieren
  • 00:05:00: Spider beendet das Crawlen , alle Seiten werden bis 00:15:00 aktualisiert

Eine Anfrage, die zwischen 0:00:00 und 0:05:00 eingeht, trifft möglicherweise auf eine Seite, die noch nicht aktualisiert wurde, und muss einige Sekunden auf eine Antwort warten. Das ist nicht akzeptabel.

Was ich tun möchte, ist, vielleicht mit etwas VCL-Magie, immer Anfragen von der Spinne an das Backend weiterzuleiten, aber die Antwort trotzdem im Cache zu speichern. Auf diese Weise muss ein Benutzer niemals auf die Generierung einer Seite warten, da es kein 5-Minuten-Fenster gibt, in dem Teile des Caches leer sind (außer möglicherweise beim Serverstart).

Wie kann ich das machen?

Tom Marthenal
quelle

Antworten:

10

req.hash_always_miss sollte den Trick machen.

Führen Sie zu Beginn des Spinnenlaufs keinen vollständigen Cache-Flush durch. Stellen Sie stattdessen einfach die Spinne auf Funktion ein - und stellen Sie in Ihrem vcl_recvdie Spinnenanforderungen ein, um die Cache-Suche immer zu verpassen. Sie holen eine neue Kopie aus dem Backend.

acl spider {
  "127.0.0.1";
  /* or whereever the spider comes from */
}

sub vcl_recv {
  if (client.ip ~ spider) {
    set req.hash_always_miss = true;
  }
  /* ... and continue as normal with the rest of the config */
}

Während dies geschieht und bis sich die neue Antwort im Cache befindet, erhalten Clients weiterhin nahtlos den älteren Cache, der ihnen bereitgestellt wird (solange er sich noch in der TTL befindet).

Shane Madden
quelle
Danke für die Antwort; Ich war mitten in der Eingabe der Lösung, die ich gefunden hatte, als ich Ihre Antwort sah. Ihre ist eindeutig besser als meine (und ich benutze Ihre bereits). Können Sie sich meine Antwort ansehen und mir Probleme damit mitteilen, damit ich lernen kann?
Tom Marthenal
2

Die Antwort von Shane oben ist besser als diese. Dies ist eine alternative Lösung, die komplizierter ist und zusätzliche Probleme aufweist. Bitte stimmen Sie der Antwort von Shane zu, nicht dieser. Ich zeige nur eine andere Methode zur Lösung des Problems.


Mein erster Gedanke war, return (pass);in vcl_recvund nach der Anfrage abgerufen wurde, in vcl_fetchirgendwie anweisen Varnish , dass es sollte die Objekt - Cache, auch dachte , es speziell früher übergeben wurde.

Es stellt sich heraus, dass dies nicht möglich ist :

Wenn Sie die Anforderung in einer früheren VCL-Funktion übergeben haben (z. B. vcl_recv), führen Sie die Logik von vcl_fetch weiterhin aus, aber das Objekt wird nicht in den Cache eingegeben, selbst wenn Sie eine Cache-Zeit angeben.

Das nächstbeste ist also, eine Suche wie bei einer normalen Anforderung auszulösen, aber stellen Sie sicher, dass sie immer fehlschlägt. Es gibt keine Möglichkeit, den Suchprozess zu beeinflussen, daher wird er immer getroffen (vorausgesetzt, er wird zwischengespeichert; wenn nicht, wird er trotzdem fehlen und gespeichert). Aber wir können beeinflussen vcl_hit:

sub vcl_hit {
    # is this our spider?
    if (req.http.user-agent ~ "Wget" && client.ip ~ spider) {
        # it's the spider, so purge the existing object
        set obj.ttl = 0s;
        return (restart);
    }

    return (deliver);
}

Wir können es nicht erzwingen, den Cache nicht zu verwenden, aber wir können dieses Objekt aus dem Cache löschen und den gesamten Prozess neu starten. Jetzt geht es zurück zum Anfang vcl_recv, wo es schließlich eine weitere Suche durchführt. Da wir das Objekt, das wir aktualisieren möchten, bereits gelöscht haben, wird es fehlen, dann die Daten abrufen und den Cache aktualisieren.

Ein bisschen kompliziert, aber es funktioniert. Das einzige Fenster, in dem ein Benutzer zwischen einer Bereinigung und der gespeicherten Antwort stecken bleibt, ist die Zeit, die die einzelne Anforderung verarbeitet. Nicht perfekt, aber ziemlich gut.

Tom Marthenal
quelle
1
Ja, das sollte funktionieren! Eine zusätzliche Möglichkeit, die Sie ausführen können, um zu verhindern, dass ein Benutzer aufgrund der Lücke zwischen Löschen und erneuter Cache eine langsame Antwort erhält, besteht darin, einen kurzen Zeitgeber für den Kulanzmodus festzulegen. Da der Neustart ausgelöst wurde, hat Varnish bereits eine Anforderung für den Inhalt in Bearbeitung. Der Grace-Modus startet und liefert den veralteten Inhalt nach seiner TTL, anstatt auf das Ende der Anfrage der Spinne zu warten.
Shane Madden
@ShaneMadden, danke für den Hinweis zum Gnadenmodus - ich versuche immer noch, den Dreh raus zu bekommen und hatte noch nichts davon gehört. Ihre Lösung ist immer noch deutlich besser, aber ich schätze die Gelegenheit, mehr über Lack zu erfahren.
Tom Marthenal