Consenti alla vernice di inviare vecchi dati dalla cache mentre ne sta recuperando uno nuovo?


8

Sto memorizzando nella cache pagine generate dinamicamente (PHP-FPM, NGINX) e ho una vernice davanti a loro, questo funziona molto bene.

Tuttavia, una volta raggiunto il timeout della cache, vedo questo:

  • nuova pagina di richieste client
  • varnish riconosce il timeout della cache
  • il cliente aspetta
  • la vernice recupera la nuova pagina dal backend
  • varnish consegna una nuova pagina al client (e ha anche una pagina memorizzata nella cache per la prossima richiesta che la ottiene immediatamente)

Quello che vorrei fare è:

  • pagina delle richieste del cliente
  • la vernice riconosce il timeout
  • La vernice consegna la vecchia pagina al client
  • varnish recupera la nuova pagina dal backend e la inserisce nella cache

Nel mio caso non è un sito in cui le informazioni obsolete sono un problema così grande, soprattutto quando parliamo di timeout della cache da pochi minuti.

Tuttavia, non desidero punire l'utente in attesa in linea e piuttosto fornire qualcosa di immediato. È possibile in qualche modo?

Per illustrare, ecco un output di esempio di esecuzione dell'assedio 5 minuti sul mio server che è stato configurato per la cache per un minuto:

HTTP/1.1,200,  1.97,  12710,/,1,2013-06-24 00:21:06
...
HTTP/1.1,200,  1.88,  12710,/,1,2013-06-24 00:21:20
...
HTTP/1.1,200,  1.93,  12710,/,1,2013-06-24 00:22:08
...
HTTP/1.1,200,  1.89,  12710,/,1,2013-06-24 00:22:22
...
HTTP/1.1,200,  1.94,  12710,/,1,2013-06-24 00:23:10
...
HTTP/1.1,200,  1.91,  12709,/,1,2013-06-24 00:23:23
...
HTTP/1.1,200,  1.93,  12710,/,1,2013-06-24 00:24:12
...

Ho lasciato fuori le centinaia di richieste in esecuzione 0.02circa. Ma mi preoccupa ancora che ci saranno utenti che dovranno attendere quasi 2 secondi per il loro codice HTML non elaborato.

Non possiamo fare di meglio qui?

(Mi sono imbattuto in Varnish send mentre cache , sembrava simile ma non esattamente quello che sto cercando di fare.)

Soluzione

La risposta di Shane Madden conteneva la soluzione ma non me ne accorsi subito. C'era un altro dettaglio che non avevo incluso nella mia domanda perché pensavo non fosse rilevante, ma in realtà lo è.

La soluzione CMS che sto attualmente utilizzando ha un listener di database di vernici e quindi ha la capacità di notificare a vern per vietare le pagine il cui contenuto è cambiato. Ha inviato una PURGErichiesta con qualche regex per vietare determinate pagine.

Per riassumere, ci sono due casi in cui ho avuto utenti sfortunati:

  1. la vernice normale TTL di una pagina scade
  2. gli utenti backend cambiano contenuto, questo invia una richiesta di spurgo alla vernice

In entrambi i casi ho utenti "sfortunati". Nel secondo caso è alleviato dal fatto che gli utenti backend di solito controllano la pagina dopo che è stata modificata; ma non necessariamente.

Tuttavia, per il secondo caso ho creato una soluzione (sì, mi rendo conto che questa domanda è iniziata con la ricerca di una risposta per il primo caso ... domanda mal formulata da parte mia):

Invece di inviare una richiesta di eliminazione, ho usato il suggerimento di Shanes e ho modificato il VCL in modo che il mio listener di database di vernici possa inviare una richiesta speciale per recuperare una pagina con hash_always_missset su true.

Con l'architettura attuale non ho davvero il lusso di fare una vera richiesta asincrona, ma con l'aiuto di Come faccio a fare una richiesta GET asincrona in PHP? Sono stato in grado di creare una richiesta GET per la vernice che non aspetta il caricamento della pagina ma è abbastanza buona da innescare la vernice per recuperare la pagina dal back-end e memorizzarla nella cache.

L'effetto netto è stato che l'ascoltatore di database ha inviato la richiesta di vernice e mentre eseguivo il polling della pagina specifica non ha mai reso le mie richieste "sfortunate", ma una volta che la vernice ha recuperato la pagina completamente dal backend (questo può variare da 300 ms a 2 secondi) improvvisamente era lì.

Devo ancora trovare una soluzione su come evitare gli stessi problemi quando si esaurisce il normale TTL, ma immagino che la soluzione sia anche esattamente come suggerisce Shane: usando wget per innescare hash_always_miss, dovrò solo essere abbastanza intelligente per ottenere l'elenco di pagine che devo aggiornare.

Risposte:


3

