Permitir que o verniz envie dados antigos do cache enquanto busca um novo?

8

Estou armazenando em cache páginas geradas dinamicamente (PHP-FPM, NGINX) e tenho verniz na frente delas, isso funciona muito bem.

No entanto, uma vez atingido o tempo limite do cache, vejo o seguinte:

  • nova página de solicitações de clientes
  • verniz reconhece o tempo limite do cache
  • cliente aguarda
  • verniz busca nova página do back-end
  • o verniz entrega uma nova página para o cliente (e também tem a página em cache para a próxima solicitação que a obtém instantaneamente)

O que eu gostaria de fazer é:

  • página de solicitações do cliente
  • verniz reconhece o tempo limite
  • verniz entrega página antiga para o cliente
  • verniz busca nova página do back-end e a coloca no cache

No meu caso, não é um site onde informações desatualizadas são um problema tão grande, principalmente quando falamos sobre o tempo limite do cache em alguns minutos.

No entanto, não quero que o usuário punido espere na fila e entregue algo imediato. Isso é possível de alguma maneira?

Para ilustrar, aqui está um exemplo de saída do cerco em execução 5 minutos no meu servidor que foi configurado para armazenar em cache por um 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
...

Eu deixei de fora as centenas de solicitações em execução 0.02. Mas ainda me preocupa que os usuários tenham que esperar quase 2 segundos pelo HTML bruto.

Não podemos melhorar aqui?

(Me deparei com o Varnish send while cache , parecia semelhante, mas não exatamente o que estou tentando fazer.)

Solução

A resposta de Shane Madden continha a solução, mas eu não percebi imediatamente. Havia outro detalhe que não incluí na minha pergunta porque achei que não era relevante, mas na verdade é.

A solução CMS que estou usando atualmente tem um ouvinte de banco de dados de verniz e, portanto, tem a capacidade de notificar verniz para proibir páginas cujo conteúdo foi alterado. Enviou uma PURGEsolicitação com alguma regex para proibir determinadas páginas.

Para resumir, há dois casos em que tive usuários infelizes:

  1. o verniz normal TTL de uma página expira
  2. usuários de back-end alteram o conteúdo, isso envia uma solicitação de limpeza ao verniz

Nos dois casos, estou tendo usuários "azarados". No segundo caso, é aliviado pelo fato de os usuários de back-end geralmente verificarem a página após a alteração; mas não necessariamente.

No entanto, para o segundo caso, criei uma solução (sim, percebo que essa pergunta começou com a busca de uma resposta para o primeiro caso ... pergunta mal formulada da minha parte):

Em vez de enviar uma solicitação de limpeza, usei a sugestão de Shanes e ajustei a VCL para que meu ouvinte de banco de dados de verniz possa enviar uma solicitação especial para buscar uma página hash_always_missconfigurada como true.

Com a arquitetura atual, eu realmente não tenho o luxo de fazer uma solicitação assíncrona real, mas com a ajuda de Como faço uma solicitação GET assíncrona em PHP? Consegui criar uma solicitação GET para verniz que não espera a página ser carregada, mas é boa o suficiente para acionar o verniz para buscar a página do back-end e armazená-la em cache.

O efeito líquido foi que o ouvinte do banco de dados enviou a solicitação para envernizar e, enquanto eu pesquisava a página específica, nunca tornava meus pedidos "azarados", mas uma vez que o verniz buscou a página completamente no back-end (isso pode variar de 300ms a 2s), de repente estava lá.

Ainda tenho que encontrar uma solução para evitar os mesmos problemas quando o TTL normal acabar, mas acho que a solução também é exatamente como Shane sugere: usando o wget para acionar o hash_always_miss, só precisarei ser inteligente o suficiente para obter a lista de páginas que tenho que atualizar.

marca
fonte

Respostas:

3

A solução que eu usei para resolver esse problema é garantir que o TTL em uma página nunca tenha chance de expirar antes de ser atualizado - forçando um cliente HTTP em execução em um dos meus sistemas a obter a carga lenta em vez de um cliente azarado solicitação.

No meu caso, isso envolve wgetum cron, enviando um cabeçalho especial para marcar as solicitações e configurações com req.hash_always_missbase nisso, forçando uma nova cópia do conteúdo a ser buscada no 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;
    }
    /* ... */
}

Para o seu conteúdo, isso pode significar definir o TTL do Varnish para algo como 5 minutos, mas ter um wget agendado para fazer uma solicitação de atualização de cache a cada minuto.

Shane Madden
fonte
Eu acho que entendo o que você quer dizer. Isso funcionaria bem para uma única página, mas os outros milhares? Não é possível usar o cron / wget nessa escala.
marque
Intrinsecamente, você deve declarar pelo menos quais páginas você deseja manter atualizadas no cache. Dada esta lista, não há razão para que o wget em um script cron não possa ajudá-lo.
Falcon Momot
Eu acho que esse é o desafio dessa "abordagem externa do verniz". Eu finalmente preciso sentar e tomar uma decisão e implementar isso para cada página. Não há como saber o verniz: "ttl acabou? Busque uma nova versão, mas até que isso aconteceu sirva a antiga" ...? Hmm.
marque
4

@EDITAR:

Apenas uma rápida para informar que esse recurso parece ter sido implementado apenas na versão mais recente no ramo principal; é provável que sua versão ainda não seja compatível com a verdadeira obsoleta enquanto revalidada / o exemplo que eu publiquei serviria 9999/10000 solicitações com um bugger ruim ainda tendo que aguardar a conclusão da solicitação no back-end (Ainda melhor que nada;) ...


Bem, eu não tenho 100% de certeza por que os comentários anteriores estão dizendo que não está funcionando, mas de acordo com: https://www.varnish-software.com/static/book/Saving_a_request.html

  • req.grace - define quanto tempo um objeto está atrasado para o Varnish ainda o considerar no modo de cortesia.
  • beresp.grace - define quanto tempo o verniz beresp.ttl manterá um objeto.
  • req.grace - geralmente é modificado no vcl_recv com base no estado do back-end.

Atualmente, estou usando uma configuração como o que o manual diz e está funcionando bem ... Aqui está um trecho do meu arquivo 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;
}

Observe que, se você deseja fornecer um tempo de carência de resposta de back-end mais longo (com 500 erros, como na minha configuração), será necessário configurar a análise de back-end ... Aqui está uma cópia da minha análise de back-end.

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = { 
        .url = "/nginx-status";
        .timeout = 500 ms; 
        .interval = 3s; 
        .window = 10;
        .threshold = 4;
    }
}
David
fonte
isso ainda é válido para o vcl 4.0?
Gadelkareem 29/04
0

No verniz 3, isso é alcançado através do "modo Grace". De acordo com o manual [1], você deve adicionar a seguinte lógica:

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

NITEMAN
fonte
Isso não alcançará o objetivo do OP, um cliente ainda ficará atrasado esperando que o conteúdo seja buscado no back-end, mesmo que outros clientes por trás dele recebam o resultado de graça obsoleto. "Quando o TTL expirar, o primeiro cliente que solicita o conteúdo deve ficar parado por 15 segundos, enquanto o segundo cliente deve obter a cópia agraciada". - varnish-software.com/static/book/Saving_a_request.html
Pax
Desculpe, não percebi como ele realmente funciona com a primeira solicitação expirada.
NITEMAN
Talvez objetivo desejado pode ser alcançado com alguns ttl fraude e linha C, a fim de disparar um "pedido de fundo"
NITEMAN