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 PURGE
solicitação com alguma regex para proibir determinadas páginas.
Para resumir, há dois casos em que tive usuários infelizes:
- o verniz normal TTL de uma página expira
- 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_miss
configurada 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.