La soluzione che ho usato per risolvere questo problema è assicurarsi che il TTL su una pagina non abbia mai una possibilità di scadere prima di essere aggiornato - forzando un client HTTP in esecuzione su uno dei miei sistemi a ottenere il carico lento invece di un client sfortunato richiesta.

Nel mio caso, ciò implica wgetun cron, l'invio di un'intestazione speciale per contrassegnare le richieste e l'impostazione req.hash_always_missbasata su questo, forzando una nuova copia del contenuto da recuperare nella cache.

acl purge {
    "localhost";
}

sub vcl_recv {
    /* other config here */
    if (req.http.X-Varnish-Nuke == "1" && client.ip ~ purge) {
        set req.hash_always_miss = true;
    }
    /* ... */
}

Per i tuoi contenuti, questo potrebbe significare impostare il Varnish TTL su qualcosa come 5 minuti ma avere un wget cron configurato per fare una richiesta di aggiornamento della cache ogni minuto.


Penso di capire cosa intendi. Funzionerebbe bene per una singola pagina, ma le altre migliaia? Non è possibile utilizzare cron / wget su quella scala.
segna il

Intrinsecamente, devi dichiarare almeno quali pagine vuoi mantenere aggiornate nella cache. Dato questo elenco non c'è motivo per cui wget in uno script cron non possa aiutarti.
Falcon Momot,

Penso che sia la sfida con questo "approccio esterno alla vernice". Alla fine ho bisogno di sedermi, prendere una decisione e implementare questo per ogni pagina. Non c'è modo di dire alla vernice: "ttl si è esaurito? Recupera la nuova versione ma fino a quando non è successo serve quella vecchia" ...? Hmm.
segna il

4

@MODIFICARE:

Solo uno veloce per farti sapere che questa funzione sembra essere stata appena implementata nell'ultima versione nel ramo principale, è probabile che la tua versione potrebbe non supportare ancora vero stantio-mentre-riconvalida / l'esempio che ho pubblicato sarebbe servito 9999/10000 richieste con un pessimo bugger che devono ancora attendere che la richiesta venga completata nel backend (ancora meglio di niente;) ...


Beh, non sono sicuro al 100% del motivo per cui i commenti precedenti dicono che non funziona ma secondo: https://www.varnish-software.com/static/book/Saving_a_request.html

  • req.grace - definisce il tempo di attesa di un oggetto affinché Varnish lo consideri ancora per la modalità grazia.
  • beresp.grace - definisce per quanto tempo la vernice beresp.ttl-time manterrà un oggetto.
  • req.grace - viene spesso modificato in vcl_recv in base allo stato del backend.

Attualmente sto usando la configurazione come dice il manuale e sta funzionando bene ... Ecco uno snippet del mio file vcl ...

sub vcl_recv {
    # Cache rules above here...
    if (req.backend.healthy) {
        set req.grace = 30d;
    } else {
        set req.grace = 300d;
    }
}

sub vcl_fetch {
    # Fetch rules above here ...

    # If backend returns 500 error then boost the cache grace period...
    if (beresp.status == 500) {
        set beresp.grace = 10h;
        return (restart);
    }

    # How long carnish should keep the objects in cache..
    set beresp.grace = 1h;

    # Actual TTL of cache - If an object is older than this an update will be triggered to the backend server :)
    set beresp.ttl = 1m;
}

Si noti che se si desidera fornire un periodo di tolleranza più lungo per la risposta del back-end (per errore 500 come nella mia configurazione) è necessario impostare il sondaggio back-end ... Ecco una copia della mia sonda back-end ..

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = { 
        .url = "/nginx-status";
        .timeout = 500 ms; 
        .interval = 3s; 
        .window = 10;
        .threshold = 4;
    }
}

è ancora valido per vcl 4.0?
Gadelkareem,

0

In Varnish 3 questo si ottiene tramite "Modalità Grace". Secondo il manuale [1], è necessario aggiungere la seguente logica:

sub vcl_fetch {
  set beresp.grace = 30m;
} // Makes objects to be cached/stored 30 min beyond its max-age/ttl

sub vcl_recv {
  set req.grace = 60s;
} // Allows varnish to serve objects which expired within last minute.

[1] https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode


Ciò non raggiungerà l'obiettivo di OP, un cliente rimarrà comunque in ritardo in attesa che il contenuto venga recuperato dal back-end, anche se gli altri client dietro quello riceveranno il risultato di grazia scaduta. "Una volta scaduto il TTL, il primo client che richiede il contenuto dovrebbe essere bloccato per 15 secondi, mentre il secondo client dovrebbe ottenere la copia gradita." - varnish-software.com/static/book/Saving_a_request.html
Pax

Spiacenti, non ho capito come funziona effettivamente con la prima richiesta scaduta.
NITEMAN,

Forse l'obiettivo desiderato può essere raggiunto con un po 'di cheat ttl e inline C al fine di lanciare una "richiesta di background"
NITEMAN
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.