Introducao Ao Varnish Cache - Thijs Feryn
Introducao Ao Varnish Cache - Thijs Feryn
Introducao Ao Varnish Cache - Thijs Feryn
Novatec
Authorized Portuguese translation of the English edition of Getting Started with Varnish Cache,
ISBN 9781491972229 © 2017 Thijs Feryn. This translation is published and sold by permission of
O'Reilly Media, Inc., the owner of all rights to publish and sell the same.
Tradução em português autorizada da edição em inglês da obra Getting Started with Varnish
Cache, ISBN 9781491972229 © 2017 Thijs Feryn. Esta tradução é publicada e vendida com a
permissão da O'Reilly Media, Inc., detentora de todos os direitos para publicação e venda desta
obra.
© Novatec Editora Ltda. 2017.
Todos os direitos reservados e protegidos pela Lei 9.610 de 19/02/1998. É proibida a reprodução
desta obra, mesmo parcial, por qualquer processo, sem prévia autorização, por escrito, do autor e
da Editora.
Editor: Rubens Prates
Tradução: Aldir José Coelho Corrêa da Silva
Revisão gramatical: Priscila A. Yoshimatsu
Editoração eletrônica: Carolina Kuwabata
ISBN: 978-85-7522-569-1
Histórico de edições impressas:
Abril/2017 Primeira edição
Novatec Editora Ltda.
Rua Luís Antônio dos Santos 110
02460-000 – São Paulo, SP – Brasil
Tel.: +55 11 2959-6529
Email: [email protected]
Site: www.novatec.com.br
Twitter: twitter.com/novateceditora
Facebook: facebook.com/novatec
LinkedIn: linkedin.com/in/novatec
Este livro é dedicado a todas as pessoas que me apoiam em meu dia a dia:
Minha amada esposa Lize, meu lho Lex e minha lha Lia. Minha mãe,
meu pai, minha irmã, minha sogra e cunhados.
E, claro, meus amigos – que sabem de quem estou falando.
Sumário
Prefácio
Convenções usadas no livro
Como entrar em contato conosco
Agradecimentos
Agradecimentos
Sou muito grato à minha empregadora Combell
(https://www.combell.com/en/?
utm_source=Varnishbookthijs&utm_medium=pd ink) por me ceder tempo
para escrever este livro. Mais especi camente, ao nosso CEO Jonas
Dhaenens, ao gerente de minha área Frederik Poelman e a meus colegas
Stijn Claerhout, Christophe Van den Bulcke e Wesley Hof. Obrigado por
acreditarem em mim!
Gostaria de agradecer publicamente a Varnish Software
(https://www.varnish-software.com/) por me dar a oportunidade de
escrever meu primeiro livro. Obrigado, Hildur Smaradottir, Per Buer e
Rubén Romero.
CAPÍTULO 1
Quando este texto foi escrito, a versão mais comum, que abordaremos neste livro,
era a 4.1. A versão 5 foi lançada em 15 de setembro de 2016. No entanto, isso não
signi ca que o livro está desatualizado. O processo de adoção de novas versões
demora um pouco.
Agora que você já o conhece, deve estar ansioso para aprender a instalar,
con gurar e usar o Varnish. Este capítulo abordará o procedimento básico
de instalação nos sistemas operacionais de maior suporte e os parâmetros
típicos de con guração que podem ser ajustados conforme suas
preferências.
Instalando o Varnish
O Varnish é suportado nos seguintes sistemas operacionais:
• Linux
• FreeBSD
• Solaris
Você pode fazê-lo funcionar em outros sistemas tipo UNIX (OS X,
OpenBSD, NetBSD e Windows com o Cygwin), mas não há suporte o cial
para eles.
Ainda que o FreeBSD suporte o cialmente o Varnish, não farei menção a ele no
resto do livro. Na verdade, poucas pessoas executam o Varnish no FreeBSD. Isso não
signi ca que não respeito o projeto e o sistema operacional, mas estou escrevendo
este livro para o público em geral e sejamos sinceros: o FreeBSD não é tão popular.
Opções de inicialização
A essa altura você já sabe que a única nalidade do arquivo de
con guração é alimentar as opções de inicialização do programa
varnishd. Teoricamente, não é preciso um gerenciador de serviço: você
pode iniciar o Varnish manualmente executando o varnishd por conta
própria e atribuindo manualmente as opções de inicialização.
usage: varnishd [options]
-a address[:port][,proto] # endereço e porta de escuta do HTTP
(padrão: *:80)
# endereço: o padrão é o de loopback
# porta: porta ou serviço (padrão: 80)
# proto: HTTP/1 (padrão), PROXY
-b address[:port] # endereço e porta do backend
# endereço: nome de host ou IP
# porta: porta ou serviço (padrão: 80)
-C # exibe código VCL compilado para a
linguagem C
-d # depura
-F # Executa em primeiro plano
-f file # script VCL
-h kind[,hashoptions] # Especificação hash
# -h critbit [padrão]
# -h simple_list
# -h classic
# -h classic,<buckets>
-i identity # Identidade da instância varnish
- j jail[,jailoptions] # Especificação de jailing
# -j unix[,user=<user>][,ccgroup=
<group>]
# -j none
-l vsl[,vsm] # Tamanho do arquivo de memória
compartilhada
# vsl: espaço para registros VSL [80m]
# vsm: espaço para contadores
estatísticos [1m]
-M address:port # Destino de CLI reverso
-n dir # diretório de trabalho do varnishd
-P file # Arquivo PID
-p param=value # define parâmetro
-r param[,param...] # torna o parâmetro somente de leitura
-S secret-file # Arquivo de segredo para autenticação na
CLI
-s [name=]kind[,options] # Especificação do armazenamento de
backend
# -s malloc[,<size>]
# -s file,<dir_or_file>
# -s file,<dir_or_file>,<size>
# -s file,<dir_or_file>,<size>,
<granularity>
# -s persistent (experimental)
-T address:port # Endereço e porta de escuta do Telnet
-t TTL # TTL-padrão
-V # versão
-W waiter # Implementação de waiter
# -W epoll
# -W poll
A página de documentação do varnishd (http://varnish-
cache.org/docs/4.1/reference/varnishd.html) tem informações mais
detalhadas sobre todas as opções de inicialização.
Examinaremos algumas das opções de inicialização típicas que você
encontrará quando con gurar o Varnish. Os exemplos representam as
opções que vêm de /etc/default/varnish em um sistema Ubuntu que usa o
SysV como gerenciador de serviço.
Opções de inicialização comuns
A lista de opções de inicialização con guráveis é muito extensa, mas há
um conjunto de opções comuns que nos ajudarão a começar. O exemplo
a seguir faz isso:
DAEMON_OPTS="-a :80 \
-a :81,PROXY \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,3g \
-j unix,user=www-data \"
Vinculação de rede. A opção de rede mais essencial chama-se -a. Ela de ne o
endereço, a porta e o protocolo que serão usados na conexão com o
Varnish. Por padrão, seu valor é :6081. Isso signi ca que o Varnish estará
vinculado a todas as interfaces de rede disponíveis na porta TCP 6081. Na
maioria dos casos, o valor é mudado imediatamente para 80, a porta
HTTP convencional.
Você também pode decidir qual protocolo usará. Por padrão, é usado o
HTTP, mas podemos con gurar essa opção com PROXY
(https://www.varnish-cache.org/docs/4.1/whats-new/changes.html#proxy-
protocol-support). O protocolo PROXY adiciona um chamado
“preâmbulo” à conexão TCP e contém o endereço IP real do cliente. Isso
só funciona quando o Varnish está localizado atrás de outro servidor
proxy que dê suporte ao protocolo PROXY. O protocolo PROXY será
discutido com mais detalhes em “E quanto ao TLS/SSL?”.
É possível de nir vários endereços de escuta com o uso de múltiplas
opções -a. Pode fazer sentido usar vários endereços de escuta se você
estiver combinando o suporte ao HTTP e ao PROXY, como ilustrado
anteriormente.
Vinculação de endereço CLI. A segunda opção que discutiremos chama-se -T.
Ela é usada para de nir o endereço e a porta em que a CLI do Varnish
escutará. Em “Banimento na linha de comando”, precisaremos de acesso à
CLI para invalidar o cache.
Por padrão, a CLI do Varnish ca vinculada ao endereço localhost na
porta 6082. Isso signi ca que ela só pode ser acessada localmente.
Se você não especi car uma opção -f, terá de adicionar a opção -b para de nir o
servidor backend que o Varnish usará.
E quanto ao TLS/SSL?
O Transport Layer Security (TLS), também chamado de Secure Sockets
Layer (SSL), é um conjunto de protocolos criptográ cos usados para
criptografar a transferência de dados pela rede. Em um contexto web, o
TLS e o SSL são o “S” de HTTPS. O TLS assegura que a conexão seja
protegida com a criptogra a da comunicação e o estabelecimento de um
nível de con ança por meio da emissão de certi cados.
Durante os últimos anos, o TLS se tornou tão popular que daqui a alguns
anos não consideraremos mais normal a existência de tráfego HTTP não
criptografado. A segurança ainda é um tópico importante na indústria de
TI, e quase todas as marcas existentes na internet querem mostrar que são
seguras e con áveis oferecendo o HTTPS em seus sites. Até mesmo o
Google Search supostamente dá uma melhor classi cação para páginas de
sites que usam o HTTPS.
O projeto do Varnish não incluiu o suporte ao TLS em sua base de código. Isso
signi ca que você não pode usar o Varnish em projetos que demandem o TLS? É
claro que não! Se fosse esse o caso, ele estaria com seus dias contados.
O Varnish não inclui nativamente o suporte ao TLS porque a criptogra a
é complicada e não faz parte da operação básica do projeto. Ele se dedica
ao cache e deixa a criptogra a para os especialistas no assunto.
O truque para o uso do TLS é terminar a conexão protegida antes de o
tráfego alcançar o Varnish. Isso signi ca adicionar um o oader de
TLS/SSL à instalação que termine a conexão TLS e se comunique pelo
HTTP com o Varnish.
A desvantagem é que esse esquema adiciona outra camada de
complexidade à instalação e outro sistema que pode falhar. Além disso, é
um pouco mais difícil para o servidor web determinar o endereço IP de
origem. Sob circunstâncias normais, o Varnish deve pegar o valor do
cabeçalho de solicitação HTTP X-Forwarded-For enviado pelo o oader
de TLS e armazená-lo em seu próprio cabeçalho X-Forwarded-For. Dessa
forma, o backend pode recuperar o IP de origem.
No Varnish 4.1, o suporte ao protocolo PROXY foi adicionado. Trata-se de
um protocolo pequeno introduzido pelo HAProxy
(http://www.haproxy.org/), o principal software open source de
balanceamento de carga. O protocolo PROXY adiciona um pequeno
preâmbulo à conexão TCP que contém o endereço IP do cliente original.
Essa informação é transferida e pode ser interpretada pelo Varnish. O
Varnish usará esse valor adicionando-o automaticamente ao cabeçalho X-
Forwarded-For que ele envia para o backend.
Redigi uma postagem de blog detalhada (https://blog.feryn.eu/varnish-4-1-
haproxy-get-the-real-ip-by-leveraging-proxy-protocol-support/) sobre o
assunto, e ela contém mais informações sobre a instalação tanto do
HAProxy quanto do Varnish.
A implementação do protocolo PROXY no Varnish também usa essa nova
informação do endereço IP de origem para con gurar algumas variáveis
no VCL:
• Con gura a variável client.ip com o endereço IP enviado por
intermédio do protocolo PROXY
• Con gura a variável server.ip com o endereço IP do servidor que
aceitou a conexão inicial
• Con gura a variável local.ip com o endereço IP do servidor Varnish
• Con gura a variável remote.ip com o endereço IP da máquina que se
encontra na frente do Varnish
O HAProxy não é o único o oader de TLS que dá suporte ao PROXY. A
Varnish Software lançou o Hitch (http://hitch-tls.org/), um proxy TLS que
termina a conexão TLS e se comunica pelo HTTP com o Varnish.
Enquanto o HAProxy é principalmente um balanceador de carga que
oferece o oading de TLS, o Hitch só faz o o oading de TLS. O blog do
HAProxy tem uma postagem sobre o assunto
(http://blog.haproxy.com/haproxy/proxy-protocol/) que lista um conjunto
de projetos prontos para o protocolo PROXY. Dependendo de seu caso de
uso e de se o balanceamento de carga é necessário em sua instalação, você
pode selecionar o HAProxy ou um proxy TLS dedicado. O Varnish Plus, a
versão avançada do Varnish desenvolvida pela Varnish Software, oferece
suporte a TLS/SSL nos lados do servidor e do cliente. O proxy TLS/SSL
do Varnish Plus é totalmente integrado ao Varnish e ajuda a melhorar a
segurança do site sem depender de soluções de terceiros.
Conclusão
Não deixe todas essas con gurações o amedrontarem – elas são apenas
uma prova de que o Varnish é uma ferramenta incrivelmente exível com
várias opções e con gurações que podem ser ajustadas.
Se você é um administrador de sistemas, espero tê-lo encorajado a tentar
ajustar algumas das con gurações. Se não é, lembre-se apenas de que o
Varnish pode ser instalado facilmente com um gerenciador de pacotes de
sua distribuição Linux e quase não requer ajustes para começar a operar.
Examine pelo menos a con guração de “Vinculação de rede”, se quiser
que o Varnish processe tráfego HTTP na porta 80.
CAPÍTULO 3
Idempotência
O Varnish só armazena em cache recursos que sejam solicitados por meio
de um verbo HTTP idempotente, que são verbos HTTP que não alteram o
estado do recurso. Resumindo, o Varnish só armazena em cache
solicitações que usem os seguintes métodos:
• GET
• HEAD
E isso faz muito sentido: se você emitir uma solicitação usando POST ou
PUT, o próprio método já implica que ocorrerá uma alteração. Nesse caso,
o cache não seria útil porque você estaria armazenando dados obsoletos
desde o início.
Logo, se o Varnish se deparar com a chegada de uma solicitação, digamos,
POST, ele a passará para o backend e não armazenará em cache a resposta
retornada.
Para sermos mais exatos, estes são os verbos/métodos HTTP que o
Varnish pode manipular:
• GET (pode ser armazenado em cache)
• HEAD (pode ser armazenado em cache)
• PUT (não pode ser armazenado em cache)
• POST (não pode ser armazenado em cache)
• TRACE (não pode ser armazenado em cache)
• OPTIONS (não pode ser armazenado em cache)
• DELETE (não pode ser armazenado em cache)
Todos os outros métodos HTTP são considerados não compatíveis com o
RFC2616 e serão ignorados pelo cache.
Embora eu tenha mencionado o RFC2616
(https://tools.ietf.org/html/rfc2616), na verdade esse RFC é obsoleto
(https://www.mnot.net/blog/2014/06/07/rfc2616_is_dead) e foi substituído
pelos RFCs a seguir:
• RFC7230 (https://tools.ietf.org/html/rfc7230)
• RFC7231 (https://tools.ietf.org/html/rfc7231)
• RFC7232 (https://tools.ietf.org/html/rfc7232)
• RFC7233 (https://tools.ietf.org/html/rfc7233)
• RFC7234 (https://tools.ietf.org/html/rfc7234)
• RFC7235 (https://tools.ietf.org/html/rfc7235)
Estado
Agora que você conhece a idempotência e sabe que os métodos de
solicitações HTTP não devem mudar o estado do recurso, examinaremos
outros mecanismos do HTTP que podem controlar o estado. Não estou
falando do estado global, mas sim de dados especí cos do usuário. Há
duas maneiras de rastrear o estado dos usuários:
• Cabeçalhos de autorização
• Cookies
Sempre que o Varnish vê um desses itens, ele passa a solicitação para o
backend e não armazena a resposta em cache. Isso ocorre porque quando
um cabeçalho de autenticação ou um cookie é enviado, esse elemento
sugere que os dados serão diferentes para cada usuário que estiver
emitindo a solicitação.
Se você decidir armazenar em cache a resposta de uma solicitação que
contenha um cabeçalho de autorização ou cookie, estará servindo uma
resposta personalizada para o primeiro usuário que a solicitou. Outros
usuários também a verão, e a resposta pode conter informações sigilosas
ou irrelevantes.
No entanto, sejamos francos: os cookies são nosso principal instrumento
de rastreamento de estado, e é difícil encontrar sites que não os usem.
Infelizmente, a internet usa cookies demais e com frequência para as
razões erradas.
Usamos cookies para estabelecer sessões em nosso aplicativo. Também
podemos usar cookies para rastrear o idioma, a região e outras
preferências. E ainda há os cookies de rastreamento que são usados por
terceiros para nos “espionar”.
Quando se trata de HTTP, os cookies aparecem no processo tanto de
solicitação quanto de resposta. É o backend que de ne um ou mais
cookies emitindo um cabeçalho de resposta Set-Cookie. O cliente recebe
essa resposta e armazena os cookies em seu armazenamento local.
Como você pode ver no exemplo a seguir, um cookie é um conjunto de
pares chave-valor, delimitados por um “e” comercial (ampersand).
Set-Cookie: language=en&country=us
Quando um cliente armazena cookies de um domínio, ele usa um
cabeçalho Cookie para devolvê-los para o servidor a cada solicitação
subsequente. Os cookies também são enviados em solicitações que não
demandam um estado especí co (por exemplo, arquivos estáticos).
Cookie: language=en&country=us
É com esse processo de duas etapas que os cookies são de nidos e
anunciados. Só temos de nos lembrar da diferença entre Cookie e Set-
Cookie. O primeiro é um cabeçalho de solicitação; o segundo é um
cabeçalho de resposta.
Cabeçalho Expires
O cabeçalho Expires é muito simples: de nimos apenas a data e a hora
em que um objeto deve ser considerado obsoleto. Ele é um cabeçalho de
resposta que é enviado pelo backend.
Aqui está um exemplo desse cabeçalho:
Expires: Sat, 09 Sep 2017 14:30:00 GMT
Lembre-se sempre de que a hora de um cabeçalho Expires é baseada na hora de
Greenwich. Se você estiver localizado em outro fuso horário, expresse a hora de
acordo.
Cabeçalho Cache-control
O cabeçalho Cache-control de ne o tempo de vida de maneira relativa: em
vez de declarar o momento da expiração, ele declara quantos segundos
faltam para o objeto expirar. Em muitas situações, essa é uma abordagem
mais intuitiva: você poderia dizer que um objeto só deve ser armazenado
em cache por uma hora atribuindo 3.600 segundos como tempo de vida.
Esse cabeçalho HTTP tem mais recursos que o cabeçalho Expires: é
possível de nir o tempo de vida tanto para clientes quanto para proxies.
Isso permite de nir um comportamento distinto dependendo do tipo de
sistema que processará o cabeçalho; também podemos decidir se faremos
o armazenamento em cache e se faremos a revalidação com o backend.
Cache-control: public, max-age=3600, s-maxage=86400
O exemplo anterior usa três palavras-chave importantes para de nir o
tempo de vida e o recurso de armazenamento em cache:
public
Indica que tanto navegadores quanto caches compartilhados podem armazenar o
conteúdo em cache.
max-age
Tempo de vida em segundos que deve ser respeitado pelo navegador.
s-maxage
Tempo de vida em segundos que deve ser respeitado pelo proxy.
Também é importante saber que o Varnish só respeita um subconjunto da
sintaxe de Cache-control. Ele só respeita as palavras-chave relevantes para
seu papel como proxy de cache reverso:
• Cabeçalhos Cache-control enviados pelo navegador são ignorados.
• O tempo de vida proveniente de uma instrução s-maxage tem
prioridade sobre o de uma instrução max-age.
• Instruções must-revalidate e proxy-revalidate são ignoradas.
• Quando um cabeçalho de resposta Cache-control contém os termos
private, no-cache ou no-store, a resposta não é armazenada em cache.
Precedência de expiração
O Varnish respeita tanto o cabeçalho Expires quanto o cabeçalho Cache-
control. No Varnish Con guration Language, também podemos de nir
qual será o tempo de vida independentemente dos cabeçalhos de cache. E
se não houver um tempo de vida, o Varnish recorrerá ao padrão de 120
segundos embutido em seu código.
Aqui está a lista de prioridades que o Varnish aplica na seleção de um
tempo de vida:
1. Se beresp.ttl estiver con gurado no VCL, usa esse valor como tempo
de vida.
2. Procura uma instrução s-maxage no cabeçalho Cache-control.
3. Procura uma instrução max-age no cabeçalho Cache-control.
4. Procura um cabeçalho expires.
5. Faz o armazenamento em cache por 120 segundos em todas as outras
circunstâncias.
Como você pode ver, o TTL do VCL tem prioridade absoluta. Lembre-se desse
fato, porque ele fará com que cabeçalhos Expires ou Cache-control sejam
ignorados em favor do valor de beresp.ttl.
Solicitações condicionais
A expiração é um mecanismo importante para a atualização do cache. Ela
se baseia no conceito de atualidade de um objeto em determinados
intervalos. Esses intervalos são de nidos pelo tempo de vida e
processados pelo Varnish. O usuário nal não contribui para isso.
Após a expiração, tanto os cabeçalhos quanto o payload são transmitidos
e armazenados em cache. Isso pode causar um problema de uso excessivo
de recursos e ser um desperdício de largura de banda, principalmente se
os dados solicitados não mudarem nesse período.
Felizmente, o HTTP oferece uma maneira de resolver o problema. Além
de usar um tempo de vida, ele nos permite fazer o rastreamento da
validade de um recurso. Há dois mecanismos para isso:
• Cabeçalho de resposta Etag
• Cabeçalho de resposta Last-Modified
ETag
Um Etag é um cabeçalho de resposta HTTP que é de nido pelo servidor
web ou pelo aplicativo. Ele contém um valor exclusivo que corresponde ao
estado do recurso.
Uma estratégia muito comum é criar um hash exclusivo, que pode ser um
hash md5 ou sha baseado no URL e na data de modi cação interna do
recurso. Ele pode ser qualquer coisa, contanto que seja exclusivo.
HTTP/1.1 200 OK
Host: localhost
Etag: 7c9d70604c6061da9bb9377d3f00eb27
Content-type: text/html; charset=UTF-8
Hello world output
Assim que um navegador se deparar com esse Etag, ele armazenará o
valor. Na próxima solicitação, o valor de Etag será retornado para o
servidor em um cabeçalho If-None-Match.
GET /if_none_match.php HTTP/1.1
Host: localhost
User-Agent: curl/7.48.0
If-None-Match: 7c9d70604c6061da9bb9377d3f00eb27
O servidor receberá esse cabeçalho If-None-Match e veri cará se o valor
difere do valor do cabeçalho Etag que ele está para enviar.
Se o valor de Etag for igual ao de If-None-Match, o servidor web ou o
aplicativo poderá retornar um cabeçalho de resposta HTTP/1.1 304 Not
Modified para indicar que o valor não mudou.
HTTP/1.0 304 Not Modified
Host: localhost
Etag: 7c9d70604c6061da9bb9377d3f00eb27
Quando enviamos um código de status 304, não enviamos payload, o que
pode reduzir muito a quantidade de bytes enviada. O navegador recebe o
código 304 e sabe que pode continuar exibindo os dados antigos.
Se o valor de If-None-Match não coincidir com o de Etag, o servidor web
ou o aplicativo retornará o payload completo, acompanhado do cabeçalho
de resposta HTTP/1.1 200 OK e, claro, do novo Etag.
Essa é uma ótima maneira de conservar recursos. O objetivo principal é
reduzir a largura de banda, mas também o ajudará a reduzir o consumo
de memória, ciclos de CPU e I/O de disco se você implementar
corretamente.
A seguir temos um exemplo de implementação. Trata-se apenas de um
script ctício que não serve para nada, a não ser provar meu argumento.
Ele foi escrito em PHP por ser minha linguagem preferida.
De nitivamente essa implementação não está restrita ao PHP. Você pode
criá-la em qualquer linguagem do lado do servidor.
<?php
$etag = md5(__FILE__.filemtime(__FILE__));
header('Etag: ' . $etag);
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])
&& $_SERVER['HTTP_IF_NONE_MATCH'] == $etag) {
header('HTTP/1.0 304 Not Modified');
exit;
}
sleep(5);
?>
<h1>Etag example</h1>
<?php
echo date("Y-m-d H:i:s").'<br />';
Last-Modi ed
Os ETags não são a única maneira de fazer solicitações condicionais;
também há uma técnica alternativa baseada no cabeçalho de resposta
Last-Modified. O cliente usará então o cabeçalho de solicitação If-
Modified-Since para validar a atualidade do recurso.
A abordagem é semelhante:
1. Faça seu aplicativo ou servidor web retornar um cabeçalho de
resposta Last-Modified.
2. O cliente armazenará esse valor e o usará como cabeçalho If-
Modified-Since na próxima solicitação.
3. O aplicativo ou servidor web comparará o valor de If-Modified-Since
com a data de modi cação do recurso.
4. Será retornado um HTTP/1.1 304 Not Modified ou um HTTP/1.1 200 OK.
Os benefícios são os mesmos: reduz os bytes enviados e a carga no
servidor evitando a renderização completa da saída.
Variações de cache
Em geral, um recurso HTTP é público e tem o mesmo valor para todos os
seus consumidores. Quando dados são especí cos de um usuário, em
teoria eles não podem ser armazenados em cache. No entanto, há exceções
a essa regra e o HTTP tem um mecanismo para isso.
O HTTP usa o cabeçalho Vary para executar variações de cache. O
cabeçalho Vary é um cabeçalho de resposta que é enviado pelo backend.
Seu valor contém o nome de um cabeçalho de solicitação que deve ser
usado para de nir a variação.
Conclusão
Quando você estiver com tudo funcionando e puder enviar tráfego HTTP
pelo Varnish, haverá um comportamento especí co que afetará a
capacidade de cache de seu site.
Esse comportamento não re ete regras e políticas arbitrárias de nidas
pelo próprio Varnish. O Varnish respeita as melhores práticas
convencionais do HTTP que foram de nidas nos RFCs aceitos por toda a
indústria.
Mesmo se você não adicionar nenhum código VCL, as melhores práticas
assegurarão que seu site tenha um cache apropriado, contanto que seu
código também as respeite.
Uma vantagem adicional é que a capacidade de armazenamento em cache
de seu site e a portabilidade do comportamento do cache podem ir além
do escopo do Varnish. Você pode trocar o Varnish por outro tipo de proxy
reverso ou até mesmo por uma CDN.
A essa altura você sabe o que é um cabeçalho Cache-control e em que ele
difere de um cabeçalho Expires. Já tem uma ideia sólida de como se
bene ciar desses cabeçalhos para controlar a capacidade de
armazenamento de suas páginas em cache. E já está familiarizado com as
variações de cache e as solicitações condicionais.
Para concluir, o mais importante: você só pode armazenar em cache
solicitações GET ou HEAD, porque elas são idempotentes. Solicitações não
idempotentes como, por exemplo, POST, PUT e DELETE não podem ser
armazenadas em cache.
CAPÍTULO 4
Hooks e sub-rotinas
O VCL não é o tipo de linguagem em que digitamos algo em um arquivo
vazio ou dentro de um método principal; ele é restritivo e só nos permite
interagir com certos aspectos do uxo de execução do Varnish por meio
de hooks. Esse uxo de execução é de nido em uma máquina de estados
nitos.
Os hooks representam estágios especí cos do uxo do Varnish. O
comportamento do Varnish nesses estágios é expresso por meio de várias
sub-rotinas internas. Você de ne uma sub-rotina em seu arquivo VCL,
estende o comportamento de cache nessa sub-rotina e emite um
recarregamento do arquivo VCL para ativar esse comportamento.
Toda sub-rotina tem um conjunto xo de instruções de retorno que
representam uma mudança de estado no uxo.
Sub-rotinas de backend
Esta é uma lista de sub-rotinas de backend:
vcl_backend_error_fetch
Chamada antes do envio de uma solicitação para o servidor backend.
vcl_backend_response
Chamada imediatamente após o recebimento bem-sucedido de uma
resposta do servidor backend.
vcl_backend_error
Executada quando uma busca no backend não foi bem-sucedida ou
quando o número máximo de novas tentativas foi excedido.
Sub-rotinas personalizadas
Você também pode de nir suas próprias sub-rotinas e chamá-las de
dentro de seu código VCL. Sub-rotinas personalizadas podem ser usadas
para organizar e modularizar código VCL, quase sempre em uma
tentativa de reduzir a duplicação de código.
O exemplo a seguir é composto pela sub-rotina remove_ga_cookies que
contém uma lógica de busca e substituição que usa expressões regulares.
O resultado nal é a remoção dos cookies de rastreamento do Google
Analytics da solicitação recebida.
Aqui está o arquivo que contém a sub-rotina personalizada:
sub remove_ga_cookies {
# Remove cookies baseados no Google Analytics
set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(;
)?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?",
"");
set req.http.Cookie = regsuball(req.http.Cookie, "_gat=[^;]+(; )?",
"");
set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(;
)?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(;
)?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(;
)?", "");
}
Ela é chamada desta forma:
include "custom_subroutines.vcl";
sub vcl_recv {
call remove_ga_cookies;
}
Instruções de retorno
Enquanto as sub-rotinas VCL representam os diferentes estados da
máquina de estados, a instrução de retorno existente em cada sub-rotina
permite mudanças de estado.
Se você especi car uma instrução de retorno válida em uma sub-rotina, a
ação correspondente será executada e ocorrerá uma transição para o
estado desejado. Como mencionado anteriormente, quando não
especi camos uma instrução de retorno, a execução da sub-rotina
continua e o Varnish usa como fallback o VCL interno.
Aqui está uma lista das instruções de retorno válidas:
hash
Procura o objeto no cache.
pass
Passa a solicitação para o backend, mas não armazena o resultado em
cache.
pipe
Passa a solicitação para o backend e ignora qualquer lógica de cache.
synth
Interrompe a execução e retorna imediatamente uma saída sintética.
Essa instrução de retorno recebe um código de status HTTP e uma
mensagem.
purge
Remove o objeto e suas variantes do cache. O URL da solicitação é
usado como identi cador.
fetch
Passa a solicitação para o backend e tenta armazenar a resposta em
cache.
restart
Reinicia a transação e aumenta o contador de req.restarts até
max_restarts ser alcançado.
deliver
Retorna a resposta para o cliente.
miss
Atualiza o objeto sincronamente a partir do backend, até mesmo em um
acerto.
lookup
Usa o hash para procurar um objeto no cache.
abandon
Abandona uma solicitação feita ao backend e retorna um erro HTTP
503 (backend indisponível).
Fluxo de execução
No Capítulo 3 falei sobre o VCL interno e na seção anterior listei um
conjunto de sub-rotinas e instruções de retorno. É hora de juntar todas as
peças do quebra-cabeça e compor o uxo de execução do Varnish.
No Capítulo 1 mencionei a máquina de estados nitos que o Varnish usa.
Vamos examiná-la e ver como o Varnish faz transições entre estados e o
que as causa.
A Figura 4.1 mostra um uxograma simpli cado que explica o uxo de
execução.
Figura 4.1 – Fluxo de execução simpli cado do Varnish.
Podemos dividir o uxo em duas partes:
1. Buscas no backend (caixa cinza)
2. Manipulação de solicitações e respostas (resto do uxograma)
Sintaxe do VCL
Se você quiser usar hooks no uxo de execução do Varnish e estender as
sub-rotinas, precisa conhecer a sintaxe. Bem, falemos então sobre ela.
Operadores
O VCL tem um conjunto de operadores (https://www.varnish-
cache.org/docs/4.1/reference/vcl.html#operators) que você pode usar para
atribuir, comparar e procurar valores.
Aqui está um exemplo em que combinamos alguns operadores:
sub vcl_recv {
if(req.method == "PURGE" || req.method == "BAN") {
return(purge);
}
if(req.method != "GET" && req.method != "HEAD") {
return(pass);
}
if(req.url ~ "^/products/[0-9]+/") {
set req.http.x-type = "product";
}
}
• Usamos o operador de atribuição (=) para atribuir valores a variáveis ou
objetos.
• Usamos o operador de comparação (==) para comparar valores. Ele
retorna true se os dois valores forem iguais; caso contrário, false é
retornado.
• Usamos o operador de busca (~) para executar uma busca de expressão
regular. Se o valor atender à expressão regular, true será retornado;
caso contrário, false será retornado.
• O operador de negação (!) retorna o estado lógico inverso.
• O operador e lógico (&&) retorna true se os dois operandos retornarem
true; caso contrário, false é retornado.
No exemplo anterior, veri camos se:
• O método da solicitação é igual a PURGE ou a BAN.
• O método da solicitação não é igual a GET e a HEAD.
• O URL da solicitação atende a uma expressão regular que procura
URLs de produtos.
Também há os operadores menor que (<), maior que (>), menor ou igual a
(<=) e maior ou igual a (>=). Consulte a seção de operadores
(https://www.varnish-cache.org/docs/4.1/reference/vcl.html#operators) do
site de documentação do Varnish para saber mais.
Instruções condicionais
São as instruções if e else – você provavelmente sabe o que elas fazem.
Pularemos a teoria e passaremos direto para um exemplo:
sub vcl_recv {
if(req.url == "/"){
return(pass);
} elseif(req.url == "/test") {
return(synth(200,"Test succeeded"));
} else {
return(pass);
}
}
Basicamente, o VCL dá suporte a if, else e elseif. E isso é tudo!
Comentários
Os comentários são partes do VCL que não são interpretadas, mas sim
usadas para adicionar notas que descrevem o código.
O VCL oferece três maneiras de adicionar comentários:
• Comentários de linha única usando a barra dupla //
• Comentários de linha única usando o símbolo de jogo da velha #
• Comentários de várias linhas em um bloco de comentário delimitado
por /* e */
Aqui está o trecho de um código VCL que usa os três estilos de
comentário:
sub vcl_recv {
// Linha única de VCL desativada por símbolo de comentário.
# Outra maneira de desativar uma única linha com um símbolo de
comentário.
/*
Bloco de VCL de várias linhas desativado por símbolo de
comentário.
*/
}
Valores escalares
Você pode usar strings, inteiros e booleanos – os valores escalares típicos –
em VCL. O VCL também suporta hora e durações.
Vejamos o que é possível fazer com os valores escalares.
Strings
As strings cam entre aspas duplas e não podem conter novas linhas. É
claro que aspas duplas também não podem ser usadas. Se você pretende
empregar novas linhas ou aspas duplas em suas strings, terá de usar
strings longas, que são incluídas em aspas duplas e chaves.
A seguir temos um código. Este exemplo tem uma string normal e uma
longa:
sub vcl_recv {
set req.http.x-test = "testing 123";
set req.http.x-test-long = {"testing '123', or even "123" for that
matter"};
set req.http.x-test-long-newline = {"testing '123',
or even "123"
for that matter"};
}
É fácil usar strings – apenas lembre-se de que as strings longas permitem novas
linhas e aspas duplas, o que não ocorre com as strings comuns.
Inteiros
Não há muito a dizer sobre os inteiros – eles são apenas números.
Quando usamos inteiros no contexto de uma string, eles são convertidos
em strings.
Aqui está um exemplo de uso válido de inteiros:
sub vcl_recv {
return(synth(200,"All good"));
}
O primeiro argumento da função synth requer um inteiro, logo foi o que
passamos para ele.
sub vcl_recv {
return(synth(200,200));
}
O exemplo anterior não tem muita utilidade; a única coisa que ele faz é
provar que inteiros são convertidos em strings.
Booleanos
Os booleanos produzem verdadeiro ou falso. Além de um exemplo de
código, não há nada mais a comentar:
sub vcl_backend_response {
if(beresp.http.set-cookie) {
set beresp.uncacheable = true;
}
}
Esse exemplo não armazena o objeto em cache se a resposta HTTP tiver
um cabeçalho Set-Cookie.
Durações
Outro tipo ao qual o VCL dá suporte é o das durações. Elas são usadas
para o tempo-limite, tempo de vida, idade, tempo extra, tempo de
manutenção, e assim por diante.
A duração tem a aparência de um número com um su xo em formato
string. O su xo pode ser qualquer um dos valores a seguir:
• ms – milissegundos
• s – segundos
• m – minutos
• h – horas
• d – dias
• w – semanas
• y – anos
Logo, se quisermos que a duração seja de três semanas, a de niremos
com 3w.
Aqui está um exemplo de VCL em que de nimos o tempo de vida da
resposta com uma hora:
sub vcl_backend_response {
set beresp.ttl = 1h;
}
As durações podem conter números reais. A seguir temos um exemplo em
que o armazenamento em cache dura 1,5 hora:
sub vcl_backend_response {
set beresp.ttl = 1.5h;
}
Expressões regulares
O VCL dá suporte às Perl Compatible Regular Expressions (PCRE,
Expressões Regulares Compatíveis com Perl). As expressões regulares
podem ser usadas na procura de padrões com o uso do operador de busca
~.
Elas também podem ser usadas em funções como regsub e regsuball para
procurar e substituir texto.
Você deve estar querendo ver um código, certo? No entanto, já lhe mostrei
um exemplo de expressões regulares quando falei sobre o operador de
busca. Então, copiarei e colarei o mesmo exemplo para demonstrar meu
argumento:
sub vcl_recv {
if(req.url ~ "^/products/[0-9]+/"){
set req.http.x-type = "product";
}
}
Funções
O VCL tem um conjunto de funções internas que executam várias tarefas.
Essas funções são:
• regsub
• regsuball
• hash_data
• ban
• synthetic
Regsub
regsub é uma função que procura padrões com base em expressões
regulares e pode retornar subconjuntos desses padrões. Essa função é
usada para executar operações de busca e substituição em variáveis VCL.
regsub só detecta a primeira ocorrência de um padrão.
A seguir temos um exemplo da vida real em que estamos procurando um
cookie de idioma e extraindo-o do cabeçalho cookie para executar uma
variação de cache:
sub vcl_hash {
if(req.http.Cookie
~ "language=(nl|fr|en|de|es)"){
hash_data(regsub(req.http.Cookie,
"^.*;? ?language=(nl|fr|en|de|es)( ?|;| ;).*$","\1"));
}
}
Regsuball
A única diferença entre regsub e regsuball é o fato de que a última
procura todas as ocorrências, enquanto a primeira só procura a primeira
ocorrência.
Quando você tiver de executar uma operação de busca e substituição em
uma string que tenha várias ocorrências do padrão procurado, regsuball é
que deve ser usada!
Quer ver um exemplo? Certo! Consulte o Exemplo 4.1.
Exemplo 4.1 – Remove os cookies do Google Analytics usando a função
regsuball
sub vcl_recv {
set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(;
)?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?",
"");
set req.http.Cookie = regsuball(req.http.Cookie, "_gat=[^;]+(; )?",
"");
set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(;
)?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(;
)?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(;
)?", "");
}
Talvez você se lembre de ter visto esse exemplo em “Sub-rotinas
personalizadas”. Se você usa o Google Analytics, haverá alguns cookies de
rastreamento no cabeçalho de cookies. Esses cookies são controlados por
JavaScript, não pelo servidor. Eles interferem na taxa de acertos e é bom
que sejam removidos.
A função regsuball procurará todas as ocorrências desses padrões e as
removerá.
A primeira linha será responsável por remover os seguintes cookies:
• __utma
• __utmb
• __utmc
• __utmt
• __utmv
• __utmz
Precisamos realmente de regsuball para fazer isso, porque regsub só
removeria o primeiro cookie que fosse encontrado.
Hash_data
A função hash_data é usada na sub-rotina vcl_hash e adiciona dados ao
hash usado para identi car objetos no cache.
O exemplo a seguir é o mesmo que usamos no caso de regsub: ele
adiciona o cookie de idioma ao hash. Já que não mencionamos
explicitamente uma instrução de retorno, o nome do host e o URL
também serão adicionados após a execução de vcl_hash:
sub vcl_hash {
if(req.http.Cookie ~ "language=(nl|fr|en|de|es)"){
hash_data(regsub(req.http.Cookie,
"^.*;? ?language=(nl|fr|en|de|es)( ?|;| ;).*$","\1"));
}
}
Ban
A função ban é usada para banir objetos do cache. Todos os objetos que
coincidirem com um padrão especí co serão invalidados pelo mecanismo
de banimento interno do Varnish.
Veremos mais detalhes sobre o banimento e o expurgo no Capítulo 5. No
entanto, só por diversão, mostrarei um exemplo de uma função ban:
sub vcl_recv {
if(req.method == "BAN") {
ban("req.http.host == " + req.http.host + " && req.url == " +
req.url);
return(synth(200, "Ban added"));
}
}
O que esse exemplo faz é remover objetos do cache quando eles são
chamados por intermédio do método HTTP BAN.
Sim, sei que o método BAN não é um método HTTP o cial. Não se preocupe, é
só para uso interno.
Certi que-se de inserir esse fragmento de VCL antes de códigos que procurem
métodos HTTP. Caso contrário, sua solicitação pode acabar sendo canalizada para
o backend. Isso também ocorrerá se você não retornar a resposta sintética.
A função ban recebe um argumento em formato string que compara os
metadados internos do objeto armazenado em cache com os valores que
foram passados. Se um objeto atender a esses critérios, ele será adicionado
à lista de banimento e removido do cache na próxima solicitação.
Synthetic
A função synthetic retorna uma resposta HTTP sintética na qual o corpo
é o valor do argumento que foi passado para a função. O argumento de
entrada da função é uma string. Strings normais e longas são suportadas.
O termo sintético signi ca que a resposta não é resultado de uma busca
no backend. Ela é 100% arti cial e é composta por meio da função
synthetic. Você pode executar a função synthetic várias vezes e a cada
execução a saída será adicionada ao corpo da resposta HTTP.
O código de status da resposta é de nido por resp.status na sub-rotina
vcl_synth. O valor-padrão é, claro, 200.
A função synthetic está restrita a duas sub-rotinas:
• vcl_synth
• vcl_backend_error
Esses são os dois contextos em que não há uma resposta disponível no
backend e a criação de uma resposta sintética faz sentido.
Aqui está um exemplo de código de respostas sintéticas:
sub vcl_recv {
return(synth(201,"I created something"));
}
sub vcl_backend_error {
set beresp.http.Content-Type = "text/html; charset=utf-8";
synthetic("An error occured: " + beresp.reason + "<br />");
synthetic("HTTP status code: " + beresp.status + "<br />");
return(deliver);
}
sub vcl_synth {
set resp.http.Content-Type = "text/html; charset=utf-8";
synthetic("Message of the day: " + resp.reason + "<br />");
synthetic("HTTP status code: " + resp.status + "<br />");
return(deliver);
}
A saída sintética não exibe apenas uma string de literais. Também podemos
analisar valores de entrada. Como você pode ver nos exemplos anteriores, estamos
usando a razão e o status para obter o corpo e o código de status HTTP.
É bom ressaltar que, em vcl_synth, obtemos essas variáveis por meio do objeto
resp. Isso signi ca que estamos interceptando-o diretamente a partir da resposta
que será enviada para o cliente.
Em vcl_backend_error, não usamos o objeto resp, mas sim o objeto beresp.
beresp signi ca backend response. Logo, foi feita uma tentativa de buscar dados no
backend, mas ela falhou. Em vez disso, a mensagem de erro será adicionada à
variável beresp.reason.
Inclusões
Embora você deva tentar o máximo possível usar o VCL interno, em
alguns casos ainda haverá muito código VCL.
Após algum tempo, a grande quantidade de código di culta manter a
visão geral. As inclusões o ajudarão a organizar seu código. A instrução
include é processada pelo compilador VCL e carrega o conteúdo do
arquivo incluído inline.
No exemplo a seguir estamos apenas carregando o arquivo someFile.vcl.
Seu conteúdo será inserido dentro da sub-rotina vcl_recv:
sub vcl_recv {
include "someFile.vcl";
}
Este poderia ser o conteúdo do arquivo someFile.vcl:
if ((req.method != "GET" && req.method != "HEAD")
|| req.http.Authorization || req.http.Cookie) {
return (pass);
}
Variáveis VCL
Você já deve estar familiarizado com req.url e client.ip. Sim, há variáveis
VCL e não são poucas.
A seguir temos uma lista dos diferentes objetos de variável:
bereq
Estrutura de dados de solicitação ao backend.
beresp
Objeto de variável de resposta do backend.
client
Objeto de variável que contém informações sobre a conexão do cliente.
local
Informações sobre a conexão TCP local.
now
Informações sobre a hora atual.
obj
Objeto de variável que contém informações sobre um objeto que está
armazenado em cache.
remote
Informações sobre a conexão TCP remota. Trata-se do cliente ou de um
proxy que esteja na frente do Varnish.
req
Objeto de variável da solicitação.
req_top
Informações sobre a solicitação de nível superior de uma árvore de
solicitações ESI.
resp
Objeto de variável da resposta.
server
Informações sobre o servidor Varnish.
storage
Informações sobre o mecanismo de armazenamento.
A Tabela 4.1 lista algumas variáveis úteis e explica o que elas fazem. Para
ver uma lista de variáveis completa, consulte a seção de variáveis
(https://www.varnish-cache.org/docs/4.1/reference/vcl.html#variables) na
parte do site de documentação do Varnish referente ao VCL.
Tabela 4.1 – Alguns objetos úteis do VCL
Legível/Gravável
Variável Retorna Signi cado
a partir de
beresp.do_esi booleano Processa o Edge Side vcl_backend_response,
Includes após buscá-lo. vcl_backend_error
O padrão é false.
Con gure-a com true
para analisar o objeto
em relação às diretivas
ESI. Só será respeitada
se req.esi for true.
beresp.do_stream booleano Distribui o objeto para o vcl_backend_response,
cliente diretamente sem vcl_backend_error
buscá-lo por inteiro no
Varnish. Se essa
solicitação for passada
adiante ela não será
armazenada na
memória.
beresp.grace duração Con gure com um vcl_backend_response,
período para ativar o vcl_backend_error
modo grace.
beresp.http. cabeçalho Cabeçalho HTTP vcl_backend_response,
correspondente. vcl_backend_error
Legível/Gravável
Variável Retorna Signi cado
a partir de
beresp.keep duração Con gure com um vcl_backend_response,
período para permitir o vcl_backend_error
envio de solicitações
condicionais ao
backend. O tempo de
manutenção (keep time)
é o tempo de existência
no cache mais o tempo
de vida.
beresp.reason string Mensagem de status vcl_backend_response,
HTTP retornada pelo vcl_backend_error
servidor.
beresp.status inteiro Código de status HTTP vcl_backend_response,
retornado pelo servidor. vcl_backend_error
beresp.ttl duração Tempo de vida restante vcl_backend_response,
do objeto, em segundos. vcl_backend_error
beresp.uncacheable booleano A ativação dessa variável vcl_backend_response,
torna o objeto vcl_backend_error
inalcançável, e ele pode
ser armazenado como
um objeto hit-for-pass
no cache.
client.identity string Identi cação do cliente, client
usada no balanceamento
de carga em seu diretor.
O padrão é client.ip.
client.ip (*) IP Endereço IP do cliente. client
local.ip (*) IP Endereço IP da client
extremidade local da
conexão TCP.
obj.age (*) duração Idade do objeto. vcl_hit
obj.grace (*) duração Tempo extra restante do vcl_hit
objeto em segundos.
obj.hits (*) inteiro Contagem de acertos no vcl_hit,
cache para esse objeto. vcl_deliver
Um valor igual a 0
indica um cache miss.
Legível/Gravável
Variável Retorna Signi cado
a partir de
obj.ttl (*) duração Tempo de vida restante vcl_hit
do objeto, em segundos.
remote.ip (*) IP Endereço IP da outra client
extremidade da conexão
TCP. Pode ser o
endereço IP do cliente
ou o endereço IP de
saída de um servidor
proxy.
req.backend_hint backend Con gura client
bereq.backend com esse
valor quando uma busca
no backend é necessária.
req.hash_always_miss booleano Força um cache miss vcl_recv
para essa solicitação. Se
con gurada com true, o
Varnish desconsiderará
qualquer objeto
existente e sempre fará
uma (nova) busca no
backend. Isso nos
permite atualizar o valor
de um objeto sem ser
preciso expurgá-lo ou
bani-lo.
req.http. cabeçalho Cabeçalho HTTP client
correspondente.
req.method string Tipo da solicitação (por client
exemplo, GET, HEAD,
POST, …).
req.url string URL solicitado. client
resp.reason string Mensagem de status vcl_deliver,
HTTP retornada. vcl_synth
resp.status int Código de status HTTP vcl_deliver,
retornado. vcl_synth
server.ip (*) IP Endereço IP do servidor client
em que a conexão do
cliente foi recebida.
(*) A opção "Gravável a partir de" não é aplicável nestas variáveis.
Embora esse arquivo do mundo real aumente a taxa de acertos, ele não foi
ajustado para nenhum CMS ou framework especí co. Se você precisar de um
arquivo VCL que considere aplicativos especí cos, eles costumam vir com um
módulo de CMS ou framework.
Há excelentes templates VCL disponíveis. Eu mesmo poderia criar um,
mas estaria apenas reinventando a roda. De acordo com o espírito open
source, pre ro mostrar um dos templates VCL mais populares existentes.
O autor do arquivo VCL é Mattias Geniar (https://ma.ttias.be/), um colega
belga, membro da indústria de hospedagem, amigo e um verdadeiro
defensor do Varnish. Acesse seu repositório no GitHub
(https://github.com/mattiasgeniar/varnish-4.0-con guration-templates) para
ver o código.
Esse template VCL sanitiza a solicitação, otimiza conexões de backend,
facilita expurgos, calcula estatísticas de cache e adiciona o suporte ao ESI.
Conclusão
Agora você já conhece a sintaxe, as funções, as diferentes estruturas de
linguagem, os tipos de retorno, os objetos de variável e o uxo de
execução do VCL. Use este capítulo como referência quando em dúvida.
Não se esqueça de que o projeto Varnish Cache tem um site de
documentação (https://www.varnish-cache.org/docs/4.1/) bastante
completo. Se você não encontrar a resposta para sua pergunta neste livro,
provavelmente a encontrará nele.
A essa altura, espero que você esteja se sentindo à vontade com a sintaxe
do VCL e consiga ler e interpretar os fragmentos de linguagem que
encontrar. No Capítulo 7, examinaremos em detalhes alguns cenários
comuns em que o VCL personalizado é necessário.
Invalidando o cache
Expurgo
O expurgo é a maneira mais fácil de invalidar o cache. No exemplo a
seguir, é possível ver que no VCL podemos executar um return (purge) de
dentro da sub-rotina vcl_recv. Isso removerá o objeto explicitamente do
cache. O objeto é identi cado pelos critérios de nidos em vcl_hash, logo,
por padrão, eles serão o nome do host e o URL. A memória será liberada
de imediato e variações de cache também serão removidas.
acl purge {
"localhost";
"192.168.55.0"/24;
}
sub vcl_recv {
# permite a execução de PURGE a partir de localhost e 192.168.55...
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return(synth(403,"Not allowed."));
}
return (purge);
}
}
Há algumas tarefas preparatórias envolvidas se você quiser proceder da
maneira correta: o exemplo anterior nos protege contra invalidações
desautorizadas impondo o uso de uma ACL. Só expurgos provenientes de
localhost ou da sub-rede 192.168.55.0/24 são permitidos.
Depois há a veri cação do método de solicitação PURGE. Ao solicitar o
recurso com PURGE em vez de GET, você está basicamente informando ao
Varnish que essa solicitação HTTP não é uma solicitação de recuperação
de dados comum, mas sim uma solicitação de expurgo.
Você deve estar lembrado da seção “Quando o Varnish contorna o cache?”. Nela
mencionei que só certos métodos de solicitação são considerados válidos pelo
Varnish. PURGE não é um deles. Por isso é importante fazer a veri cação de PURGE
antes que ocorra a validação do método de solicitação. Caso contrário, você entrará
no modo pipe e a solicitação será enviada para o backend, retornando um código
de status HTTP 200 de validade ou, se seu servidor web não permitir PURGE, um
erro HTTP 405.
Podemos implementar uma chamada de expurgo em qualquer local do
código, normalmente usando um cliente HTTP suportado por nosso
framework ou linguagem de programação. Em muitos casos, esse cliente é
baseado no cURL. Aqui está um exemplo de expurgo que usa o binário
cURL:
curl -XPURGE http://example.com/some/page
Esse exemplo usa o parâmetro -X em cURL para de nir o método da
solicitação. Como esperado, estamos con gurando-o com PURGE e
de nindo o URL como http://example.com/some/page. Esse é o recurso
que estamos removendo do cache.
Banimento
O expurgo é fácil: ele usa o hash de um objeto, remove apenas esse objeto
e pode ser executado com um simples return(purge).
No entanto, quando há um grande número de expurgos para serem
executados ou quando não temos certeza dos recursos que são obsoletos,
invalidações rigorosas de URLs podem ser restritivas. Um mecanismo de
invalidação baseado em padrão resolveria esse problema, e o banimento
faz exatamente isso.
O banimento não é um conceito desconhecido para você; em “Ban”,
falamos sobre a função ban que o executa.
Basicamente, os banimentos usam uma veri cação de expressão regular
para marcar os objetos que devem ser removidos do cache. Os objetos
marcados são colocados na chamada lista de banimento. O banimento
não remove itens do cache de imediato e, portanto, não libera memória na
mesma hora.
Os banimentos são veri cados quando um objeto é acessado e são
executados de acordo com a lista de banimento. Também há a chamada
thread de segundo plano espreitadora de banimentos (ban lurker) que
procura banimentos que apresentem uma correspondência com variáveis
do objeto obj.
Mais exibilidade
Examinaremos mais um exemplo de banimento que reúne tudo o que já
vimos e proporciona ainda mais exibilidade:
acl ban {
"localhost";
"192.168.55.0"/24;
}
sub vcl_backend_response {
set beresp.http.x-host = bereq.http.host;
set beresp.http.x-url = bereq.url;
}
sub vcl_deliver {
unset resp.http.x-host;
unset resp.http.x-url;
}
sub vcl_recv {
if (req.method == "BAN") {
if (!client.ip ~ ban) {
return(synth(403, "Not allowed."));
}
if(req.http.x-ban-regex) {
ban("obj.http.x-host == " + req.http.host + "
&& obj.http.x-url ~ " + req.http.x-ban-regex);
} else {
ban("obj.http.x-host == " + req.http.host + "
&& obj.http.x-url == " + req.url);
}
return(synth(200, "Ban added"));
}
}
O exemplo combina os benefícios dos exemplos de banimento anteriores.
Ele nos dá a exibilidade de escolher entre uma procura de URL rigorosa
ou uma busca de expressão regular. Se você de nir o cabeçalho de
solicitação x-ban-regex ao fazer o banimento, o valor será usado na
veri cação do padrão do URL. Se o cabeçalho não for de nido, o próprio
URL (e nada mais) será banido. E é claro que esse é um banimento
amigável com o espreitador.
Aqui está um exemplo que usa o binário cURL:
curl -XBAN http://example.com/ -H"x-ban-regex: ^/product/[0-
9]+/details"
Nesse exemplo, estamos expurgando todas as páginas de detalhes do
produto baseando-nos na expressão regular ^/product/[0-9]+/details. Se
você só quiser expurgar uma única página de detalhes do produto, a
chamada a curl seria:
curl -XBAN http://example.com/product/121/details
O comando anterior deve ser digitado em uma única linha sem quebra. Aqui só
usei a quebra de linha devido a restrições de página.
Conclusão
A essa altura, você já sabe que a invalidação de cache é importante e que
o Varnish oferece o banimento, o expurgo e a atualização forçada para sua
execução.
Você pode invalidar o cache usando chamadas HTTP ou conectar-se com
o varnishadm e emitir o comando ban sem ter de escrever um código VCL
especí co para fornecer a invalidação.
Invalidar o cache não é apenas importante – também é muito difícil. O
truque é conseguir mapear suas rotas HTTP para os dados impactados.
Seleção do backend
Em capítulos anteriores, mencionei que há duas maneiras de anunciar o
backend para o Varnish:
• Adicionando um backend ao nosso arquivo VCL.
• Ou omitindo totalmente o VCL e usando a ag -b na hora da
inicialização.
É assim que é feito automaticamente. No entanto, em certas situações
podem existir vários backends e você poderia querer controlar qual
solicitação irá para qual backend. Podemos de nir vários backends e usar
req.backend_hint para atribuir um backend diferente do padrão.
Aqui está um exemplo:
vcl 4.0;
backend public {
.host = "web001.example.com";
}
backend admin {
.host = "web002.example.com";
}
sub vcl_recv {
if(req.url ~ "^/admin(/.*)?") {
set req.backend_hint = admin;
} else {
set req.backend_hint = public;
}
}
Observe que de nimos dois backends:
• Um que manipula tráfego público e reside em web001.example.com.
• E outro que serve o painel de administração e reside em
web002.example.com.
Incorporando a variável req.backend_hint à lógica do VCL, podemos
executar um balanceamento de carga que reconheça o conteúdo. Cada
backend poderia ser ajustado para sua tarefa especí ca.
Integridade do backend
Em “Backends e sondagens de integridade”, discutimos como veri cações
de integridade podem ser executadas com o uso de sondagens. Pegaremos
nosso exemplo anterior e adicionaremos uma sondagem de integridade:
vcl 4.0;
probe healthcheck {
.url = "/";
.interval = 5s;
.timeout = 1s;
.window = 10;
.threshold = 3;
.initial = 1;
.expected_response = 200;
}
backend public {
.host = "web001.example.com";
.probe = healthcheck;
}
backend admin {
.host = "web002.example.com";
.probe = healthcheck;
}
sub vcl_recv {
if(req.url ~ "^/admin(/.*)?") {
set req.backend_hint = admin;
} else {
set req.backend_hint = public;
}
}
As veri cações de integridade desse exemplo são executadas com base em
uma solicitação HTTP feita à homepage. A veri cação é feita a cada cinco
segundos com tempo-limite de um segundo. É esperado um código de
status HTTP 200. Os backends só são considerados íntegros quando 3
entre 10 veri cações são bem-sucedidas.
Você pode visualizar a integridade de seus backends executando o
comando a seguir:
varnishadm backend.list
A saída do comando poderia ser esta:
Backend name Admin Probe
boot.public probe Healthy 10/10
boot.admin probe Healthy 10/10
Os dois backends são listados e sua integridade é veri cada
automaticamente por uma sondagem (veja a coluna Admin). Eles foram
considerados íntegros porque todas as 10 veri cações foram bem-
sucedidas. Lembre-se: só três veri cações precisam ser bem-sucedidas
para termos um backend íntegro.
Para obter uma saída mais verbosa, use o parâmetro -p:
varnishadm backend.list -p
A saída poderia ser esta:
Backend name Admin Probe
boot.public probe Healthy 10/10
Current states good: 10 threshold: 3 window: 10
Average response time of good probes: 0.575951
Oldest ================================================== Newest
4444444444444444444444444444444444444444444444444444444444444444 Good
IPv4 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Good Xmit
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR Good
Recv HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
Happy
boot.admin probe Healthy 3/10
Current states good: 3 threshold: 3 window: 10
Average response time of good probes: 0.642713
Oldest ================================================== Newest
4444444444444444444444444444444444444444444444---------------444 Good
IPv4 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX---------------XXX
Good Xmit
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR---------------RRR Good
Recv HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---------------HHH
Happy
É possível ver que as últimas três veri cações do backend admin foram
bem-sucedidas, e essas três veri cações são su cientes para que ele seja
considerado íntegro. Esse é um backend que se recuperou de um estado
de “enfermidade”.
Se você executar esse comando continuamente (o comando watch do
Linux pode ajudá-lo nisso), poderá ver a evolução das veri cações de
integridade (Xmit), as respostas (Recv) e o restabelecimento de seu servidor.
Você também pode sobrepor manualmente a decisão da sondagem sobre
a integridade do backend emitindo os comandos a seguir:
varnishadm backend.set_health boot.public sick
varnishadm backend.set_health boot.admin healthy
A saída é a seguinte:
Backend name Admin Probe
boot.public sick Healthy 10/10
boot.admin healthy Healthy 10/10
Como você pode ver, a coluna Admin não contém mais o valor probe, mas
sim sick e healthy. Para devolver o controle para as sondagens de
integridade, basta emitir os comandos a seguir:
varnishadm backend.set_health boot.public auto
varnishadm backend.set_health boot.admin auto
A função std.healthy() que faz parte do vmod_std pode informar se um
backend é ou não íntegro. Para veri car a integridade do backend atual,
use std.healthy(req.backend_hint).
Diretores
Um diretor é um VMOD interno que agrupa vários backends e os
apresenta como uma única entidade. Os diretores oferecem diferentes
estratégias de tomada de decisões para de nir qual backend manipulará
determinada solicitação.
O objetivo dos diretores é evitar a latência do backend distribuindo
solicitações por vários backends: pelo balanceamento das solicitações
feitas aos backends, os servidores backend receberão cargas menores, o
que reduz a latência. Essa é basicamente uma estratégia de escalabilidade
horizontal.
Além do simples balanceamento de carga, os diretores também
asseguram que nós backend com problemas não sejam usados; em vez
disso, outro nó íntegro é usado para manipular essas solicitações. Essa é
uma estratégia de alta disponibilidade.
Para usar diretores, primeiro é preciso importar o VMOD directors e
inicializá-lo em vcl_init. Aqui está um exemplo:
vcl 4.0;
import directors;
backend web001 {
.host = "web001.example.com";
.probe = healthcheck;
}
backend web002 {
.host = "web002.example.com";
.probe = healthcheck;
}
sub vcl_init {
new loadbalancing = directors.round_robin();
loadbalancing.add_backend(web001);
loadbalancing.add_backend(web002);
}
sub vcl_recv {
set req.backend_hint = loadbalancing.backend();
}
Vejamos esse exemplo passo a passo:
1. Primeiro importamos o VMOD directors.
2. Declaramos dois backends.
3. Inicializamos o diretor e de nimos a estratégia de balanceamento de
carga (nesse caso, “round robin”).
4. Atribuímos os dois backends ao diretor.
5. Em seguida, temos um novo backend que chamamos de
loadbalancing.
6. Atribuímos o backend loadbalancing ao Varnish emitindo set
req.backend_hint = loadbalancing.backend();.
Mais informações sobre diretores podem ser encontradas na página de
documentação do Varnish sobre vmod_directors (https://www.varnish-
cache.org/docs/4.1/reference/vmod_directors.generated.html).
Diretor round-robin
O exemplo anterior continha uma parte referente ao diretor round-robin,
mas o que isso signi ca? Round-robin é uma estratégia básica de
distribuição em que os backends se revezam sequencialmente. Se você
tiver três backends, a sequência será:
• Backend 1
• Backend 2
• Backend 3
• Backend 1
• Backend 2
• Backend 3
•…
A carga é distribuída igualmente – o que não é novidade. Quase sempre,
o round-robin é um bom algoritmo, mas há cenários em que ele não tem
um desempenho aceitável. Considere, por exemplo, uma situação em que
seus servidores backend não tivessem os mesmos recursos. O servidor
com menos memória ou CPU terá de executar o mesmo volume de
trabalho.
Aqui está um exemplo de uma declaração de diretor round-robin que usa
três backends:
sub vcl_init {
new loadbalancing = directors.round_robin();
loadbalancing.add_backend(backend1);
loadbalancing.add_backend(backend2);
loadbalancing.add_backend(backend3);
}
Após declararmos o diretor, ele precisa ser atribuído em vcl_recv:
sub vcl_recv {
set req.backend_hint = loadbalancing.backend();
}
Diretor hash
O diretor hash seleciona o backend de acordo com um hash SHA256 de
determinado valor. O valor submetido ao hash é passado para o método
backend() do objeto de diretor.
Em geral, o diretor hash é usado para facilitar sticky sessions1 fazendo o
hash do endereço IP do cliente ou de um cookie da sessão. Ao fazer o hash
de um desses valores, o Varnish assegura que solicitações para o mesmo
usuário ou sessão sempre alcancem o mesmo backend. Isso é importante
para servidores backend que armazenam os dados de sua sessão
localmente.
Você também poderia fazer o hash por URL da solicitação. As solicitações
de um determinado URL serão sempre enviadas para o mesmo backend.
O perigo de fazer o hash pelo endereço IP do cliente ou pelo URL da
solicitação é que a carga não será distribuída igualmente, como nos casos
a seguir:
• O endereço IP do cliente pode ser de um servidor proxy usado por
vários usuários, trazendo uma carga volumosa para um backend
especí co.
• Um URL pode ser mais popular que o outro, trazendo uma carga
volumosa para um backend especí co.
É assim que declaramos um diretor hash:
sub vcl_init {
new loadbalancing = directors.hash();
loadbalancing.add_backend(backend1,1.0);
loadbalancing.add_backend(backend2,1.0);
}
Esse exemplo atribui dois backends com o mesmo peso, que é o valor
recomendado. Se você alterar os pesos, um servidor receberá mais
solicitações que o outro, porém solicitações do mesmo usuário, URL ou
sessão continuarão sendo enviadas para o mesmo backend.
Com os diretores hash, a mágica está na atribuição, não na declaração.
Vejamos um exemplo de diretor hash que faz o hash por endereço IP do
cliente:
sub vcl_recv {
set req.backend_hint = loadbalancing.backend(client.ip);
}
Como expliquei, fazer o hash por endereço IP é arriscado. Aqui está um
exemplo em que o hash é feito por cookie da sessão:
sub vcl_recv {
set req.backend_hint =
loadbalancing.backend(regsuball(req.http.Cookie,
"^.*;? ?PHPSESSID=([a-zA-Z0-9]+)( ?|;| ;).*$","\1"));
}
Esse exemplo usa o cookie PHPSESSID que contém o ID de sessão gerado
pela função session_start() em PHP.
E aqui está um último exemplo, em que fazemos o hash do URL:
sub vcl_recv {
set req.backend_hint = loadbalancing.backend(req.url);
}
Diretor fallback
O último diretor que vou apresentar é o diretor fallback. Para esse diretor,
a ordem de atribuições de backend é muito importante: o diretor fallback
testa cada backend e retorna o primeiro que for íntegro.
Modo grace
No decorrer deste capítulo, nos dedicamos a fornecer um serviço backend
estável de modo que o Varnish possa acessar dados do backend sem
nenhuma interrupção:
• Avaliando a integridade do backend
• Adicionando sondagens de veri cação de integridade
• Oferecendo diretores para distribuição de carga
• Bene ciando-nos de diretores para usar nós íntegros em vez de nós
com problemas
No entanto, uma pergunta importante permanece sem resposta: o que
fazer se não houver backends disponíveis?
Podemos conviver com isso ou remediar o problema. Pre ro a segunda
alternativa, e é aí que o modo grace entra em cena.
Se atribuirmos uma quantidade especí ca de tempo de vida extra,
estaremos basicamente dizendo ao Varnish que ele pode servir objetos
além de seu tempo de vida. Esses objetos são considerados “obsoletos” e
serão servidos contanto que não haja um objeto atualizado pelo período
de nido no tempo extra.
A lógica de acertos interna do VCL explica melhor:
sub vcl_hit {
if (obj.ttl >= 0s) {
// Acerto puro não adulterado, distribua-o
return (deliver);
}
if (obj.ttl + obj.grace > 0s) {
// O objeto está no modo grace, distribua-o
// Aciona automaticamente uma busca em segundo plano
return (deliver);
}
// Busca e distribui ao obter o resultado
return (miss);
}
• Se o objeto não tiver expirado (obj.ttl >= 0s), continue servindo-o.
• Se o objeto tiver expirado, mas ainda houver algum tempo extra
(obj.ttl + obj.grace > 0s), continue servindo-o, mas procure uma nova
versão assincronamente.
• Caso contrário, procure uma nova versão e coloque a solicitação na
la.
Conclusão
Você passou muito tempo aprendendo como o Varnish funciona e como
obter dados no cache. Grande parte de sua atenção foi dedicada ao lado
do cliente: servindo dados armazenados em cache para o usuário nal. No
entanto, não nos esqueçamos de que o Varnish depende de um backend
íntegro para fazer seu trabalho.
Agora você já sabe como conectar o Varnish a um ou vários backends.
Pode con gurar todos os tipos de tempos-limite e consegue veri car a
integridade de um backend. Também deve se sentir seguro para evitar
backends com problemas usando diretores ou o modo grace.
Usando algumas das dicas e truques deste capítulo, você terá uma taxa
maior de disponibilidade. Independentemente de sua taxa de acertos,
você ainda precisará de seu backend para a revalidação de conteúdo, logo
certi que-se de considerar a disponibilidade de seus servidores backend.
1 O conceito de sticky sessions signi ca con gurar o balanceador de carga para anexar
uma sessão de usuário a uma instância especí ca.
CAPÍTULO 7
Erros comuns
Lembro-me de que quando comecei a usar o Varnish, pensei que tinha
feito tudo que era necessário. Li o manual, copiei e colei código VCL e
adicionei uma camada de Varnish ao site de um cliente. Tudo isso como
uma tentativa de proteger o site do impacto de uma grande campanha de
marketing.
Contudo, as coisas não saíram como o planejado. Eu estava usando o
cache com muita voracidade e armazenei até os cookies. Isso resultou em
uma versão em cache do carrinho de compras e da página de login. Não
preciso dizer que o cliente cou insatisfeito.
Houve outras situações em que a taxa de acertos foi muito baixa e isso
ocorreu porque eu não conhecia o VCL interno. Estava apenas criando
VCL em vcl_recv sem sair da sub-rotina com instruções de retorno como
hash ou pass. O Varnish continuou seguindo sua linha de ação e usando o
comportamento-padrão que descartava minhas alterações.
Vejo clientes que criam seu próprio VCL cometerem erros semelhantes.
Resumo da história: há um conjunto de erros comuns que as pessoas
cometem, portanto veremos como evitar as armadilhas mais comuns.
Não saber o que é hit-for-pass
Muitas pessoas se esquecem de que o Varnish cria um objeto hit-for-pass
quando os objetos buscados não podem ser armazenados em cache. O
Varnish mantém a decisão de não armazenar em cache por 120 segundos.
Os objetos do cache hit-for-pass não são en leirados como erros de
acesso comuns e estabelecem diretamente uma conexão com o backend.
Esse mecanismo gera um impacto e pode levar a conclusões estranhas se
você não preparar algumas contingências.
Imagine uma situação em que você con gurasse s-maxage
temporariamente com zero visando uma depuração mais rápida. Se zer a
rede nição com um valor armazenável em cache dentro de 120 segundos
da solicitação anterior, ele continuará não sendo armazenado em cache.
Isso confunde as pessoas.
Meu conselho
Faça o expurgo ou o banimento do URL que está preso no cache hit-for-
pass e o cabeçalho Cache-control atualizado surgirá.
Meu conselho
Inclua o código do VCL interno que você esteja precisando ou apenas
remova a instrução explícita return(hash); para voltar para o VCL interno.
Embora eu esteja dizendo que devemos usar no-store, você pode obter o mesmo
resultado usando uma das instruções Cache-control a seguir:
• no-cache
• private
• s-maxage=0
• max-age=0
Painel de administração
Imagine um site controlado por um CMS. As páginas propriamente ditas
são estáticas, mas o painel de administração hospedado sob /admin é
dinâmico e requer login. Após ser feito o login, um cookie de sessão que
rastreia o ID da sessão. Soa familiar?
Este é o VCL necessário para você armazenar o site em cache, mas ainda
ter acesso dinâmico ao painel de administração:
sub vcl_recv {
if (!(req.url ~ "^/admin/")) {
unset req.http.Cookie;
}
}
Já que só precisamos de cookies quando estamos na seção /admin,
podemos removê-los de todas as outras páginas. Observe que não
estamos “retornando”; estamos deixando o resto do uxo para o VCL
interno.
Sanitizando
Até agora, a única limpeza de entradas que zemos foi baseada em
cookies. No entanto, a maneira como o URL é usado também pode
atrapalhar nossa taxa de acertos. A seguir temos algumas correções
rápidas que otimizam os URLs para evitar cache misses desnecessários.
Removendo a porta
O próximo exemplo remove o número da porta do host HTTP. O número
da porta pode ser importante do ponto de vista do TCP, mas uma vez que
você tiver alcançado o Varnish, já terá entrado. Manter o número da porta
pode causar uma variação de cache e provocar erro de acesso.
Com a remoção da porta, a condição de conectividade não é
interrompida, mas o cabeçalho de host é sanitizado e a taxa de acertos
mantida.
sub vcl_recv {
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
}
Marcador de acerto/erro
Um acréscimo útil aos cabeçalhos de resposta seria o de um cabeçalho
personalizado que nos permitisse saber se a página que estamos vendo é
resultado de um acerto ou de um erro de acesso ao cache. Este é o código
VCL necessário para exibir o tão conveniente marcador de acerto/erro:
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
}
Também temos o cabeçalho Age para saber por quanto tempo a página foi
servida a partir do cache até o momento.
AJAX
AJAX é a abreviação de Asynchronous JavaScript and XML e não tem
nada a ver com o Varnish. Usando AJAX, você estará basicamente
permitindo que seu navegador carregue os diferentes blocos como
solicitações HTTP separadas. Isso é feito em JavaScript, portanto é uma
ação do lado do cliente.
A desvantagem é que há uma solicitação HTTP para cada bloco de
conteúdo, o que causa overhead. Já a vantagem das solicitações HTTP
separadas é que você pode controlar o tempo de vida e a capacidade de
armazenamento em cache de cada bloco de nindo os cabeçalhos Cache-
control certos.
Podemos usar o AJAX nativamente inicializando um objeto
XMLHttpRequest, mas a maioria das pessoas usa a implementação do AJAX
criada para seu framework JavaScript favorito.
Em termos de cache, seria ótimo se o aplicativo tivesse controle total.
Nunca é demais repetir: os cabeçalhos Cache-control são tudo que é
necessário para que isso ocorra. No entanto, se você não quiser se
preocupar com a disciplina do cabeçalho Cache-control, basta escrever um
código VCL para manipular a situação. A ideia é esta: se você só estiver
usando o AJAX para carregar blocos que de outra forma não seriam
armazenados em cache, pode passar todas as solicitações AJAX ao
backend. Este é o código VCL a ser usado:
sub vcl_recv {
if (req.url ~ "^.*/ajax/.*$")
{
return (pass);
}
}
Você pode estar achando minhas suposições simples e arriscadas, e
concordo: quando o URL contém uma parte /ajax/, presumimos o uso do
AJAX e não fazemos o armazenamento em cache. Mas espere, resolvemos
o problema!
Arquivo do Composer
Este é o arquivo composer.json necessário para você executar o exemplo:
{
"require": {
"silex/silex": "^2.0",
"twig/twig": "^1.27",
"symfony/twig-bridge": "^3.1",
"symfony/translation": "^3.1"
}
}
Código PHP
Este é o código PHP que renderiza a saída:
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Silex\Provider\HttpFragmentServiceProvider;
use Silex\Provider\HttpCacheServiceProvider;
$app = new Silex\Application();
$app['debug'] = true;
$app->register(new Silex\Provider\TwigServiceProvider(),
['twig.path' => __DIR__.'/../views']);
$app->register(new HttpFragmentServiceProvider());
$app->register(new HttpCacheServiceProvider());
$app->register(new Silex\Provider\TranslationServiceProvider(),
['locale_fallbacks' => ['en']]);
$app['locale'] = 'en';
$app['translator.domains'] = [
'messages' => [
'en' => [
'welcome' => 'Welcome to the site',
'rendered' => 'Rendered at %date%',
'example' => 'An example page'
],
'nl' => [
'welcome' => 'Welkom op de site',
'rendered' => 'Samengesteld op %date%',
'example' => 'Een voorbeeldpagina'
]
]
];
$app->before(function (Request $request) use ($app){
$app['translator']->setLocale($request->getPreferredLanguage());
});
$app->after(function(Request $request, Response $response) use ($app){
$response
->setVary('Accept-Language')
->setETag(md5($response->getContent()))
->isNotModified($request);
});
$app->get('/', function () use($app) {
$response = new Response($app['twig']->render('index.twig'),200);
$response
->setSharedMaxAge(5)
->setPublic();
return $response;
})->bind('home');
$app->get('/header', function () use($app) {
$response = new Response($app['twig']->render('header.twig'),200);
$response
->setPrivate()
->setSharedMaxAge(0);
return $response;
})->bind('header');
$app->get('/footer', function () use($app) {
$response = new Response($app['twig']->render('footer.twig'),200);
$response
->setSharedMaxAge(10)
->setPublic();
return $response;
})->bind('footer');
$app->get('/nav', function () use($app) {
$response = new Response($app['twig']->render('nav.twig'),200);
$response
->setSharedMaxAge(20)
->setPublic();
return $response;
})->bind('nav');
$app->run();
Vejamos o que ele faz:
1. Inicializa o autocarregador.
2. Resolve os namespaces.
3. Inicializa o aplicativo Silex.
4. Registra o provedor de serviços Twig (https://twig.sensiolabs.org/) para
carregar e analisar templates Twig.
5. Registra o HttpFragmentServiceProvider para dar suporte ao
carregamento de blocos de conteúdo com o ESI e o AJAX.
6. Registra o HttpCacheServiceProvider para dar suporte ao view helper
do ESI.
7. Registra o TranslationServiceProvider para dar suporte a traduções e
usar seu view helper.
8. De ne inglês como o idioma-padrão.
9. Inicializa as traduções.
10. De ne um hook pré-despacho que usa o valor do cabeçalho Accept-
Language como idioma.
11. Usa um hook pós-despacho que de ne o cabeçalho Vary: Accept-
Language.
12. Usa um hook pós-despacho que de ne o cabeçalho ETag.
13. De ne um hook pós-despacho que veri ca o cabeçalho If-None-Match
e retorna um código de status HTTP 304 se nada tiver mudado.
14. Registra uma rota MVC padrão que manipula a homepage, analisa o
template index.twig e armazena a resposta em cache por cinco
segundos.
15. Registra uma rota MVC para /header que carrega o cabeçalho como
um fragmento HTTP separado. Esse recurso não é armazenado em
cache.
16. Registra uma rota MVC para /footer que carrega o rodapé como um
fragmento HTTP separado. Esse recurso é armazenado em cache por
10 segundos.
17. Registra uma rota MVC para /nav que carrega a navegação como um
fragmento HTTP separado. Esse recurso é armazenado em cache por
20 segundos.
Tudo isso em 77 linhas de código. Nada mau!
Template de índice
Agora precisamos de um template que contenha a saída da homepage.
Aqui está ele:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html"
xmlns:hx="http://purl.org/NET/hinclude">
<head>
<title>Varnish</title>
<meta name="viewport" content="width=device-width, initial-
scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"
/>
<link rel="stylesheet"
href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css
/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on
3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="//rawgit.com/mnot/hinclude/master/hinclude.js">
</script>
</head>
<body>
<div class="container-fluid">
{{ render_hinclude(url('header')) }}
<div class="row">
<div class="col-sm-3 col-lg-2">
{{ render_esi(url('nav')) }}
</div>
<div class="col-sm-9 col-lg-10">
<div class="page-header">
<h1>{{ 'example' | trans }}
<small>{{ 'rendered' |
trans({'%date%':"now"|date("Y-m-d H:i:s")}) }}
</small></h1>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Mauris consequat orci eget libero sollicitudin, non
ultrices turpis mollis. Aliquam sit amet tempus elit.
Ut viverra risus enim, ut venenatis justo accumsan nec.
Praesent a dolor tellus. Maecenas non mauris leo.
Pellentesque lobortis turpis at dapibus laoreet. Mauris
rhoncus nulla et urna mollis, et lobortis magna ornare.
Etiam et sapien consequat,
egestas felis sit amet, dignissim enim.</p>
<p>Quisque quis mollis justo, imperdiet fermentum velit.
Aliquam nulla justo, consectetur et diam non, luctus
commodo
metus. Vestibulum fermentum efficitur nulla non luctus.
Nunc lorem nunc, mollis id efficitur et, aliquet sit amet
ante.
Sed ipsum turpis, vehicula eu semper eu, malesuada eget
leo.
Vestibulum venenatis dui id pulvinar suscipit. Etiam nec
massa pharetra justo pharetra dignissim quis non magna.
Integer id convallis lectus. Nam non ullamcorper metus.
Ut vestibulum ex ut massa posuere tincidunt.
Vestibulum hendrerit neque id lorem rhoncus aliquam. Duis a
facilisis metus, a faucibus nulla.</p>
</div>
</div>
{{ render_esi(url('footer')) }}
</div>
</body>
</html>
Esse template Twig é carregado na linha 46 do código PHP anterior. Ele
contém HTML que é estilizado pela biblioteca Twitter Bootstrap
(http://getbootstrap.com/).
Também estou usando a biblioteca JavaScript hinclude.js
(http://mnot.github.io/hinclude/) para executar chamadas hx:include. Elas
são tags de espaço reservado semelhantes às tags ESI. Essas tags não são
processadas na borda; em vez disso são processadas pelo navegador. É
uma forma alternativa de AJAX.
O cabeçalho é renderizado pela chamada a {{
render_hinclude(url(header)) }}. Esse view helper renderiza uma rota
nomeada chamada header e a exibe como uma tag <hx:include />. A tag é
processada pelo navegador e carrega a rota /header.
O próximo bloco carregado é a navegação. Isso é feito com a chamada a {{
render_esi(url(nav)) }}. Esse view helper carrega uma rota nomeada
chamada nav e exibe esse bloco como uma tag ESI. A tag é processada
pelo Varnish e carrega a rota /nav.
O último bloco carregado é o rodapé, que é renderizado pela chamada a
{{ render_esi(url(footer)) }} e que também carrega uma rota nomeada
de maneira semelhante usando o ESI.
Uma última observação sobre o template de índice: você deve ter notado
{{ example | trans }} e {{ rendered | trans({%date%:"now" | date("Y-m-d
H:i:s")})}}. Essas são chaves de tradução que são traduzidas pelo ltro
trans. Dependendo do idioma, a mensagem certa é analisada nesses
placeholders. Injetamos até mesmo a data e a hora atuais no segundo
placeholder.
Template de cabeçalho
O cabeçalho foi carregado como um fragmento HTTP separado no
template de índice. Este é o template Twig que é carregado quando
/header é chamada:
<div class="jumbotron">
<div class="page-header">
<h1>{{ 'welcome'|trans }}
<small>{{ 'rendered' | trans({'%date%':"now"|date("Y-m-d
H:i:s")}) }}
</small></h1>
</div>
</div>
Como você pode ver, é HTML simples com o acréscimo de alguns
placeholders Twig e ltros que fornecem traduções.
Template nav
O template de navegação também é um template Twig, mas ele só contém
o bom e velho HTML. Não há nada de especial a relatar.
<nav class="navbar navbar-default navbar-fixed-side">
<ul class="nav">
<li><a href="#">Item 1</a></li>
<li><a href="#">Item 2</a></li>
</ul>
</nav>
Template de rodapé
Para concluir, há o template de rodapé que exibe uma mensagem
traduzida e a data atual, convertidas na mensagem com o uso do view
helper interno do Twig.
<footer><small>{{ 'rendered' | trans({'%date%':"now"|date("Y-m-d
H:i:s")}) }}
</small></footer>
Conclusão
O abrangente exemplo de código é a prova perfeita de que é possível
projetar um aplicativo altamente armazenável em cache. Se, por alguma
razão, uma parte do conteúdo não for armazenável em cache, fragmentos
HTTP podem ser usados para carregá-la na borda ou no navegador.
Lembre-se sempre de cabeçalhos como Cache-control, Vary, ETag, If-None-
Match, Last-Modified, If-Modified-Since, Surrogate-Capability e Surrogate-
Control. Caso tenha se esquecido deles, volte ao Capítulo 3 e estude-os
novamente!
Se estiver lidando com um aplicativo legado em que seja difícil
implementá-los, basta escrever um código VCL. Não há problema.
1 N.T.: Script kiddie (“garoto dos scripts”, em tradução literal) é um termo atribuído a
indivíduos inexperientes (geralmente de faixas etárias mais novas) que desenvolvem
atividades relacionadas com segurança da informação utilizando-se do trabalho
intelectual dos verdadeiros especialistas técnicos. Não possuem conhecimento de
programação e não estão interessados em tecnologia, mas sim em ganhar fama ou
outros tipos de lucro pessoal.
2 N.T.: Graceful degradation ocorre quando um site continua a operar mesmo sendo
visualizado com um software que não seja o ideal e no qual efeitos avançados não
funcionem.
CAPÍTULO 8
O Varnish também oferece outras ferramentas, mas muitas não têm relação com
o escopo deste livro. Para aprender mais, você pode consultar a documentação de
binários como o varnishhist (https://varnish-
cache.org/docs/4.1/reference/varnishhist.html) e o varnishncsa
(https://varnish-cache.org/docs/4.1/reference/varnishncsa.html).
Varnishstat
O binário varnishstat (https://varnish-
cache.org/docs/4.1/reference/varnishstat.html) exibe estatísticas de uma
instância Varnish que está em execução. São estatísticas gerais sobre
conexões, sessões, backends, armazenamento, taxa de acertos e muito
mais. Esse é um bom painel para administradores de sistemas: ele
compartilha poucas informações sobre o aplicativo e solicitações
individuais, mas proporciona uma visão geral sobre o estado da instância
Varnish. É fácil ver o número de objetos em cache ou o espaço restante no
dispositivo de armazenamento. Você pode até ver se o Varnish está
descartando objetos do cache devido à falta de espaço.
Exemplo de saída
Aqui está um exemplo de saída do varnishstat.
Exibindo métricas especí cas
A saída que você está obtendo não inclui todas as métricas: execute
varnishstat -l para ver uma lista completa.
A seguir temos um exemplo em que estamos exibindo um conjunto
limitado de métricas:
• Todas as informações sobre o cache (acertos, erros, hit-for-passes)
• Número de falhas de backend
• Número de bytes disponíveis no cache
• Número de objetos armazenados em cache
• Número de objetos que foram removidos do cache devido à falta de
espaço
varnishstat -f MAIN.cache_* -f MAIN.backend_fail -f SMA.s0.c_bytes
-f MAIN.n_object -f MAIN.n_lru_nuked
E esta poderia ser a saída:
Uptime mgt: 156+00:32:10 Hitrate
n: 9 9 9
Uptime
child: 38+21:06:23 avg(n): 0.4551 0.4551 0.4551
NAME CURRENT CHANGE AVERAGE AVG_1 AVG_10
0
MAIN.cache_hit 26468969 53.94 7.00 13.74 13.7
4
MAIN.cache_hitpass 3654504 12.98 1.00 3.00 3.0
0
MAIN.cache_miss 4638817 4.99 1.00 3.75 3.7
5
MAIN.backend_fail 71 0.00 . 0.00 0.0
0
SMA.s0.c_bytes 164.34G 95.51K 51.30K 68.35K 68.3
5K
MAIN.n_object 48508 -11.99 . 48512.33 48512.3
3
Formatação da saída
Por padrão, o varnishstat é visualizado como uma lista de métricas
atualizada continuamente. Você pode usar a ag -1 para obter a saída
apenas uma vez.
É possível formatar a saída como XML com a inclusão da ag -x e como
JSON com o uso da ag -j .
Varnishlog
O varnishlog (https://varnish-cache.org/docs/4.1/reference/varnishlog.html) é
uma ferramenta binária que lê os logs em memória compartilhada e exibe
essas informações em tempo real. Ele representa o log como uma lista de
tags e valores. Consulte a extensa lista de tags VSL (https://www.varnish-
cache.org/docs/4.1/reference/vsl.html) no site de documentação do Varnish
e aprenda como interpretar seu valor.
Exemplo de saída
Este exemplo é a saída não ltrada de uma execução do varnishlog:
* << Request >> 65538
- Begin req 1 rxreq
- Timestamp Start: 1476957981.431713 0.000000 0.000000
- Timestamp Req: 1476957981.431713 0.000000 0.000000
- ReqStart 10.10.10.1 60358
- ReqMethod GET
- ReqURL /
- ReqProtocol HTTP/1.1
- ReqHeader Host: example.com
- ReqHeader Connection: keep-alive
- ReqHeader Cache-Control: max-age=0
- ReqHeader Upgrade-Insecure-Requests: 1
- ReqHeader User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X
10_12_0)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143
Safari/537.36
- ReqHeader Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,
image/webp,*/*;q=0.8
- ReqHeader Accept-Encoding: gzip, deflate, sdch
- ReqHeader Accept-Language: nl,en-US;q=0.8,en;q=0.6
- ReqHeader X-Forwarded-For: 10.10.10.1
- VCL_call RECV
- VCL_return hash
- ReqUnset Accept-Encoding: gzip, deflate, sdch
- ReqHeader Accept-Encoding: gzip
- VCL_call HASH
- Hash "/%00"
- Hash "example.com%00"
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- Link bereq 65539 fetch
- Timestamp Fetch: 1476957982.211473 0.779760 0.779760
- RespProtocol HTTP/1.1
- RespStatus 200
- RespReason OK
- RespHeader Date: Thu, 20 Oct 2016 10:06:21 GMT
- RespHeader Server: Apache/2.4.10 (Debian)
- RespHeader Vary: Accept-Encoding
- RespHeader Content-Encoding: gzip
- RespHeader Content-Length: 496
- RespHeader Content-Type: text/html; charset=UTF-8
- RespHeader X-Varnish: 65538
- RespHeader Age: 0
- RespHeader Via: 1.1 varnish-v4
- VCL_call DELIVER
- VCL_return deliver
- Timestamp Process: 1476957982.211516 0.779804 0.000043
- RespHeader Accept-Ranges: bytes
- Debug "RES_MODE 2"
- RespHeader Connection: keep-alive
- Timestamp Resp: 1476957982.211588 0.779875 0.000072
- ReqAcct 424 0 424 289 496 785
- End
** << BeReq >> 65539
-- Begin bereq 65538 fetch
-- Timestamp Start: 1476957981.431787 0.000000 0.000000
-- BereqMethod GET
-- BereqURL /
-- BereqProtocol HTTP/1.1
-- BereqHeader Host: example.com
-- BereqHeader Upgrade-Insecure-Requests: 1
-- BereqHeader User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X
10_12_0)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143
Safari/537.36
-- BereqHeader Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,
image/webp,*/*;q=0.8
-- BereqHeader Accept-Language: nl,en-US;q=0.8,en;q=0.6
-- BereqHeader X-Forwarded-For: 10.10.10.1
-- BereqHeader Accept-Encoding: gzip
-- BereqHeader X-Varnish: 65539
-- VCL_call BACKEND_FETCH
-- VCL_return fetch
-- BackendOpen 33 boot.default 127.0.0.1 8080 127.0.0.1 36222
-- Timestamp Bereq: 1476957981.431879 0.000092 0.000092
-- Timestamp Beresp: 1476957982.211306 0.779520 0.779427
-- BerespProtocol HTTP/1.1
-- BerespStatus 200
-- BerespReason OK
-- BerespHeader Date: Thu, 20 Oct 2016 10:06:21 GMT
-- BerespHeader Server: Apache/2.4.10 (Debian)
-- BerespHeader Vary: Accept-Encoding
-- BerespHeader Content-Encoding: gzip
-- BerespHeader Content-Length: 496
-- BerespHeader Content-Type: text/html; charset=UTF-8
-- TTL RFC 120 10 -1 1476957982 1476957982 1476957981 0 0
-- VCL_call BACKEND_RESPONSE
-- VCL_return deliver
-- Storage malloc s0
-- ObjProtocol HTTP/1.1
-- ObjStatus 200
-- ObjReason OK
-- ObjHeader Date: Thu, 20 Oct 2016 10:06:21 GMT
-- ObjHeader Server: Apache/2.4.10 (Debian)
-- ObjHeader Vary: Accept-Encoding
-- ObjHeader Content-Encoding: gzip
-- ObjHeader Content-Length: 496
-- ObjHeader Content-Type: text/html; charset=UTF-8
-- Fetch_Body 3 length stream
-- Gzip u F - 496 3207 80 80 3901
-- BackendReuse 33 boot.default
-- Timestamp BerespBody: 1476957982.211449 0.779663 0.000143
-- Length 496
-- BereqAcct 406 0 406 196 496 692
-- End
São exibidas tags como:
• ReqURL
• ReqHeader
• VCL_call
• VCL_return
• Hash
• TTL
Todas essas tags e seus respectivos valores fornecem informações muito
detalhadas sobre o estado de uma solicitação. São exibidas informações
da solicitação, os diferentes estágios da Máquina de Estados Finitos
Varnish, conexões de backend opcionais, a maneira como um objeto está
armazenado, o tempo de vida e muito mais.
Essa é uma ferramenta essencial para a depuração. Admito que ela é
extremamente verbosa e, em sistemas em execução, impossível de ser
usada sem a ltragem apropriada.
Filtrando a saída
Felizmente, o varnishlog oferece estas opções de ltragem:
-g
Fornece diferentes tipos de agrupamento de saídas.
-i
Permite só incluir certas tags VSL.
-I
Inclui tags por expressão regular.
-x
Permite excluir certas tags VSL.
-I
Exclui tags por expressão regular.
-q
Permite executar uma consulta VSL.
Em versões mais antigas do Varnish, era difícil depurar o log
compartilhado em memória devido a limitações de ltragem. No Varnish
versão 4, foram introduzidas as consultas VSL (https://www.varnish-
cache.org/docs/4.1/reference/vsl-query.html). Esse recurso trouxe uma
grande melhoria à depuração do comportamento do Varnish.
Aqui está um exemplo em que queremos ver URLs que não sejam
servidos a partir do cache, acompanhado do uxo que é executado para a
obtenção desse resultado:
varnishlog -i ReqUrl -i VCL_call -i VCL_return
-q "VCL_call eq 'MISS' or VCL_call eq 'PASS'"
Estamos interessados em entradas de log em que as tags VCL_call sejam
iguais a miss (armazenável em cache, mas sem estar presente) ou pass
(não armazenável em cache). Após ltrar as solicitações, só exibiremos as
linhas de log que tiverem o URL da solicitação (ReqUrl), os diferentes
estágios da Máquina de Estados Finitos Varnish (VCL_call) e as ações que
foram retornadas para cada estado (VCL_return).
- ReqURL /
- VCL_call RECV
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- VCL_call DELIVER
- VCL_return deliver
Essa solicitação continha os seguintes eventos:
1. Recebida pelo Varnish (VCL_call RECV).
2. O Varnish decidiu que ela era armazenável e executou uma busca no
cache (VCL_return hash).
3. O hash de busca foi composto (VCL_call HASH).
4. Com base no hash, uma busca no cache foi executada (VCL_return
lookup).
5. O item não foi encontrado no cache e disparou um erro de acesso
(VCL_call MISS).
6. Uma conexão com o backend foi estabelecida e houve a busca do item
(VCL_return fetch).
7. Os dados buscados são distribuíveis para o cliente (VCL_call DELIVER).
8. A resposta é retornada com êxito para o cliente (VCL_return deliver).
Varnishtop
O varnishtop (https://varnish-cache.org/docs/4.1/reference/varnishtop.html)
é um binário que usa o mesmo log em memória compartilhada do
varnishlog e emprega o mesmo conceito de tags e valores. Até mesmo as
opções binárias são quase iguais.
Então, o que o torna diferente? Bem, a saída: em vez de exibir linhas de
log como parte de uma solicitação, ele apresenta uma lista atualizada
continuamente com as entradas de log de ocorrência mais comum. É
comparável ao comando top (http://man7.org/linux/man-
pages/man1/top.1.html) do Linux.
Já que o varnishtop ordena as entradas pelo número de ocorrências
existentes no log em memória compartilhada, não faz sentido executar o
comando sem aplicar os ltros apropriados. Logo, você usará a ltragem
de tags e consultas VSL para apresentar uma saída signi cativa.
Aqui está um exemplo em que aplicamos ltros ao varnishtop para
recuperar uma lista dos URLs que apresentam mais cache misses:
varnishtop -i ReqUrl -q "VCL_call eq 'MISS'"
Esta é a saída que ele poderia retornar:
125.25 ReqURL /page1
10.86 ReqURL /page2
0.57 ReqURL /
0.10 ReqURL /page3
Se você examinar a saída, notará que /page1 gera 125,25 misses por
minuto. É recomendável dar uma olhada nessa página para inspecionar
seu comportamento. Você pode usar o varnishlog para veri car quais
valores de VCL_call e VCL_return ela apresenta na execução do uxo.
Conclusão
Se você executar o Varnish e não usar nenhuma das ferramentas
mencionadas neste capítulo, cará vulnerável. Mesmo tendo a impressão
de que tudo está bem, um conjunto repentino de cache misses pode
surgir do nada. Use o varnishtop para monitorar suas instâncias. Você
pode até mesmo formatar a saída de várias maneiras. Também pode usar
as métricas em seus agentes de monitoramento e enviar alertas quando os
valores alcançarem um nível crítico. E pode auditar facilmente o
comportamento do aplicativo emitindo comandos varnishtop, já que eles
lhe permitirão ver as execuções mais comuns de certas tags. Se algum
desses valores sair do normal, faça uma pesquisa mais minuciosa usando
o varnishlog para inspecionar vários cenários especí cos. Para otimizar a
taxa de acertos (como indicado no Capítulo 7), é preciso saber as
consequências de suas alterações no VCL – essas ferramentas o ajudarão
a se certi car.
CAPÍTULO 9
A essa altura, você deve ter extraído informações su cientes deste livro
para instalar o Varnish e con gurá-lo apropriadamente. E se tudo der
certo, seu aplicativo também sofrerá algum ajuste.
No entanto, por que fazê-lo? Do ponto de vista técnico, é uma decisão
fácil: para tornar sua plataforma melhor, mais rápida e mais forte. Porém,
do ponto de vista dos negócios, pode ser difícil se decidir. Se você for um
desenvolvedor ou administrador de sistemas que está tentando convencer
seu gerente a usar o Varnish, este capítulo fornecerá as alegações
necessárias. Se for um especialista técnico tomador de decisões e
interessado em usar o Varnish, ele será sua fonte de inspiração.
Este capítulo oferece algumas histórias de sucesso e aconselhamento
prático sobre como o Varnish pode ser útil em sua pilha – e em sua
empresa.
Varnish Plus
Há alguns aspectos de missão crítica das empresas online aos quais o
Varnish não dá suporte em sua versão original. Eles requerem muito
código VCL personalizado, um conjunto de VMODs e certa
complexidade na infraestrutura.
O Varnish Plus (https://www.varnish-software.com/products/varnish-plus/)
é um produto comercial da Varnish Software que adiciona recursos de
missão crítica e orientados a negócios a partir do Varnish.
Estes são alguns dos recursos que o Varnish Plus oferece como serviço:
• Alta disponibilidade (https://www.varnish-software.com/plus/varnish-
high-availability/)
• Mecanismo de armazenamento massivo (https://www.varnish-
software.com/plus/massive-storage-engine/)
• Invalidação de cache aprimorada (https://www.varnish-
software.com/plus/varnish-enhanced-cache-invalidation/)
• Suporte ao Varnish Plus (https://www.varnish-
software.com/plus/support/)
• Suporte interno ao SSL/TLS (https://www.varnish-
software.com/plus/ssl-tls-support/)
• Detecção de dispositivo móvel (https://www.varnish-
software.com/plus/varnish-mobile-device-detection/)
• Console de administração fácil de usar (https://www.varnish-
software.com/plus/varnish-administration-console/)
• Suporte ao Paywall (https://www.varnish-software.com/plus/varnish-
paywall/)
• Estatísticas personalizadas (https://www.varnish-
software.com/plus/varnish-custom-statistics/)
• Edgestash (https://www.varnish-software.com/plus/edgestash/)
• Parallel ESI (https://www.varnish-software.com/plus/parallel-esi/)
Você deve concordar que esses recursos são personalizados a partir das
necessidades das empresas. Podemos construir todos eles por conta
própria usando o VCL e VMODs, mas isso tomaria muito tempo. O
Varnish Plus oferece esses recursos avançados a partir do Varnish, com
suporte e uma interface de gerenciamento intuitiva.
Varnish na Wikipedia
Até mesmo a Wikipedia (https://www.wikipedia.org/) usa o Varnish.
Emanuele Rocca
(https://wikimediafoundation.org/wiki/User:ERocca_(WMF)), um dos
engenheiros de operações da Wikipedia, fez uma apresentação na
Varnishcon 2016 sobre como a Wikipedia usa o Varnish. Os slides
(https://upload.wikimedia.org/wikipedia/commons/d/d4/WMF_Tra c_Varni
shcon_2016.pdf) e a gravação em vídeo
(https://www.infoq.com/fr/presentations/varnishcon-emanuele-rocca-scaling-
wikipedia) estão disponíveis online.
A Wikipedia escolheu o Varnish porque ele é open source e tem um
histórico de sucesso. A própria fundação Wikimedia é uma forte
defensora do software open source e tem raízes profundas nos
movimentos de cultura e software livre.
Basicamente, a Wikipedia tem uma pilha Varnish de várias camadas para
manipular cerca de 100 mil solicitações recebidas por segundo. Ela usa o
Varnish não só para sua própria CDN multirregional, mas também para o
cache de páginas. Devido aos valores seguidos pela Wikipedia, ela exige
autonomia plena e não quer depender de empresas externas. Também
apresenta alguns requisitos técnicos que demandam controle total sobre a
tecnologia de cache. Um modelo “as-a-service” não funcionaria para a
Wikipedia.
O Varnish é a ferramenta ideal para esse uso pelas seguintes razões:
• A Wikipedia tem controle total sobre políticas de cache e expurgo.
• O VCL permite a criação de várias otimizações personalizadas.
• O Varnish permite a execução de análises personalizadas.
A instalação multicamada do Varnish na Wikipedia é composta por duas
instâncias do varnishd executadas em portas separadas:
• Uma primeira camada que armazena objetos na memória
• Uma segunda camada que armazena objetos em disco
Solicitações recebidas são roteadas para o “melhor” datacenter de acordo
com o GeoDNS (https://github.com/abh/geodns). Os balanceadores de
carga enviam tráfego para um nó de cache com base no endereço IP do
cliente. Já que a terminação TLS ocorre nos nós de cache e devido à
persistência de sessão TLS, faz sentido enviar solicitações do mesmo
endereço IP de cliente para o mesmo nó.
A primeira camada do Varnish serve conteúdo popular a partir da
memória. Se um objeto não estiver no cache, a solicitação será enviada
para a segunda camada que armazena seu cache em disco. Esse esquema é
muito mais rápido que servir diretamente a partir do servidor web. As
solicitações são roteadas para a segunda camada do Varnish com base no
URL. Isso permite compartilhar dados com vários servidores sem que
haja objetos duplicados.
Devido à persistência de objetos na segunda camada, a Wikipedia pode
lidar facilmente com reinicializações sem o risco de perder dados do
cache.
Conclusão
O Varnish é um projeto sério – uma tecnologia séria para empresas sérias.
Devido à sua simplicidade e exibilidade, é uma boa escolha até mesmo
para empresas e organizações pequenas que têm problemas de
desempenho e não de escalabilidade. O Varnish tem um histórico
impressionante e é usado por mais de 2,5 milhões de sites, alguns dos
quais estão entre os mais populares do mundo.
Se você deseja integrar o Varnish aos seus projetos, mas ainda encontra
alguma resistência de colegas ou da gerência, mostre esses casos de
clientes. Se ele é su cientemente bom para a Wikipedia, provavelmente
também será bom para seu site.
E se tudo isso ainda for complicado e técnico demais para a pessoa
responsável por decidir, mostre a ela este vídeo que explica o cache do
Varnish (https://www.youtube.com/watch?v=fGD14ChpcL4), conte
histórias de sucesso e, por m, crie uma prova do conceito com um pouco
de VCL.
Se sua gerência quiser garantias mais formais e serviços adicionais, peça
que entre em contato com a Varnish Software (https://www.varnish-
software.com/).
Gosto do Varnish. A indústria gosta do Varnish. E espero que a essa altura
você também goste!
CAPÍTULO 10
Suporte a Patch
É preciso adicionar suporte explícito ao método HTTP PATCH. O Varnish
4.1 só suporta os métodos HTTP de nidos no RFC 2616
(https://tools.ietf.org/html/rfc2616) e PATCH não faz parte dessa
especi cação. O suporte a PATCH foi adicionado no RFC 2068
(https://tools.ietf.org/html/rfc2068#section-19.6.1), e você terá de fornecer o
fragmento VCL a seguir para fazê-lo funcionar:
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "PATCH" &&
req.method != "DELETE") {
return (pipe);
}
Autenticação
Se o acesso à sua API RESTful demandar autenticação, você pode usar o
cabeçalho authorization ou empregar um VMOD (http://www.varnish-
cache.org/vmods/) para fornecer formas alternativas de autenticação.
Falaremos sobre VMODs em “Estendendo o comportamento do Varnish
com VMODs”.
No entanto, se quiser uma autenticação básica simples na API sem
precisar se conectar com o backend, pode usar vmod_basicauth
(http://git.gnu.org.ua/cgit/vmod-basicauth.git).
Invalidação
Permitir que sua API RESTful retorne conteúdo obsoleto é tão arriscado
quanto o seria em sites e aplicativos web. Logo, é igualmente importante
que você tenha uma estratégia de invalidação correta.
Há estratégias mais simples como a invalidação de recursos individuais
chamados com o uso de POST, DELETE, PATCH e PUT.
Digamos que você execute um PUT como neste exemplo:
PUT /user/1
Você está basicamente executando uma atualização completa no recurso
/users/1. Portanto, se tentar recuperá-lo usando GET como na linha a
seguir, terá de se certi car de que ele foi invalidado:
GET /user/1
Se você se lembra do VCL interno, sabe que chamadas a GET são
armazenadas em cache e chamadas a PUT não. Na lógica de sua operação
PUT, você pode expurgar ou banir esse recurso.
Porém, ca ainda mais complicado: há recursos agregados que também
poderiam conter informações sobre o recurso atualizado. Considere, por
exemplo, a chamada a GET a seguir:
GET /user
Esse recurso /user também precisa ser invalidado já que contém um
conjunto de usuários que inclui o usuário 1.
Resumindo, já que as APIs RESTful são orientadas a dados, geralmente é
importante que os dados sejam consistentes. Certi que-se de ter uma
estratégia de invalidação de dados decente. Se uma consistência eventual
for aceitável, você poderá con ar na expiração dos recursos sem ter de se
preocupar com a invalidação explícita.
No Varnish 4.1, o código C inline ainda é suportado, mas seu uso não é
recomendado. Se quiser usar código C personalizado, você terá de ativar
vcc_allow_inline_c como opção de inicialização.
Então, qual seria a alternativa? Agora é incentivado o uso de módulos
Varnish, também conhecidos como VMODs (https://www.varnish-
cache.org/docs/4.1/reference/vmod.html). Um VMOD também é escrito em
C, mas em vez de estender diretamente o comportamento do Varnish, ele
é oferecido como uma biblioteca compartilhada que pode ser chamada a
partir do código VCL. Poderíamos dizer que os VMODs são módulos que
enriquecem a sintaxe do VCL com recursos adicionais.
Encontrando e instalando VMODs
Como já mencionado, há um diretório o cial de VMODs no site do
Varnish (https://www.varnish-cache.org/vmods/). Você também pode criar
seus próprios VMODs se precisar. A comunidade Varnish oferece alguns
VMODs básicos que são instalados como um grande conjunto. Eles se
encontram no GitHub (https://github.com/varnish/varnish-modules), caso
você esteja interessado.
Ativando VMODs
Só porque você compilou e instalou os VMODs no diretório certo, isso
não signi ca que eles serão ativados. Ainda é preciso importá-los para seu
arquivo VCL.
É assim que o VMOD padrão é importado:
import std;
Dependendo do tipo de VMOD, é possível começar a usar suas funções
dentro das sub-rotinas do VCL. Se seu VMOD demandar inicialização
adicional, isso pode ser feito em vcl_init.
Lembra-se deste exemplo do Capítulo 6?
vcl 4.0;
import directors;
backend web001 {
.host = "web001.example.com";
.probe = healthcheck;
}
backend web002 {
.host = "web002.example.com";
.probe = healthcheck;
}
sub vcl_init {
new loadbalancing = directors.round_robin();
loadbalancing.add_backend(web001);
loadbalancing.add_backend(web002);
}
sub vcl_recv {
set req.backend_hint = loadbalancing.backend();
}
Nesse exemplo, tivemos de inicializar um diretor de nindo seu algoritmo
de distribuição e adicionando backends. Fizemos isso em vcl_init.
Precisa de ajuda?
Você leu o livro e sente como se tivesse todas as ferramentas necessárias
para instalar uma pilha Varnish com uma ótima taxa de acertos?
Excelente! Este livro não pretende ser a bíblia do Varnish. Há mais coisas a
serem aprendidas.
No entanto, se você não souber o que fazer e precisar de ajuda, os
recursos a seguir estão disponíveis:
• A lista varnish-misc (https://www.varnish-
cache.org/lists/mailman/listinfo/varnish-misc) está aberta a perguntas.
• Há um canal de IRC #varnish no irc.linpro.no. As pessoas que o
frequentam tendem a ser amigáveis e prestativas.
• Há uma tag Varnish no StackOver ow
(http://stackover ow.com/questions/tagged/varnish?
sort=newest&pageSize=40) na qual é possível fazer perguntas.
• Perguntas relacionadas ao VCL podem ser feitas na tag varnish-vcl no
StackOver ow (http://stackover ow.com/questions/tagged/varnish-vcl?
sort=newest&pageSize=40).
• Se você é do tipo de pessoa #dta1 e quiser fazer uma postagem no
Twitter, também pode direcionar suas perguntas para @varnishcache
(https://twitter.com/varnishcache).
Se precisar de suporte, treinamento ou serviços pro ssionais, a Varnish
Software (https://www.varnish-software.com/) é a empresa com a qual deve
entrar em contato. Ela é a principal patrocinadora do projeto Varnish e
emprega muitos de seus colaboradores essenciais. Eles são a fonte
de nitiva quando se trata de produtos e serviços comerciais baseados no
Varnish.
Sobre o autor
Thijs Feryn é evangelista técnico em uma empresa belga de hospedagem
na web chamada Combell. Sua meta é trazer tecnologia para as pessoas e
levar estas à tecnologia. Ele tenta preencher a lacuna existente entre
código e infraestrutura. Thijs também participa de muitas comunidades
open source. Ele fala, ouve, escreve, codi ca, ensina, organiza e, acima de
tudo, está muito entusiasmado com este livro.
Colofão
O animal da capa de Introdução ao Varnish Cache é o tartaranhão-caçador
(Circus pygargus); seu nome, que em inglês é Montagu›s harrier, presta
homenagem ao naturalista inglês George Montagu.
A plumagem do tartaranhão-caçador difere de acordo com o sexo:
machos adultos são cobertos por uma plumagem cinza clara com a ponta
da asa negra, e fêmeas adultas têm as partes inferiores na cor amarela
clara com listas longitudinais e as partes superiores uniformes na cor
marrom escura. Quando jovens, todos os tartaranhões-caçadores parecem
fêmeas adultas, mas com as partes inferiores uniformes na cor marrom
avermelhada.
O tartaranhão-caçador é famoso pelo voo gracioso e por suas batidas de
asa poderosas. Ele é pequeno em comparação com a maioria das outras
aves de rapina; a envergadura da asa varia de ٩٦ a ١١٤ centímetros e seu
peso é de ٢٦٥ (machos) a ٣٤٥ gramas (fêmeas). A fêmea da espécie é
maior para produzir ovos.
Essa espécie é encontrada em climas temperados e nas zonas
mediterrânea e boreal. Ela costuma nidi car em terras baixas, quase
sempre em amplos vales uviais, planícies e áreas que margeiam lagos ou
o mar. Quando precisa muito encontrar um habitat, o tartaranhão-
caçador nidi ca em fazendas agrícolas, o que o torna vulnerável à colheita
antecipada. O tartaranhão-caçador come pequenos roedores, pássaros,
ovos de pássaros, répteis e insetos grandes, capturando qualquer que seja
a presa que esteja na área de seu ninho. Ele apanha a presa enquanto voa
a alturas baixas e velocidade constante ao longo de rotas xas. Durante a
época de acasalamento, os machos fornecem alimento para as fêmeas e
depois para os lhotes. Eles tendem a caçar em uma área extensa – dentro
de ١٢ quilômetros de distância da próxima ave. Geralmente as fêmeas
caçam mais perto do ninho, dentro de ١ quilômetro de distância, e só
após os lhotes saírem dos ovos.
Muitos dos animais nas capas dos livros da O’Reilly estão ameaçados;
todos eles são importantes para o mundo. Para saber mais sobre como
você pode ajudar, acesse animals.oreilly.com.
A imagem da capa é do periódico British Birds.
Aprendendo a desenvolver
aplicações web
Purewal, Semmy
9788575227381
360 páginas