Introducao Ao Varnish Cache - Thijs Feryn

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 192

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

Capítulo 1 ■ O que é Varnish Cache?


Por que o desempenho na web é importante?
Qual o papel do Varnish?
Projeto open source Varnish Cache
Como o Varnish funciona?
Armazenar em cache não é um truque
Conclusão

Capítulo 2 ■ Não demore; comece logo!


Instalando o Varnish
Instalando o Varnish usando um gerenciador de pacotes
Instalando o Varnish no Ubuntu e Debian
Instalando o Varnish no Red Hat e CentOS
Con gurando o Varnish
Arquivo de con guração
Algumas observações sobre o Systemd no Ubuntu e Debian
Opções de inicialização
E quanto ao TLS/SSL?
Conclusão

Capítulo 3 ■ O Varnish fala HTTP


Idempotência
Estado
Expiração
Cabeçalho Expires
Cabeçalho Cache-control
Precedência de expiração
Solicitações condicionais
ETag
Last-Modi ed
Como o Varnish lida com solicitações condicionais
Variações de cache
Comportamento do VCL interno do Varnish
Quando uma solicitação é considerada armazenável em cache?
Quando o Varnish contorna o cache?
Como o Varnish identi ca um objeto?
Quando o Varnish armazena um objeto em cache?
O que ocorre quando um objeto não é armazenado em cache?
Por quanto tempo o Varnish armazena um objeto em cache?
Conclusão

Capítulo 4 ■ Varnish Con guration Language


Hooks e sub-rotinas
Sub-rotinas do lado do cliente
Sub-rotinas de backend
Sub-rotinas de inicialização e limpeza
Sub-rotinas personalizadas
Instruções de retorno
Fluxo de execução
Sintaxe do VCL
Operadores
Instruções condicionais
Comentários
Valores escalares
Expressões regulares
Funções
Inclusões
Importando módulos Varnish
Backends e sondagens de integridade
Listas de controle de acesso
Variáveis VCL
VCL interno do Varnish
Arquivo VCL do mundo real
Conclusão

Capítulo 5 ■ Invalidando o cache


Armazenando por um tempo muito longo
Expurgo
Banimento
Banimentos amigáveis com o espreitador
Mais exibilidade
Visualizando a lista de banimento
Banimento na linha de comando
Forçando um cache miss
É difícil invalidar o cache
Conclusão

Capítulo 6 ■ Lidando com backends


Seleção do backend
Integridade do backend
Diretores
Diretor round-robin
Diretor aleatório (random)
Diretor hash
Diretor fallback
Modo grace
Ativando o modo grace
Conclusão

Capítulo 7 ■ Melhorando sua taxa de acertos


Erros comuns
Não saber o que é hit-for-pass
Retornando cedo demais
Expurgando sem a lógica de expurgo
ACL de proteção contra acesso ao expurgo
Armazenamento de respostas 404 em cache
De nindo um cabeçalho Age
Max-age versus s-maxage
Adicionando autenticação básica para ambientes de aceitação
Cookies de sessão em todos os lugares
Inexistência de variações de cache
Deseja realmente armazenar recursos estáticos em cache?
Listas negras e listas brancas de URLs
Decida o que será armazenado em cache com cabeçalhos Cache-control
Sempre haverá cookies
Painel de administração
Remova os cookies de rastreamento
Remova todos, exceto alguns
Variações de cookie
Sanitizando
Removendo a porta
Classi cação de strings de consulta
Removendo parâmetros de URL do Google Analytics
Removendo a cerquilha do URL
Removendo o ponto de interrogação nal
Marcador de acerto/erro
Armazenando blocos em cache
AJAX
Edge Side Includes
Fazendo o Varnish analisar o ESI
ESI versus AJAX
Tornando seu código pronto para o cache de blocos
Exemplo de código contendo todas as práticas
Conclusão

Capítulo 8 ■ Registrando, avaliando e depurando


Varnishstat
Exemplo de saída
Exibindo métricas especí cas
Formatação da saída
Varnishlog
Exemplo de saída
Filtrando a saída
Varnishtop
Conclusão

Capítulo 9 ■ O que essa decisão signi ca para os negócios?


Usar ou não usar uma CDN
O VCL é mais barato
Varnish como bloco de construção
O caso do cliente original
Varnish Plus
Empresas que usam o Varnish atualmente
NU.nl: investir cedo compensa
SFR: construa sua própria CDN
Varnish na Wikipedia
Combell: Varnish em hospedagem compartilhada
Conclusão

Capítulo 10 ■ Passando para o próximo nível


E quanto aos serviços RESTful?
Suporte a Patch
Autenticação
Invalidação
Estendendo o comportamento do Varnish com VMODs
Encontrando e instalando VMODs
Ativando VMODs
VMODs que vêm com o Varnish
Precisa de ajuda?
O futuro do projeto Varnish
Sobre o autor
Colofão
Prefácio

Convenções usadas no livro


As convenções tipográ cas a seguir são usadas neste livro:
Itálico
Indica novos termos, URLs, endereços de email, nomes de arquivo e
extensões de arquivo.
Largura constante
Usada para listagens de programas, assim como dentro de parágrafos
para fazer referência a elementos de um programa, como nomes de
funções ou variáveis, bancos de dados, tipos de dados, variáveis de
ambiente, instruções e palavras-chave.
Largura constante em negrito
Mostra comandos ou outros tipos de texto que tenham de ser digitados
literalmente pelo usuário.
Largura constante em itálico
Mostra o texto que deve ser substituído por valores fornecidos pelo
usuário ou determinados pelo contexto.

Este elemento signi ca uma dica ou sugestão.

Este elemento signi ca uma nota geral.

Este elemento indica um aviso ou precaução.


Como entrar em contato conosco
Envie seus comentários e suas dúvidas sobre este livro à editora
escrevendo para: [email protected].
Temos uma página web para este livro na qual incluímos erratas,
exemplos e quaisquer outras informações adicionais.
• Página da edição em português
http://www.novatec.com.br/catalogo/introducao-varnish-cache
• Página da edição original em inglês
http://shop.oreilly.com/product/0636920056294.do
Para obter mais informações sobre os livros da Novatec, acesse nosso site
em http://www.novatec.com.br.

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

O que é Varnish Cache?

Varnish Cache é o chamado proxy de cache reverso. Trata-se de um


software colocado na frente do(s) servidor(es) web para reduzir o tempo
de carregamento do site/aplicativo/API pelo armazenamento da saída do
servidor em cache. Estamos falando basicamente de desempenho na web.
Neste capítulo, explicarei por que o desempenho na web é tão importante
e como o Varnish pode melhorá-lo.

Por que o desempenho na web é importante?


Muitas pessoas subestimam a importância do desempenho na web. Pela
lógica comum, se um site tem um bom desempenho quando 10 usuários
o estão acessando, ele também funcionará bem quando 1 milhão de
usuários quiserem acessá-lo. Uma simples campanha de marketing bem-
sucedida destrói esse mito.
Desempenho e escalabilidade não são a mesma coisa. Desempenho é a
velocidade bruta do site: em quantos milissegundos sua página é
carregada. Escalabilidade, por outro lado, é manter o desempenho estável
quando a carga aumenta. A última é a razão pela qual as empresas
maiores escolhem o Varnish. O primeiro é aplicável a tudo, até mesmo a
projetos pequenos.
Digamos que seu site tenha cerca de 100 visitantes por dia. Nem é tanto
assim, certo? E o tempo de carregamento de uma página seja de 1,5
segundo – que não é ótimo, mas também não é tão ruim. Sem cache,
pode ser preciso algum tempo (e dinheiro) para reduzir esse tempo para
menos de um segundo. Você poderia refatorar seu código ou otimizar a
infraestrutura. E depois analisar se o esforço valeu a pena.
Também é importante ressaltar que o desempenho na web é parte
essencial da experiência do usuário. Deseja agradar os usuários e
assegurar que eles permaneçam em seu site? Então certi que-se de que as
páginas sejam carregadas com rapidez. Até mesmo o Google sabe disso –
sabia que o Google Search leva em consideração o tempo de carregamento
dos sites quando classi ca páginas em seu ranking?
Além de prejudicar a classi cação no Google, um desempenho fraco
também afetará o que é mais importante: as pessoas não têm paciência
para esperar conteúdo lento e logo procurarão uma alternativa. Em um
mercado muito saturado, é provável que elas acabem acessando um de
seus rivais.

Qual o papel do Varnish?


Com um Varnish con gurado de maneira correta, você reduzirá
automaticamente o tempo de carregamento de seu site sem muito esforço.
Como o Varnish é open source e fácil de con gurar, isso não será difícil.
E se você souber agir, talvez um dia seu site torne-se popular. O termo
“viral” vem à mente. Se você já tem um Varnish con gurado de maneira
apropriada, não precisa fazer mais nada.
Muita gente acha que o Varnish é tecnologia para grandes projetos e
empresas maiores – o tipo de site que atrai quantidades massivas de
acessos. É verdade; essas empresas usam o Varnish. De fato, 13% dos
10.000 sites de maior destaque usam o Varnish para assegurar tempos de
carregamento rápidos. No entanto, o Varnish também é adequado para
projetos de tamanho pequeno e médio. Consulte o Capítulo 9 para
conhecer algumas histórias de sucesso e casos de uso empresariais.
Apesar de tudo, o Varnish não é a panaceia; é apenas parte da pilha. São
necessários vários outros componentes para que as páginas sejam servidas
com rapidez e con abilidade, mesmo no carregamento. Esses
componentes, como a rede, o servidor, o sistema operacional, o servidor
web e o runtime do aplicativo, também podem nos deixar na mão.
Projeto open source Varnish Cache
O Varnish Cache (https://www.varnish-cache.org/) é um projeto open
source escrito em C. O fato de ele ser open source signi ca que o código
também está disponível online e que o uso do Varnish é gratuito.
O Varnish Cache é mantido por uma comunidade ativa, liderada por
Poul-Henning Kamp (http://phk.freebsd.dk/). Embora ele seja gratuito, há
uma empresa por trás do projeto patrocinando grande parte de seu
desenvolvimento. Essa empresa, chamada Varnish Software
(https://www.varnish-software.com/), consegue patrocinar o projeto
Varnish Cache fornecendo treinamento, suporte e recursos adicionais que
vão além do Varnish.

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.

Como o Varnish funciona?


O Varnish é instalado em servidores web ou em máquinas separadas.
Após ser instalado e iniciado, ele imitará o comportamento do servidor
web localizado atrás. Geralmente, o Varnish escuta na porta TCP 80, a
porta TCP convencional que distribui HTTP – a menos que, claro, ele
também esteja atrás de outro proxy. Ele terá um ou mais backends
registrados e se comunicará com um deles caso um resultado não possa
ser recuperado no cache.
O Varnish pré-alocará um bloco de memória virtual e o usará para
armazenar seus objetos, que contêm os cabeçalhos de resposta HTTP e o
payload recebido do backend. Os objetos armazenados na memória serão
servidos para os clientes solicitantes do recurso HTTP correspondente. Os
objetos do cache são identi cados por um hash que, por padrão, é
composto pelo nome do host (ou o endereço IP se não for especi cado
um nome de host) e o URL da solicitação.
O Varnish é muito rápido e usa pthreads
(https://en.wikipedia.org/wiki/POSIX_Threads) para manipular uma
grande quantidade de solicitações recebidas. O modelo de threading e o
uso de memória para armazenamento resultarão em uma melhoria
signi cativa no desempenho de seu aplicativo. Quando con gurado de
maneira correta, o Varnish Cache consegue facilmente tornar o site 1.000
vezes mais rápido.
O Varnish usa o Varnish Con guration Language (VCL) para controlar o
comportamento do cache. O VCL é uma linguagem de domínio especí co
que oferece hooks para sobrepor e estender o comportamento dos
diferentes estados da Máquina de Estados Finitos Varnish. Esses hooks
são representados por um conjunto de sub-rotinas que existem no VCL.
As sub-rotinas e o código VCL residem dentro do arquivo VCL. Na hora
da inicialização, o arquivo VCL é lido, convertido para C, compilado e
carregado dinamicamente como um objeto compartilhado.
A sintaxe do VCL é muito extensa, mas só vai até certo ponto. Se quiser
estender o comportamento ainda mais, você pode criar módulos Varnish
personalizados com C. Os módulos podem conter literalmente qualquer
coisa que você possa programar em C. Esse comportamento estendido é
apresentado por meio de um conjunto de funções. As funções são
expostas para o VCL e enriquecem sua sintaxe.
VCL: o coração e a alma do Varnish
O VCL é o coração e a alma do Varnish. É o fator que o populariza e a razão para
as pessoas preferirem o Varnish em vez de outras tecnologias de cache. No
Capítulo 4 abordaremos o VCL com mais detalhes e no Capítulo 9 você
encontrará alguns casos de uso empresariais e histórias de sucesso em que o
Varnish e o VCL salvaram o dia.
Um exemplo interessante que vem à mente é o ataque DDoS destinado ao
WikiLeaks. Ele continha um padrão claro: os cabeçalhos Accept eram iguais em
todas as solicitações. Algumas linhas de VCL foram su cientes para rechaçá-lo.
Isso mostra que a exibilidade que o VLC traz não tem paralelos no universo do
armazenamento em cache.
Armazenar em cache não é um truque
Na verdade, a maioria dos sites, aplicativos e APIs é orientada a dados.
Isso signi ca que sua principal nalidade é apresentar e visualizar dados
que vêm do banco de dados ou de uma fonte externa (feed, API etc.).
Quase sempre eles são usados na recuperação, agrupamento e
visualização de dados.
Quando não fazemos o armazenamento em cache, esse processo é
repetido a cada solicitação de cliente. Imagine quantos recursos são
desperdiçados no reprocessamento, mesmo se os dados não tiverem
mudado.
No passado
No passado, quando eu ainda era um estudante, meu professor de banco de dados
me ensinou tudo sobre a normalização de bancos de dados e por que devíamos
sempre normalizar os dados para a terceira forma normal. Ele nos dizia para nunca
armazenar no banco de dados resultados que pudessem ser recuperados e
recalculados. E naquela época isso estava certo.
Naqueles dias, a carga suportada por um servidor de banco de dados usado para
alimentar um site não era tão alta. No entanto, o hardware era mais caro. O
armazenamento de resultados computados não era um grande problema.
Porém, com a evolução da web, tive de rever essa questão. Atualmente, meu mantra
é: “Não reprocesse se os dados não tiverem mudado”. E é claro que é mais fácil falar
do que fazer.
Se você decidir armazenar um resultado computado em cache, deve ter
um bom controle sobre os dados originais. Se eles mudarem, é preciso
assegurar que o cache seja atualizado. No entanto, esvaziar o cache com
muita frequência vai contra sua nalidade. É seguro dizer que armazenar
em cache é um ato de equilíbrio entre servir dados atualizados e
assegurar tempos de carregamento aceitáveis.
Armazenar em cache não é um truque nem uma maneira de compensar o
fato de certos sistemas ou aplicativos terem desempenho fraco; armazenar
em cache é uma decisão de arquitetura que, quando executada
corretamente, aumenta a e ciência e reduz o custo da infraestrutura.
Conclusão
Sites lentos devem ser evitados. Os usuários não têm muita paciência, e
em um mercado altamente saturado um site veloz pode lhe dar vantagem
sobre seus competidores. O desempenho bruto é importante, mas um
tempo para o primeiro byte estável em condições de carga pesada tem a
mesma importância. Chamamos isso de escalabilidade e é um problema
difícil de resolver. Há várias maneiras de tornar um site escalável, e a
maioria delas requer uma quantidade considerável de tempo e dinheiro.
Felizmente, uma estratégia de cache decente pode reduzir o impacto de
todo esse tráfego. O Varnish é uma ferramenta que pode armazenar em
cache nosso tráfego HTTP e remover grande parte da carga dos
servidores.
CAPÍTULO 2

Não demore; comece logo!

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.

Na verdade, provavelmente você instalará o Varnish em um sistema Linux. Para


ns de desenvolvimento, é possível executá-lo no OS X. O Linux é o sistema
operacional mais usado para sistemas de produção. Algumas pessoas fazem o
desenvolvimento local em um Mac e preferem testar seu código localmente. Logo,
pode fazer sentido instalar no OS X, só para você ver como o código se comporta
quando armazenado em cache pelo Varnish.
As distribuições Linux suportadas são:
• Ubuntu
• Debian
• Red Hat
• CentOS
Você pode instalar o Varnish facilmente usando o gerenciador de pacotes
de seu sistema operacional, mas também pode compilá-lo a partir do
código-fonte.

Instalando o Varnish usando um gerenciador de pacotes


Compilar a partir do código-fonte é fácil, mas muito demorado. Se você se
enganar na obtenção de uma das dependências ou instalar a versão errada
dela, terá problemas. Por que fazê-lo da maneira difícil (a menos que
tenha suas razões) se pode instalar o Varnish facilmente usando o
gerenciador de pacotes de seu sistema operacional?
Aqui está uma lista de gerenciadores de pacote que você pode usar de
acordo com seu sistema operacional:
• APT (www.debian.org/doc/manuals/debian-reference/ch02.en.html) no
Ubuntu e Debian
• YUM (www.centos.org/docs/5/html/yum/) no Red Hat e CentOS
• PKG (www.freebsd.org/doc/handbook/pkgng-intro.html) no FreeBSD

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.

Instalando o Varnish no Ubuntu e Debian


De maneira geral, poderíamos dizer que as distribuições Ubuntu e
Debian estão relacionadas. O Ubuntu é um sistema operacional baseado
no Debian. As duas distribuições usam o gerenciador de pacotes APT. No
entanto, ainda que a instalação do Varnish seja semelhante em ambas, há
diferenças sutis. É por isso que há canais de repositório diferentes no APT
para o Ubuntu e o Debian.
O Varnish é instalado da seguinte maneira no Ubuntu, supondo que você
esteja executando a versão 14.04 LTS (Trusty Tahr) do sistema
operacional:
apt-get install apt-transport-https
curl https://repo.varnish-cache.org/GPG-key.txt | apt-key add -
echo "deb https://repo.varnish-cache.org/ubuntu/ trusty varnish-4.1" \
    >> /etc/apt/sources.list.d/varnish-cache.list
apt-get update
apt-get install varnish

Também há pacotes disponíveis para outras versões do Ubuntu. O Varnish só dá


suporte às versões LTS. Além de instalar o Varnish no Trusty Tahr, você pode fazê-lo
no Ubuntu 12.04 LTS (Precise Pangolin) e no Ubuntu 10.04 LTS (Lucid Lynx). Para
isso, substitua a palavra-chave trusty por precise ou lucid no exemplo anterior.
Se você estiver executando o Debian, o Varnish é instalado no Debian 8
(Jessie) desta forma:
apt-get install apt-transport-https
curl https://repo.varnish-cache.org/GPG-key.txt | apt-key add -
echo "deb https://repo.varnish-cache.org/debian/ jessie varnish-4.1"\
    >> /etc/apt/sources.list.d/varnish-cache.list
apt-get update
apt-get install varnish

Se estiver executando uma versão mais antiga do Debian, há pacotes disponíveis


para Debian 5 (Lenny), Debian 6 (Squeeze) e Debian 7 (Wheezy). Basta substituir a
palavra-chave jessie por lenny, squeeze ou wheezy nas instruções anteriores.

Instalando o Varnish no Red Hat e CentOS


Há três distribuições básicas da família Red Hat de sistemas operacionais:
• Red Hat Enterprise: versão empresarial paga
• CentOS: versão gratuita
• Fedora: versão de ponta para desktop
Todas as três têm o gerenciador de pacotes YUM, mas daremos mais
atenção ao Red Hat e CentOS, que têm o mesmo procedimento de
instalação.
Se você estiver no Red Hat ou CentOS versão 7, o Varnish é instalado
assim:
yum install epel-release
rpm --nosignature -i https://repo.varnish-cache.org/redhat/varnish-
4.1.el7.rpm
yum install varnish
Se estiver no Red Hat ou CentOS versão 6, você instalará o Varnish desta
forma:
yum install epel-release
rpm --nosignature -i https://repo.varnish-cache.org/redhat/varnish-
4.1.el6.rpm
yum install varnish

Con gurando o Varnish


Agora que você está com o Varnish instalado em seu sistema, é hora de
de nir algumas con gurações para começar a usá-lo.
O Varnish tem um grupo de opções de inicialização que nos permite
con gurar a maneira como interagiremos com ele. Essas opções estão
localizadas em um arquivo de con guração e são atribuídas ao programa
varnishd na hora da inicialização. Aqui estão alguns exemplos de opções
de inicialização típicas:
• Endereço e porta em que o Varnish processará as solicitações HTTP
recebidas
• Endereço e porta em que a CLI do Varnish (https://www.varnish-
cache.org/docs/4.1/reference/varnish-cli.html) será executada
• Local do arquivo VCL que contém as políticas de cache
• Local do arquivo que contém a chave secreta, usada para a
autenticação na CLI do Varnish
• Tipo e tamanho do backend de armazenamento
• Opções de jailing para proteção do Varnish
• Endereço e porta do backend com o qual o Varnish interagirá

Você pode ler mais sobre as opções de inicialização do Varnish na página da


documentação o cial do varnishd (www.varnish-
cache.org/docs/4.1/reference/varnishd.html).

Arquivo de con guração


O primeiro desa o é encontrar onde o arquivo de con guração está
localizado em seu sistema. Isso depende não só da distribuição Linux,
mas também do gerenciador de serviço executado por seu sistema
operacional.
Se seu sistema operacional estiver usando o gerenciador de serviço
systemd (https://en.wikipedia.org/wiki/Systemd), o arquivo de con guração
do Varnish estará localizado em uma pasta diferente daquela em que ele
costuma estar. O Systemd vem ativado por padrão no Debian Jessie e
CentOS 7. O Ubuntu Trusty Tahr ainda usa o SysV.
Se quiser saber onde o arquivo de con guração está localizado em seu
sistema operacional (dado que você instalou o Varnish por intermédio de
um gerenciador de pacotes), consulte a Tabela 2.1.
Tabela 2.1 – Localização do arquivo de con guração do Varnish
SysV Systemd
Ubuntu/Debian /etc/default/varnish /etc/systemd/system/varnish.service
Red Hat/CentOS /etc/syscon g/varnish /etc/varnish/varnish.params

Caso você esteja usando o systemd no Ubuntu ou Debian, o arquivo de


con guração /etc/systemd/system/varnish.service ainda não terá sido criado. É
preciso copiá-lo de /lib/systemd/system/.
Se alterar o conteúdo do arquivo, você terá de recarregar o serviço Varnish
para carregar as con gurações. Execute o comando a seguir para que isso
ocorra:
sudo service varnish reload
Algumas observações sobre o Systemd no Ubuntu e Debian
Se você estiver no Ubuntu ou Debian usando o gerenciador de serviço
systemd, há várias coisas que terá de lembrar.
Primeiro, terá de copiar o arquivo de con guração na pasta certa para
sobrepor as con gurações-padrão. Isso é feito assim:
sudo cp /lib/systemd/system/varnish.service /etc/systemd/system
Se pretende fazer alterações nesse arquivo, não se esqueça de que os
resultados são armazenados na memória cache. É preciso recarregar o
systemd para que as alterações sejam carregadas a partir do arquivo, o que
é feito desta forma:
sudo systemctl daemon-reload
Isso não signi ca que o Varnish será iniciado com as opções de
inicialização certas, signi ca apenas que o systemd conhece as
con gurações mais recentes. Você terá de recarregar o serviço Varnish para
carregar as alterações feitas na con guração com:
sudo service varnish reload

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.

Cuidado quando tornar a CLI acessível remotamente porque embora o acesso


demande autenticação, ele ocorre por uma conexão não criptografada.
Opções de segurança. A opção -j permite isolar a instância Varnish e executar
os subprocessos empregando o usuário especi cado. Por padrão, todos os
processos são executados com o usuário varnish.
A opção de jailing é particularmente útil quando executamos várias
instâncias Varnish no mesmo servidor. Dessa forma, há um melhor
isolamento de processos entre as instâncias.
A opção -S é usada para de nir o local do arquivo que contém a chave
secreta. Essa chave é usada para a autenticação na CLI do Varnish. Por
padrão, o local do arquivo é /etc/varnish/secret. Ele contém
automaticamente um valor aleatório.
Você pode optar por não incluir o parâmetro -S para permitir o acesso
não autenticado à CLI, mas isso é algo que não recomendo fazer. Se quiser
alterar o local do valor da chave secreta, mude o valor do parâmetro -S. Se
quiser alterar apenas a chave secreta, edite /etc/varnish/secret e recarregue
o Varnish.
Opções de armazenamento. Os objetos do cache têm de ser armazenados em
algum local. É nesse momento que a opção -s entra em cena. Por padrão,
os objetos são armazenados na memória (~malloc) e o tamanho do cache
é de 256 MiB.
O Varnish expressa o tamanho do cache em quibibytes, mebibytes, gibibytes e
tebibytes. Essa terminologia difere dos tradicionais quilobytes, megabytes, gigabytes
e terabytes. O “bi” de quibibytes representa binário, logo isso signi ca que um
quibibyte é composto por 1.024 bytes, enquanto um quilobyte tem 1.000 bytes. A
mesma lógica é aplicável aos mebibytes (1.024 × 1.024 bytes), gibibytes (1.024 × 1.024
× 1.024 bytes) e tebibytes (1.024 × 1.024 × 1.024 × 1.024 bytes).
O tamanho do cache e o tipo de armazenamento dependem do número
de objetos a serem armazenados. Se todos os seus arquivos armazenáveis
em cache couberem na memória, estará tudo bem. A memória é rápida e
simples, mas infelizmente é limitada em termos de tamanho. Se a
instância Varnish car sem memória, ela aplicará a conhecida estratégia
Menos Utilizado Recentemente (LRU, Least Recently Used) para remover
itens do cache.

Se você não especi car o tamanho do armazenamento e só mencionar malloc, o


tamanho do cache será ilimitado. Ou seja, o Varnish poderia consumir toda a
memória de seu servidor. Se o servidor car sem memória, ele usará o espaço de
swap do sistema operacional. Isso armazenaria o excesso de dados no disco e
poderia causar uma grande lentidão em todo o sistema se os discos forem lentos.
O Varnish conta a quantidade de acessos por objeto do cache. Quando
tem de remover objetos devido à falta de memória disponível, ele remove
os objetos menos populares até ter espaço su ciente para armazenar o
próximo objeto solicitado.
Se você tiver um servidor Varnish dedicado, é aconselhável alocar cerca de
80% da memória disponível para o Varnish. Isso signi ca que será preciso
alterar a opção de inicialização -s.

O armazenamento em arquivos também é suportado. Embora seja mais lento que


a memória, ele também é feito no bu er da memória. Quase sempre, o
armazenamento na memória resolve o problema.
Local do arquivo VCL. O local do arquivo VCL é de nido com o uso da opção
-f. Por padrão, ela aponta para /etc/varnish/default.vcl. Se quiser mudar o
local de seu arquivo VCL para outro arquivo, você pode modi car essa
opção.

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á.

Usando opções mais avançadas


Incrementaremos um pouco as coisas lançando algumas opções de
inicialização avançadas na mistura. Aqui está um exemplo:
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 \
             -l 100m,10m \
             -t 60 \
             -p feature=_++esi_disable_xml_check \
             -p connect_timeout=5 \
             -p first_byte_timeout=10 \
             -p between_bytes_timeout=2"
Armazenamento de log compartilhado em memória. O Varnish não armazena
apenas seus objetos; também há espaço alocado na memória para logging
e estatísticas. Essas informações são usadas por utilitários binários como
o varnishlog, o varnishtop e o varnishstat.
Por padrão, 1 MiB é alocado para os Contadores de Estatísticas do
Varnish (VSC, Varnish Statistics Counters) e 81 MiB para os Logs
Compartilhados em Memória (VSL, Varnish Shared Memory Logs).
Você pode manipular o tamanho do VSC e do VSL alterando o valor da
opção de inicialização -l.
Tempo de vida padrão. O Varnish usa expirações ou cabeçalhos de controle de
cache para determinar o tempo de vida de um objeto. Se não houver
cabeçalhos presentes e não for especi cado um tempo de vida explícito no
arquivo VCL, ele usará como padrão um tempo de vida de 120 segundos.
Você pode modi car o tempo de vida padrão na hora da inicialização
de nindo a opção -t. O valor dessa opção é expresso em segundos.
Parâmetros de runtime. Há vários parâmetros de runtime que podem ser
ajustados. A sobreposição de um parâmetro de runtime é feita pela
de nição da opção de inicialização -p. Alternativamente, se você quiser
que esses parâmetros sejam somente de leitura, pode usar a opção -r.
De nir que os parâmetros serão somente de leitura impede que usuários
com acesso à CLI do Varnish os sobreponham no runtime.
Consulte a lista completa de parâmetros de runtime na página de
documentação do varnishd (https://www.varnish-
cache.org/docs/4.1/reference/varnishd.html#run-time-parameters).
No exemplo anterior, de nimos os seguintes parâmetros de runtime:
• feature=esi_disable_xml_check
• connect_timeout
• first_byte_timeout
• between_bytes_timeout
O primeiro (feature=esi_disable_xml_check) desativa veri cações de XML
durante o processamento do Edge Side Includes (ESI). Por padrão, o
Varnish requer que o conteúdo do ESI seja de XML válido. O ESI é uma
técnica usada pelo Varnish para a composição de uma página contendo
blocos de conteúdo provenientes de vários URLs. Cada inclusão pode ter
seu próprio tempo de vida que é respeitado pelo Varnish. O Varnish
monta o conteúdo dos URLs usando tags de inclusão ESI como
<esi:include src="http://example.com" />. O ESI também nos permite
armazenar em cache partes de uma página que de outra forma não
poderiam estar no cache (mais informações sobre o ESI podem ser
encontradas em “Edge Side Includes”).
O parâmetro seguinte con gura connect_timeout com cinco segundos. Isso
signi ca que o Varnish esperará até cinco segundos quando se conectar
com o backend. Se o tempo-limite for excedido, um erro de backend será
retornado. O valor-padrão é 3,5 segundos.
O terceiro parâmetro con gura first_byte_timeout com dez segundos.
Após estabelecer uma conexão com o backend, o Varnish esperará
durante dez segundos a chegada do primeiro byte. Se isso não ocorrer
dentro desse tempo, um erro de backend será retornado. O valor-padrão é
60 segundos.
O quarto con gura between_bytes_timeout com dois segundos. Quando
dados são retornados do backend, o Varnish espera um uxo de bytes
constante. Se ele tiver de esperar mais de dois segundos entre os bytes, um
erro de backend será retornado. O valor-padrão é 60 segundos.

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

O Varnish fala HTTP

Agora que instalamos o Varnish, é hora de usá-lo. No Capítulo 2, falamos


sobre as de nições de con gurações, logo você já deve estar com as
con gurações de rede corretas que permitam receber solicitações HTTP
diretamente na porta 80 ou por meio de outro proxy ou balanceador de
carga.
O Varnish já vem pronto para ser útil. Há um conjunto de regras que ele
segue, assim como um comportamento-padrão que é expresso pelo VCL
interno. Se seu aplicativo backend obedecer a essas regras, você terá uma
taxa de acertos muito boa.

O Varnish emprega várias práticas recomendadas de uso do HTTP para decidir o


que será armazenado em cache, como será armazenado e por quanto tempo. Como
desenvolvedor web, meu conselho é o de que você aplique essas melhores práticas
ao desenvolvimento diário de seus aplicativos backend. Isso o capacitará e ajudará a
evitar o uso de con gurações personalizadas do Varnish que atendam ao aplicativo.
Ou seja, mantém a lógica de cache portável.
Diferente de outros proxies, o Varnish é um acelerador de HTTP. Isso
signi ca que ele só opera com HTTP. Faz sentido então conhecer o HTTP
e como ele se comporta.
Há cinco maneiras pelas quais o Varnish respeita as melhores práticas do
HTTP:
• Idempotência
• Estado
• Expiração
• Solicitações condicionais
• Variações de cache
Veremos cada uma e examinaremos como o Varnish lida com elas.

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.

Chamo a atenção para que os desenvolvedores web não usem cookies em


demasia. Não inicie uma sessão que acione um Set-Cookie apenas porque você
pode. Só de na sessões e cookies quando precisar realmente fazê-lo. Sei que é
tentador, mas considere o impacto.
Como mencionado, o Varnish não costuma armazenar cookies em cache.
Sempre que ele vê uma solicitação com um cabeçalho Cookie, ela é
passada para o backend e a resposta não é armazenada em cache.
Quando uma solicitação não contém um cookie, mas a resposta inclui um
cabeçalho Set-Cookie, o Varnish não armazena o resultado em cache.
Expiração
O HTTP tem um conjunto de mecanismos para decidir quando um
objeto armazenado deve ser removido do cache. Os objetos não podem
residir no cache para sempre: você pode car sem espaço de
armazenamento em cache (espaço na memória ou em disco) e o Varnish
terá de remover itens usando uma estratégia LRU para esvaziar o espaço.
Ou você pode se deparar com uma situação em que os dados que está
servindo sejam obsoletos e o objeto precise ser sincronizado com uma
nova resposta ao backend.
Expiração é apenas a de nição de um tempo de vida. O HTTP tem dois
tipos de cabeçalho de resposta que ele usa para indicar isso:
Expires
Timestamp absoluto que representa quando ocorrerá a expiração.
Cache-control
Quantos segundos um item pode residir no cache antes de se tornar
obsoleto.

O Varnish fornece informações sobre a idade de um objeto armazenado em cache.


O cabeçalho Age é retornado a cada resposta. O valor desse cabeçalho corresponde
a quanto tempo o objeto está no cache. O tempo de vida real é o tempo de vida do
cache menos o valor de Age. Portanto, recomendo que você não de na um
cabeçalho Age por conta própria, já que isso desorganizará o TTL (tempo de vida)
de seus objetos.

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.

Embora o Varnish respeite as palavras-chave public e private, ele não se


considera um cache compartilhado e se exime do cumprimento de algumas dessas
regras. O Varnish é mais como um servidor web substituto porque ca totalmente
sob o controle do servidor web e faz tudo o que o webmaster quer.

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

A maioria dos navegadores web dá suporte a solicitações condicionais baseadas


nos cabeçalhos Etag e Last-Modified, mas o Varnish também dá suporte a elas
quando se comunica com o backend.

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.

Os timestamps são baseados no fuso horário GMT. Certi que-se de converter


seus timestamps para esse fuso horário para evitar um comportamento inesperado.
O ponto de partida do exemplo a seguir é o servidor web (ou o aplicativo)
retornando um cabeçalho de resposta Last-Modified:
HTTP/1.1 200 OK
Host: localhost
Last-Modified: Fri, 22 Jul 2016 10:11:16 GMT
Content-type: text/html; charset=UTF-8
Hello world output
O navegador armazena o valor de Last-Modified e o usa como If-Last-
Modified na próxima solicitação:
GET /if_last_modified.php HTTP/1.1
Host: localhost
User-Agent: curl/7.48.0
If-Last-Modified: Fri, 22 Jul 2016 10:11:16 GMT
O recurso não foi modi cado, um código 304 é retornado e o valor de
Last-Modified permanece o mesmo:
HTTP/1.0 304 Not Modified
Host: localhost
Last-Modified: Fri, 22 Jul 2016 10:11:16 GMT
O navegador faz outra solicitação condicional:
GET /if_last_modified.php HTTP/1.1
Host: localhost
User-Agent: curl/7.48.0
If-Last-Modified: Fri, 22 Jul 2016 10:11:16 GMT
Durante esse período, o recurso foi modi cado e um código 200 completo
é retornado, incluindo o payload e um novo cabeçalho Last-Modified.
HTTP/1.1 200 OK
Host: localhost
Last-Modified: Fri, 22 Jul 2016 11:00:23 GMT
Content-type: text/html; charset=UTF-8
Some other hello world output
Agora veremos outro exemplo de implementação de solicitações
condicionais, desta vez baseado no cabeçalho Last-Modified. Novamente, é
um código ctício, escrito em PHP:
<?php
header('Last-Modified: ' .
gmdate('D, d M Y H:i:s', filemtime(__FILE__)) . ' GMT');
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
    strtotime($_SERVER['HTTP_    IF_MODIFIED_SINCE']) >=
filemtime(__FILE__))
{
    header('HTTP/1.0 304 Not Modified');
    exit;
}
sleep(5);
?>
<h1>Last-Modified example</h1>
<?php
echo date("Y-m-d H:i:s").'<br />';
Como no exemplo de implementação anterior, simulamos a espera
causada pela alta carga e usamos uma instrução sleep para fazer o
aplicativo parecer mais lento do que realmente é.

Como o Varnish lida com solicitações condicionais


Quando o Varnish detecta um cabeçalho If-Modified-Since ou If-None-
Match na solicitação, ele rastreia o timestamp de Last-Modified e/ou o Etag.
Tendo ou não o objeto sido armazenado em cache pelo Varnish, um
código de status 304 será retornado se o cabeçalho Last-Modified ou Etag
coincidir.
Do ponto de vista do cliente, o Varnish reduz a quantidade de bytes
enviada retornando o código 304.
Por outro lado, o Varnish também dá suporte a solicitações condicionais
quando se trata de comunicação com o backend: se um objeto for
considerado obsoleto, o Varnish enviará cabeçalhos If-Modified-Since e
If-None-Match para o backend se a resposta anterior tiver um timestamp
Last-Modified ou um Etag.
Quando o backend retorna um código de status 304, o Varnish não recebe
o corpo da resposta e presume que o conteúdo não mudou. Como
consequência, os dados obsoletos são revalidados e deixam de ser
obsoletos. O cabeçalho de resposta Age é rede nido para zero e o objeto
residirá no cache conforme o tempo de vida de nido pelo servidor web
ou aplicativo.
Os dados obsoletos costumam ser revalidados pelo Varnish, mas há uma
variável VCL que permite manipular esse comportamento: a variável
beresp.keep de ne por quanto tempo objetos obsoletos serão retornados
durante a execução de uma solicitação condicional. Ela é basicamente um
período de tempo adicionado ao tempo de vida. Isso permite que o
Varnish execute as solicitações condicionais de maneira assíncrona sem o
cliente vivenciar esperas. A variável beresp.keep tem operação
independente da variável beresp.grace.

Tanto beresp.keep quanto beresp.grace, assim como vários outros objetos e


variáveis do VCL, serão discutidas no Capítulo 4.

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.

O valor do cabeçalho Vary só pode conter um cabeçalho de solicitação válido


de nido pelo cliente. Você pode usar o valor de cabeçalhos HTTP X-
personalizados como variação de cache, mas será preciso se certi car se eles foram
de nidos pelo cliente.
Um exemplo muito comum é a detecção de idioma baseada no cabeçalho
de solicitação Accept-Language. O navegador envia esse cabeçalho em cada
solicitação. Ele contém um conjunto de idiomas ou regiões geográ cas
que o navegador suporta. O aplicativo pode então usar o valor desse
cabeçalho para determinar o idioma da saída. Se o idioma desejado não
for exposto no URL ou por meio de um cookie, a única maneira de
conhecê-lo é usando o cabeçalho Accept-Language.
Se não houver um cabeçalho de variação de nido, o cache (o cache do
navegador ou qualquer cache intermediário) não terá como identi car a
diferença e armazenará o objeto com base na primeira solicitação. Se ela
tiver sido feita em holandês, enquanto o cache existir todos os outros
usuários obterão a saída nesse idioma – não importando o idioma do
navegador.
Esse é um problema genuíno, logo, nesse caso, o aplicativo retorna um
cabeçalho Vary contendo Accept-Language como seu valor. Aqui está um
exemplo:
O idioma do navegador está con gurado com holandês:
GET / HTTP/1.1
Host: localhost
Accept-Language: nl
O aplicativo de ne um cabeçalho Vary que instrui o cache a manter uma
versão separada do objeto armazenado baseada no valor do cabeçalho
Accept-Language da solicitação.
HTTP/1.1 200 OK
Host: localhost
Vary: Accept-Language
Hallo, deze pagina is in het Nederlands geschreven.
O cache sabe que há uma versão desse recurso em holandês e a
armazenará separadamente, mas ainda a vinculará ao objeto armazenado
do recurso principal. Quando a próxima solicitação for enviada de um
navegador que só suporte inglês, o objeto armazenado em cache contendo
a saída em holandês não será servido. Uma nova solicitação será feita pelo
backend e a saída será armazenada separadamente.

Cuidado ao executar variações de cache baseadas em cabeçalhos de solicitação


que podem conter muitos valores diferentes. Os cabeçalhos User-Agent e Cookie
são ótimos exemplos.
Em várias situações, não temos controle total sobre o valor do cookie. Rastrear
cookies de nidos por serviços de terceiros pode adicionar ao cookie valores
exclusivos por usuário. Isso pode resultar em variações demais, provocando a queda
da taxa de acertos.
O mesmo se aplica a User-Agent: quase todos os dispositivos têm seu próprio
User-Agent. Se ele for usado como variação de cache, a taxa de acertos pode cair
muito rapidamente.
O Varnish respeita o cabeçalho Vary e adiciona variações ao cache a partir
dos identi cadores-padrão. Os identi cadores típicos de um objeto
armazenado em cache são o nome de host (ou o endereço IP se não for
de nido um nome de host) e o URL.
Quando o Varnish nota uma variação, ele cria um objeto no cache para
essa versão. As variações de cache podem expirar separadamente, mas
quando o objeto é invalidado, elas também desaparecem.

Você tem de encontrar um equilíbrio entre o fornecimento de variações de cache


su cientes e uma boa taxa de acertos. Selecione o cabeçalho de solicitação certo no
qual a variação será baseada e procure o equilíbrio.

Comportamento do VCL interno do Varnish


Agora que sabemos como o Varnish lida com o HTTP, podemos resumir
como ele se comporta internamente no estado em que o adquirimos.
Aqui está um conjunto de perguntas para fazer a si mesmo:
1. Quando uma solicitação é considerada armazenável em cache no
Varnish?
2. Quando o Varnish contorna o cache?
3. Como o Varnish identi ca um objeto?
4. Quando o Varnish armazena um objeto em cache?
5. O que ocorre quando um objeto não é armazenado em cache?
6. Por quanto tempo o Varnish armazena um objeto em cache?
Parece um enigma, não? Permita-me fornecer as respostas e explicar de
que forma o Varnish segue as melhores práticas do HTTP.

Quando uma solicitação é considerada armazenável em cache?


Quando o Varnish recebe uma solicitação, ele tem de decidir se a reposta
pode ou não ser armazenada em cache ou até mesmo se ela pode ser
servida a partir do cache. As regras são simples e baseadas na
idempotência e no estado.
Uma solicitação é armazenável em cache quando:
• Seu método é GET ou HEAD
• Não há cookies sendo enviados pelo cliente
• Não há cabeçalho de autorização sendo enviado
Quando esses critérios são atendidos, o Varnish procura o recurso no
cache e decide se uma solicitação de backend será necessária ou se a
resposta pode ser servida a partir do cache.

Quando o Varnish contorna o cache?


Quando uma solicitação não é armazenável em cache, ela é passada
adiante, uma conexão com o backend é estabelecida e o resultado é
armazenado no cache hit-for-pass. Um exemplo seria uma solicitação
POST.
No entanto, tudo isso acontecerá se o método da solicitação for um
método válido em conformidade com o RFC2616
(https://tools.ietf.org/html/rfc2616). Outros métodos de solicitação não
serão processados, sendo canalizados diretamente para o backend.
Quando o Varnish entra no modo pipe, ele abre uma conexão TCP com o
backend, transmite a solicitação original e retorna imediatamente a
resposta. Não há um processamento adicional da solicitação ou resposta.
Aqui está uma lista de métodos de solicitação válidos de acordo com o
VCL interno:
• GET
• HEAD
• PUT
• POST
• DELETE
• TRACE
• OPTIONS
Todos os outros métodos de solicitação serão canalizados para o backend.
O RFC 2616 (https://tools.ietf.org/html/rfc2616) não dá suporte a métodos de
solicitação como PATCH, LINK ou UNLINK. Eles foram introduzidos no RFC 2068
(https://tools.ietf.org/html/rfc2068#section-19.6.1). Se você precisar de suporte para
algum deles, terá de personalizar seu VCL e incluí-los.
A seção “Arquivo VCL do mundo real”, oferece uma solução para isso.

Como o Varnish identi ca um objeto?


Uma vez decidido que um objeto é armazenável em cache, precisaremos
de uma maneira de identi cá-lo para recuperá-lo posteriormente. Uma
chave hash é composta por vários valores que servem como identi cador
exclusivo.
1. Se a solicitação tiver um cabeçalho Host, o nome do host será
adicionado ao hash.
2. Caso contrário, o endereço IP será adicionado ao hash.
3. O URL da solicitação é adicionado ao hash.
Com base nesse hash, o Varnish recuperará o objeto no cache.

Quando o Varnish armazena um objeto em cache?


Se um objeto não for armazenado em cache ou se for considerado
obsoleto, uma conexão será estabelecida com o backend. De acordo com a
resposta do backend, o Varnish decidirá se o objeto retornado será
armazenado em cache ou se o cache será contornado.
Uma reposta é armazenada em cache quando:
• O tempo de vida é maior que zero.
• Ela não contém um cabeçalho Set-Cookie.
• O cabeçalho Cache-control não contém os termos no-cache, no-store
ou private.
• O cabeçalho Vary não contém *, signi cando variação conforme todos
os cabeçalhos.
O que ocorre quando um objeto não é armazenado em cache?
Se após a resposta do backend o Varnish decidir que um objeto não será
armazenado em cache, ele colocará o objeto em uma “lista negra” – o
chamado cache hit-for-pass.
Durante 120 segundos, as solicitações seguintes se conectarão
imediatamente com o backend, servindo a resposta de maneira direta,
sem tentar armazená-la em cache.
Após 120 segundos, na próxima solicitação, a resposta poderá ser
reavaliada e uma decisão será tomada em relação a se o objeto deve ou
não ser armazenado em cache.

Por quanto tempo o Varnish armazena um objeto em cache?


Depois que um objeto é armazenado em cache, uma decisão deve ser
tomada sobre seu tempo de vida. Já mencionei isso, mas há uma lista de
prioridades que o Varnish usa para decidir qual valor ele usará como
TTL.
Aqui está a lista priorizada:
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.
Quando o objeto é armazenado no cache hit-for-pass, ele é armazenado
por 120 segundos, a menos que alguém altere o valor no VCL.

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

Varnish Con guration Language

Como já mencionado, o Varnish é um proxy de cache reverso. Há muitos


outros proxies reversos que fazem o armazenamento em cache, até mesmo
no ecossistema open source. A principal razão para o Varnish ser tão
popular é, sem dúvida, o Varnish Con guration Language (VCL) – uma
linguagem de domínio especí co usada para controlar o comportamento do
Varnish.
A exibilidade que o VCL oferece não tem precedentes nesse tipo de
software. Trata-se de expressar e controlar o comportamento
programando-o em vez de declará-lo em um arquivo de con guração.
Devido à rica API exposta por meio dos objetos do VCL, o nível de
detalhe com o qual podemos ajustar o Varnish é dos melhores.
As chaves, o término de instruções com ponto e vírgula e o estilo de
comentário do VCL lembram linguagens de programação como C, C++ e
Perl. Talvez seja por isso que o VCL pareça tão intuitivo; com certeza ele
se sai melhor que a de nição de regras em um arquivo XML.
O Varnish Con guration Language não é apenas parecido com C; ele é
realmente compilado para C e carregado de forma dinâmica como um
objeto compartilhado quando o arquivo VCL é carregado pelo runtime
do Varnish. Poderíamos até chamar esse processo de transpilação, porque
estamos convertendo um código-fonte especí co em código-fonte em
outra linguagem de programação.

Se quiser saber qual é a aparência do código C, basta executar o programa


varnishd com a opção -C para ver a saída.
Neste capítulo você aprenderá como o VCL nos permite usar hooks na
máquina de estados nitos do Varnish para estender programaticamente
seu comportamento. Abordaremos as diversas sub-rotinas, objetos e
variáveis que permitem estender esse comportamento.
Já mencionei o VCL interno no Capítulo 3. Neste capítulo você verá seu
código real.

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.

Se você não de nir explicitamente uma instrução de retorno, o Varnish usará


como fallback o VCL interno que foi embutido no código do sistema. Isso pode
desativar o comportamento estendido que você de niu em seu arquivo VCL.
Esse é um erro comum, um erro que cometi quando estava começando. No entanto,
é bom ressaltar: isso não é ruim porque o VCL interno segue as melhores práticas
do HTTP.
Recomendo inclusive que você reduza o uso de VCL personalizado e use o VCL
interno o máximo possível.

Você passará 90% de seu tempo em vcl_recv


Quando você escrever código VCL, passará cerca de 90% de seu tempo em
vcl_recv, 9% em backend_response e o 1% restante em várias outras sub-rotinas.
Sub-rotinas do lado do cliente
Aqui está uma lista de sub-rotinas do lado do cliente:
vcl_recv
Executada no início de cada solicitação.
vcl_pipe
Passa a solicitação diretamente para o backend sem se preocupar com o
cache.
vcl_pass
Passa a solicitação diretamente para o backend. O resultado é
armazenado em cache.
vcl_hit
Chamada quando uma busca no cache é bem-sucedida.
vcl_miss
Chamada quando um objeto não foi encontrado no cache.
vcl_hash
Chamada após vcl_recv para criar um valor hash para a solicitação.
Esse valor é usado como chave na busca do objeto no Varnish.
vcl_purge
Chamada quando um expurgo foi executado em um objeto e este foi
removido com sucesso do cache.
vcl_deliver
Executada no m de uma solicitação quando a saída é retornada para o
cliente.
vcl_synth
Retorna um objeto sintético para o cliente. Esse objeto não tem origem
em uma busca no backend; ele é composto sinteticamente no VCL.

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 de inicialização e limpeza


Para concluir, há duas sub-rotinas que são usadas para manipular a
inicialização e a limpeza de VMODs:
vcl_init
Chamada quando o VCL é carregado. Os VMODs podem ser
inicializados aqui.
vcl_fini
Chamada após o VCL ser executado. Os VMODs podem ser removidos
aqui.

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)

A nalidade da divisão é a manipulação assíncrona de buscas no backend.


Fazendo isso, o Varnish pode servir dados obsoletos enquanto uma nova versão do
objeto armazenado em cache está sendo procurada. Esse esquema signi ca menos
en leiramento de solicitações quando o backend é lento.
Chegamos a um ponto em que as sub-rotinas começam a fazer sentido.
Para resumir, repetiremos algumas partes importantes do uxo de
execução:
• Todas as sessões começam em vcl_recv.
• As buscas no cache ocorrem em vcl_hash.
• Solicitações não armazenáveis em cache são passadas diretamente
para o backend em vcl_pass. As respostas não são armazenadas em
cache.
• Itens que foram encontrados no cache são manipulados por vcl_hit.
• Itens que não foram encontrados são manipulados por vcl_miss.
• Cache misses ou solicitações passadas adiante são buscados no
backend por vcl_backend_fetch.
• As respostas do backend são manipuladas por vcl_backend_response.
• Quando uma busca no backend falha, o erro é manipulado por
vcl_backend_error.
• Respostas válidas armazenadas em cache, passadas adiante ou que
geraram um erro de acesso são distribuídas por vcl_deliver.
Agora você já conhece o vocabulário básico que usaremos para nomear os
diferentes estágios da máquina de estados nitos. É hora de conhecer a
sintaxe e os objetos do VCL para modi car solicitações e respostas HTTP
e fazer a transição para outros estágios do uxo.

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.

O Varnish versão 4 apresenta uma mudança bastante signi cativa na sintaxe do


VCL se compararmos com a versão 3: todos os arquivos VCL devem começar com
vcl 4.0;.
Muitos exemplos de VCL deste livro não começam com vcl 4.0; porque os
considero apenas excertos e não o arquivo VCL completo. Lembre-se disso.
O manual de referência completo do VCL (https://www.varnish-
cache.org/docs/4.1/reference/vcl.html) pode ser encontrado no site do
Varnish.

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"));
    }
}

Ao colocar parênteses ao redor de partes de sua expressão regular, você agrupará


essas partes. Cada grupo pode ser endereçado na parte sub. Endereçamos um grupo
por sua classi cação. No caso do exemplo anterior, o grupo \1 representa o
primeiro grupo. É ele que contém o idioma que queremos extrair.

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);
}

Importando módulos Varnish


As importações nos permitem carregar módulos Varnish (VMODs,
Varnish modules). Esses módulos são escritos em C e estendem o
comportamento do Varnish, além de enriquecer a sintaxe do VCL.
O Varnish vem com alguns VMODs que você pode ativar importando-os.
Aqui está um exemplo em que importamos o VMOD std:
import std;
sub vcl_recv {
    set req.url = std.querysort(req.url);
}
O exemplo anterior executa a função querysort e retorna o URL com um
conjunto classi cado de parâmetros de querystring (string de consulta).
Isso é importante, porque quando um cliente usa os parâmetros de
querystring em uma ordem diferente, ele dispara um cache miss.
Acesse a página de documentação do vmod_std (https://www.varnish-
cache.org/docs/4.1/reference/vmod_std.generated.html) para aprender tudo
sobre essa útil extensão do VCL.

Backends e sondagens de integridade


O VCL que abordamos até agora cou restrito aos hooks que permitem
alterar o comportamento do Varnish. No entanto, não nos esqueçamos de
que a função do Varnish é armazenar respostas do backend em cache.
Logo, é hora de lidarmos com o aspecto do VCL relacionado aos
backends.
Em geral, ele tem esta aparência:
backend nome {
    .atributo = "valor";
}

O Varnish se conecta automaticamente com o backend que foi de nido primeiro.


Outros backends só poderão ser usados se atribuídos no VCL com o uso da variável
req.backend_hint.
A seguir temos uma lista dos atributos de backend suportados:
host
Atributo obrigatório que representa o nome do host ou o endereço IP
do backend.
port
Porta de backend que será usada. O padrão é a porta 80.
connect_timeout
Quanto tempo o Varnish esperará por uma conexão com o backend. O
padrão é 3,5 segundos.
first_byte_timeout
Quanto tempo o Varnish esperará o primeiro byte ser retornado do
backend após a conexão inicial. O valor-padrão é 60 segundos.
between_bytes_timeout
Quanto tempo o Varnish esperará entre cada byte para assegurar um
uxo de dados uniforme. O valor-padrão é 60 segundos.
max_connections
Quantidade total de conexões simultâneas estabelecidas com o backend.
Quando o limite é alcançado, novas conexões são descartadas.
Certi que-se de que seu backend consiga manipular esse número de
conexões.
probe
Sondagem do backend usada para veri car sua integridade. Pode ser
de nida inline ou ser acessada.
Vejamos um exemplo de código:
backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .connect_timeout = 2s;
    .first_byte_timeout = 5s;
    .between_bytes_timeout = 1s;
    .max_connections = 150;
}
No exemplo anterior, uma conexão é estabelecida com a máquina local na
porta 8080. Estamos esperando dois segundos por uma conexão inicial.
Uma vez que a conexão for estabelecida, esperaremos até cinco segundos
pela chegada do primeiro byte. Depois disso queremos receber bytes com
frequência regular. Vamos esperar um segundo entre cada byte. Serão
permitidas até 150 conexões simultâneas com o backend.

Se forem en leiradas mais solicitações ao backend do que o número permitido


con gurado em max_connections, elas falharão.
Se algum dos critérios não for atendido, um erro de backend será lançado
e a execução será passada para vcl_backend_error com um código de
status HTTP 503.
Sem o uso de uma sondagem, só poderemos detectar um backend com
problemas quando a conexão falhar. A chamada sondagem de backend
inspecionará o backend regularmente e veri cará sua integridade de
acordo com certas asserções. As sondagens podem ser de nidas de
maneira semelhante aos backends.
Em geral, elas têm este formato:
probe nome {
    .atributo = "valor";
}
Aqui está uma lista dos atributos de sondagem suportados:
url
URL solicitado pela sondagem. O padrão é /.
request
Solicitação HTTP personalizada que pode ser enviada para o backend.
expected_response
Código de status HTTP que o backend deve retornar. O padrão é 200.
timeout
Quanto tempo a sondagem esperará por uma resposta do backend. O
valor-padrão é 2 segundos.
interval
Frequência com que a sondagem é executada. O valor-padrão é 5
segundos.
window
Quantas consultas serão feitas para determinar a integridade do
backend. O valor-padrão é 8.
threshold
Quantas consultas da janela de consultas devem ser bem-sucedidas
antes que um backend seja considerado íntegro. O padrão é 3.
initial
Quantidade de consultas iniciais necessárias na inicialização do Varnish
antes de um backend ser considerado íntegro. O padrão para o limite é
-1.
A seguir temos um exemplo de sondagem de backend de nida inline:
backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = {
        .url = "/";
        .expected_response = 200;
        .timeout = 1s;
        .interval = 1s;
        .window = 5;
        .threshold = 3;
        .initial = 2;
    }
}
Veja o que ocorreu: o backend tenta se conectar com o host local na porta
8080. Há uma sondagem disponível para determinar sua integridade. A
sondagem consulta o backend na porta 8080 no URL raiz. Para que uma
consulta seja considerada bem-sucedida, é esperada uma resposta HTTP
com código de status 200, e ela deve ocorrer dentro de um segundo.
A cada segundo, a sondagem consultará o backend e o resultado de cinco
consultas será usado para determinar a integridade. Dessas cinco
consultas, pelo menos três devem ser bem-sucedidas para o backend ser
considerado íntegro. Na hora da inicialização, esse valor é de duas
consultas.
Também podemos de nir uma sondagem explicitamente, nomeá-la e
reutilizá-la para vários backends. Aqui está um exemplo de código que faz
isso:
probe myprobe {
    .url = "/";
    .expected_response = 200;
    .timeout = 1s;
    .interval = 1s;
    .window = 5;
    .threshold = 3;
    .initial = 2;
}
backend default {
    .host = "my.primary.backend.com";
    .probe = myprobe;
}
backend backup {
    .host = "my.backup.backend.com";
    .probe = myprobe;
}
Esse exemplo tem dois backends, ambos sendo executados na porta 80,
porém em máquinas separadas. Usamos a sondagem myprobe para
veri car a integridade das duas máquinas, mas só a de nimos uma vez.
No Capítulo 6 abordaremos tópicos mais avançados referentes aos
backends e às sondagens.

Listas de controle de acesso


As listas de controle de acesso, ou ACLs como gostamos de chamá-las, são
estruturas da linguagem VCL que contêm endereços IP, intervalos de
endereços IP ou nomes de host. Com o VCL, podemos nomear uma ACL
e associar endereços IP a ela.
As ACLs são mais usadas para restringir o acesso a certas partes de um
conteúdo ou lógica de acordo com o endereço IP. A busca pode ser feita
com o uso do operador de busca (~) em uma cláusula if.
Aqui está um exemplo de código:
acl allowed {
    "localhost";     # eu
    "192.0.2.0"/24;  # e todas as pessoas da rede local
    ! "192.0.2.23";  # exceto por um endereço IP
}
sub vcl_recv {
    if(!client.ip ~ allowed) {
        return(synth(403,"You are not allowed to access this page."));
    }
}
No exemplo anterior, só conexões locais são permitidas, ou conexões que
venham do intervalo de endereços IP 192.0.2.0/24, com uma exceção:
conexões de 192.0.2.23 não são permitidas. Também não será permitido
que nenhum outro endereço IP tenha acesso – ele verá uma mensagem de
erro HTTP 403 se tentar.
No Capítulo 5, usaremos ACLs para restringir o acesso ao mecanismo de
invalidação de cache.

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.

VCL interno do Varnish


Lembra-se da seção “Comportamento do VCL interno do Varnish”, na
qual falei sobre o assunto? Agora que sabemos como o VCL funciona,
podemos traduzir esse comportamento para um arquivo VCL completo.
Mesmo se você não registrar um arquivo VCL ou se seu arquivo VCL só
tiver uma de nição de backend, o Varnish se comportará da seguinte
forma:1
/*-
* Copyright (c) 2006 Verdens Gang AS
* Copyright (c) 2006-2015 Varnish Software AS
* All rights reserved.
*
* Author: Poul-Henning Kamp <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
the
*    documentation and/or other materials provided with the
distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF
* SUCH DAMAGE.
*
*
* The built-in (previously called default) VCL code.
*
* NB! You do NOT need to copy & paste all of these functions into your
* own vcl code, if you do not provide a definition of one of these
* functions, the compiler will automatically fall back to the default
* code from this file.
*
* This code will be prefixed with a backend declaration built from the
* -b argument.
*/
vcl 4.0;
#######################################################################
# Client side
sub vcl_recv {
    if (req.method == "PRI") {
        /* We do not support SPDY or HTTP/2.0 */
        return (synth(405));
    }
    if (req.method != "GET" &&
        req.method != "HEAD" &&
        req.method != "PUT" &&
        req.method != "POST" &&
        req.method != "TRACE" &&
        req.method != "OPTIONS" &&
        req.method != "DELETE") {
        /* Non-RFC2616 or CONNECT which is weird. */
        return (pipe);
    }
    if (req.method != "GET" && req.method != "HEAD") {
        /* We only deal with GET and HEAD by default */
        return (pass);
    }
    if (req.http.Authorization || req.http.Cookie) {
        /* Not cacheable by default */
        return (pass);
    }
    return (hash);
}
sub vcl_pipe {
    # By default Connection: close is set on all piped requests, to
stop
    # connection reuse from sending future requests directly to the
    # (potentially) wrong backend. If you do want this to happen, you
can
    # undo it here.
    # unset bereq.http.connection;
    return (pipe);
}
sub vcl_pass {
    return (fetch);
}
sub vcl_hash {
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }
    return (lookup);
}
sub vcl_purge {
    return (synth(200, "Purged"));
}
sub vcl_hit {
    if (obj.ttl >= 0s) {
        // A pure unadultered hit, deliver it
        return (deliver);
    }
    if (obj.ttl + obj.grace > 0s) {
        // Object is in grace, deliver it
        // Automatically triggers a background fetch
        return (deliver);
    }
    // fetch & deliver once we get the result
    return (miss);
}
sub vcl_miss {
    return (fetch);
}
sub vcl_deliver {
    return (deliver);
}
/*
* We can come here "invisibly" with the following errors: 413, 417 &
503
*/
sub vcl_synth {
    set resp.http.Content-Type = "text/html; charset=utf-8";
    set resp.http.Retry-After = "5";
    synthetic( {"<!DOCTYPE html>
<html>
    <head>
        <title>"} + resp.status + " " + resp.reason + {"</title>
    </head>
    <body>
        <h1>Error "} + resp.status + " " + resp.reason + {"</h1>
        <p>"} + resp.reason + {"</p>
        <h3>Guru Meditation:</h3>
        <p>XID: "} + req.xid + {"</p>
        <hr>
        <p>Varnish cache server</p>
    </body>
</html>
"} );
    return (deliver);
}
#######################################################################
# Backend Fetch
sub vcl_backend_fetch {
    return (fetch);
}
sub vcl_backend_response {
    if (beresp.ttl <= 0s ||
        beresp.http.Set-Cookie ||
        beresp.http.Surrogate-control ~ "no-store" ||
        (!beresp.http.Surrogate-Control &&
            beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
         beresp.http.Vary == "*") {
        /*
         * Mark as "Hit-For-Pass" for the next 2 minutes
         */
        set beresp.ttl = 120s;
        set beresp.uncacheable = true;
    }
    return (deliver);
}
sub vcl_backend_error {
    set beresp.http.Content-Type = "text/html; charset=utf-8";
    set beresp.http.Retry-After = "5";
    synthetic( {"<!DOCTYPE html>
<html>
    <head>
        <title>"} + beresp.status + " " + beresp.reason + {"</title>
    </head>
    <body>
        <h1>Error "} + beresp.status + " " + beresp.reason + {"</h1>
        <p>"} + beresp.reason + {"</p>
        <h3>Guru Meditation:</h3>
        <p>XID: "} + bereq.xid + {"</p>
        <hr>
        <p>Varnish cache server</p>
    </body>
</html>
"} );
    return (deliver);
}
#######################################################################
# Housekeeping
sub vcl_init {
}
sub vcl_fini {
    return (ok);
}
Resumindo, é isto que o código anterior faz:
• Não dá suporte ao método PRI e lança um erro HTTP 405 quando ele é
usado.
• Métodos de solicitação diferentes de GET, HEAD, PUT, POST, TRACE, OPTIONS
e DELETE não são considerados válidos e são canalizados diretamente
para o backend.
• Só solicitações GET e HEAD podem ser armazenadas em cache; outras
solicitações são passadas para o backend e não são servidas a partir do
cache.
• Quando uma solicitação contém um cabeçalho de cookie ou de
autorização, ela é passada para o backend e a resposta não é
armazenada em cache.
• Se nesse ponto a solicitação não for passada para o backend, ela será
considerada armazenável em cache e uma chave de busca no cache
será composta.
• Uma chave de busca no cache é um hash composto pelo URL e o
nome do host ou o endereço IP da solicitação.
• Objetos que não forem obsoletos serão servidos a partir do cache.
• Objetos obsoletos que tiverem algum tempo extra também serão
servidos a partir do cache.
• Todos os outros objetos disparam um erro de acesso e são procurados
no cache.
• Respostas do backend que não tiverem um TTL positivo serão
consideradas inalcançáveis e serão armazenadas no cache hit-for-pass.
• Respostas do backend que enviarem um cabeçalho Set-Cookie também
serão consideradas inalcançáveis e serão armazenadas no cache hit-
for-pass.
• Repostas do backend com no-store no cabeçalho Surrogate-Control
não são armazenadas no cache.
• Respostas do backend contendo no-cache, no-store ou private no
cabeçalho Cache- control não são armazenadas no cache.
• Respostas do backend que tiverem um cabeçalho Vary que crie
variações de cache em cada cabeçalho de solicitação não serão
consideradas armazenáveis em cache.
• Quando os objetos são armazenados no cache hit-for-pass, eles
permanecem nessa lista negra por 120 segundos.
• Todas as outras respostas são distribuídas e armazenadas em cache.

Arquivo VCL do mundo real


O arquivo VCL que você viu em “VCL interno do Varnish”, representa o
comportamento desejado do Varnish. Em um mundo ideal, esse código
VCL deve ser su ciente para tornar qualquer site à prova de falhas. Porém,
a verdade é que os sites, aplicativos e APIs atuais não obedecem a 100%
dessas regras.
O VCL interno assume que sites armazenáveis em cache não têm cookies.
No entanto, são poucos os sites sem cookies. O arquivo VCL a seguir lida
com esses casos do mundo real e aumenta muito a taxa de acertos.

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.

Há espaço para melhorias? Envie para Mattias uma pull request


(github.com/mattiasgeniar/varnish-4.0-con guration-templates) e explique o porquê.

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.

1 Esse código é o VCL que é usado quando instalamos o Varnish.


CAPÍTULO 5

Invalidando o cache

Neste capítulo destacarei várias estratégias de invalidação do cache. Essas


estratégias permitem remover certos itens do cache mesmo que seu tempo
de vida ainda não tenha expirado.
No universo do armazenamento em cache, só há uma coisa pior que uma
baixa taxa de acertos: o armazenamento por um tempo muito longo. Essa
declaração parece estranha, não? Estou tentando convencê-lo a armazenar
tudo o que puder em cache, o tempo todo, e dizendo ao mesmo tempo
que armazenar em cache por um período muito longo é a pior coisa a se
fazer. Preciso me explicar.

Armazenando por um tempo muito longo


No decorrer deste livro, durante todo o tempo considerei os interesses do
proprietário do site, do desenvolvedor e do administrador do sistema. A
verdade é que o site, a API e o aplicativo são principalmente serviços que
o usuário nal consome. No m das contas, tudo tem a ver com o usuário
nal.
• Por que queremos tornar o site mais veloz? Para o usuário!
• Por que queremos manter o site disponível? Para o usuário!
• Por que armazenamos em cache? Para que o usuário tenha uma boa
experiência!
O armazenamento de dados em cache por um tempo muito longo
compromete a integridade dos dados, fornecendo ao usuário uma
experiência ruim quando uma saída atualizada é importante. Isso ocorre
principalmente em sites novos.
Já falamos sobre o uso dos cabeçalhos Cache-control e Expires. É
importante estimar o tempo de vida certo e de nir os valores corretos
para esses cabeçalhos. Quanto mais preciso for o tempo de vida, melhor
será o equilíbrio.
Infelizmente, em muitos casos os dados cam desatualizados antes
mesmo de o objeto expirar. Con gurá-lo com um valor mais baixo pode
prejudicar a integridade e a capacidade de resposta do backend. Ou seja, é
car entre a cruz e a espada!
Mas não se preocupe – o Varnish nos protege! Ele oferece vários
mecanismos para a remoção de objetos do cache de acordo com certos
critérios. Acessando esses mecanismos de remoção, você pode invalidar
objetos ativamente, mesmo se eles não tiverem expirado. Dessa forma, as
notícias mais recentes serão exibidas de maneira correta na primeira
página de seu site, mesmo se o objeto ainda tiver duas horas de vida de
acordo com o tempo de vida.
A documentação do Varnish tem uma página dedicada à invalidação do
cache (https://www.varnish-cache.org/docs/4.1/users-guide/purging.html).
Faça uma consulta se tiver interesse.

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.

O objeto obj só armazena os cabeçalhos de resposta, o corpo da resposta e


metadados. Ele não tem informações da solicitação. O espreitador de
banimentos também não tem essas informações, por isso a thread espreitadora
de banimentos só pode remover itens do cache se o banimento encontrar objetos
que não tenham o contexto da solicitação, como obj. Todos os outros banimentos
são removidos na hora da solicitação e não são feitos em segundo plano.
Aqui está um exemplo básico de BAN. Ele faz a mesma coisa que o exemplo
de PURGE, mas adiciona recursos de busca de padrões de URL:
acl ban {
    "localhost";
    "192.168.55.0"/24;
}
sub vcl_recv {
    if (req.method == "BAN") {
        if (!client.ip ~ ban) {
            return(synth(403, "Not allowed."));
        }
        ban("req.http.host == " + req.http.host +
            " && req.url ~ " + req.url);
        return(synth(200, "Ban added"));
    }
}

Se acumularmos muitos banimentos baseados em variáveis de objetos req de


recursos que não sejam acessados com frequência, o Varnish pode ter problemas de
desempenho da CPU.
Os banimentos serão mantidos na lista até todos os objetos do cache terem sido
procurados nela. Se os objetos banidos não receberem um novo acesso, eles
permanecerão na lista. Quanto mais longa a lista, mais tempo de CPU será
necessário para a veri carmos a cada acesso.
Por isso é recomendável usar banimentos que sejam amigáveis com o espreitador.

Banimentos amigáveis com o espreitador


O espreitador de banimentos é responsável por veri car e limpar
assincronamente a lista de banimento. Como mencionado, ele tem um
escopo limitado para invalidar objetos devido à falta de informações de
solicitação: o espreitador de banimentos só conhece o contexto de obj.
No entanto, se copiarmos informações de solicitação a partir do objeto
req, poderemos criar banimentos que sejam amigáveis com o espreitador.
Veja o fragmento VCL a seguir:
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."));
        }
        ban("obj.http.x-host == " + req.http.host +
            " && obj.http.x-url ~ " + req.url);
        return(synth(200, "Ban added"));
    }
}
O truque é adicionar o host e o URL da solicitação como cabeçalho de
resposta quando o objeto é armazenado em cache. Se zermos isso, o
contexto de solicitação estará presente. Sei que é um artifício, mas ajuda a
resolver o problema.
set beresp.http.x-host = bereq.http.host; de nirá um cabeçalho x-host
personalizado contendo o host da solicitação, e set beresp.http.x-url =
bereq.url; de nirá o URL como cabeçalho de resposta x-url
personalizado.
Agora, além de a invalidação ser executada na hora da solicitação quando
ocorrer o próximo acesso, ela será feita assincronamente pelo espreitador
de banimentos. O espreitador terá as informações de solicitação
necessárias para processar banimentos da lista que contenham um URL
coincidente.
Após o banimento removeremos apenas os cabeçalhos personalizados; já
que eles são de uso interno, não têm serventia para o usuário. Isso é feito
em vcl_deliver.
O espreitador de banimentos não remove itens da lista imediatamente; há
três parâmetros que in uenciam esse comportamento:
ban_lurker_age
Os banimentos devem ter pelo menos esse tempo de existência para
serem removidos pelo espreitador. O valor-padrão é 60 segundos.
ban_lurker_batch
Número de banimentos que o espreitador processa durante uma única
execução. O valor-padrão é 1000 itens.
ban_lurker_sleep
Quantos segundos o espreitador de banimentos ca em suspensão entre
execuções. O valor-padrão é 0,010 segundo.
Se você criar banimentos amigáveis com o espreitador e sua lista de
banimento continuar longa, veri que esses parâmetros e ajuste-os de
acordo.

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 nome do método de solicitação usado para banir ou expurgar não é


importante. Contanto que você possa identi car uma solicitação de invalidação,
não haverá problema. Estamos chamando-o apenas de BAN ou PURGE. Selecione um
nome de sua preferência – certi que-se somente de que ele não seja igual ao de
outro método usado em seu aplicativo backend.

Visualizando a lista de banimento


Se estiver interessado em ver o estado atual da lista de banimento, você
pode emitir um comando ban.list no programa de administração
varnishadm. Basta executar o comando a seguir em seu servidor Varnish:
varnishadm ban.list
A saída poderia ser a seguinte:
Present bans:
0xb75096d0 1318329475.377475  10  obj.http.x-host == example.com
&& obj.http.x-url ~ ^/product/[0-9]+/details
0xb7509610 1318329470.785875 20C obj.http.x-host == example.com
&& obj.http.x-url ~ ^/category
Quer saber o que cada campo signi ca? Vejamos então:
• O primeiro campo contém o identi cador exclusivo do banimento.
• O segundo campo é o timestamp.
• O terceiro campo representa o número de objetos do cache referentes a
esse banimento. Opcionalmente, pode haver um C anexado ao terceiro
campo – é uma busca de banimento completa, em geral para
banimentos duplos.
• O quarto campo é a expressão de banimento.

Banimento na linha de comando


As duas seções anteriores abordaram a execução da invalidação do cache
do ponto de vista do HTTP, ou seja, tanto as solicitações comuns quanto
as de expurgo/banimento passando pelo mesmo canal. Mencionei a
vantagem que isso oferece: é muito fácil de codi car em VCL e
igualmente fácil de implementar no backend.
Também há algumas desvantagens:
• É preciso escrever código VCL adicional, o que aumenta a
complexidade.
• Não há maneira uniforme de implementar o banimento e o expurgo
no Varnish; o aplicativo dependerá da implementação da invalidação
em VCL.
• Embora as ACLs forneçam um nível de segurança, não há isolamento
do ponto de vista da rede.
Felizmente, o Varnish oferece um console de administração que permite
emitir instruções de banimento. Isso pode ser feito de maneira local ou
remota por meio do programa varnishadm. Em “Vinculação de endereço
CLI”, mencionei como você pode con gurar seu Varnish para aceitar
conexões remotas na interface do administrador.
O varnishadm é apenas um cliente que se conecta com o soquete da CLI
do Varnish. Você também pode estabelecer uma conexão TCP com esse
soquete e emitir comandos de banimento diretamente de seu código.
Consulte a página da documentação sobre a interface de linha de
comando do Varnish (www.varnish-cache.org/docs/4.1/reference/varnish-
cli.html) para saber mais sobre os comandos, as conexões remotas e o
protocolo de autenticação.
Aqui está um exemplo da invalidação de detalhes do produto, mas desta
vez usando a CLI:
varnishadm> ban obj.http.x-host == example.com && obj.http.x-url ~^/ ↵
product/ [0-9]+/details
200

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.

Forçando um cache miss1


A função de ban e purge é remover itens do cache – não armazenar novos
itens. O próximo usuário que consumir o recurso invalidado acionará a
reentrada do objeto no cache. Esse é um processo assíncrono e pode
passar algum tempo entre a solicitação de invalidação e a reentrada real
dos dados em cache.
Para um “recarregamento” síncrono dos dados, req.hash_always_miss é
uma solução melhor. Ao con gurar req.hash_always_miss com true em
vcl_recv, você estará pedindo ao Varnish para capturar o último valor
desse recurso, mesmo se o objeto não tiver expirado no cache. Um novo
objeto será de nido, contendo o valor atualizado. O objeto anterior não
será mais usado, mas continuará no local até expirar.

req.hash_always_miss não libera memória. Pelo contrário, adiciona objetos


extras ao cache.
Você pode usar essa estratégia de atualização, por exemplo, se for o editor
de um site. Basta usar uma ACL para se identi car e suas solicitações
nunca retornarão uma versão do recurso armazenada em cache. Sempre
que você atualizar esse recurso, verá imediatamente a versão atualizada. O
valor adicional para o usuário nal é que ele também verá a versão
atualizada do recurso, mas o resultado será armazenado em cache.
Aqui está um exemplo que ilustra o uso de req.hash_always_miss:
acl editors {
    "localhost";
    "192.168.55.0"/24;
}
sub vcl_recv {
    if (req.http.cache-control ~ "no-cache" && client.ip ~ editors) {
        set req.hash_always_miss = true;
    }
}
A cereja do bolo é que esse exemplo só força um erro quando o cliente
executa uma atualização forçada no navegador.

É difícil invalidar o cache


Invalidar o cache é importante, mas nem sempre é fácil de implementar.
Com o expurgo, o banimento e a atualização forçada, o Varnish facilita as
coisas. Infelizmente, esses são apenas instrumentos e ferramentas. A
di culdade real está em implementar esse mecanismo no aplicativo.
As invalidações podem ser construídas como jobs de manutenção
agendados ou ser hooks no sistema de gerenciamento de conteúdo. Até aí,
sem problemas – mas às vezes pode ser muito difícil saber quais recursos
devem ser invalidados.
Imagine um site de ecommerce que vendesse produtos. Os produtos
podem fazer parte de várias categorias. Suponhamos que eles fossem
apresentados em uma homepage. Se decidíssemos atualizar o nome do
produto, teríamos de invalidar os seguintes recursos:
• A página de detalhes do produto
• A homepage
• Todas as páginas de categorias em que o produto aparece
• Talvez até mesmo uma API ou um feed em que o produto apareça
• Poderíamos ter também, por exemplo, uma loja multilíngue que
demandasse invalidações em vários idiomas
Phil Karlton estava certo:
“Só duas coisas são difíceis na ciência da computação: invalidar o cache
e nomear coisas.”
– Phil Karlton
Uma invalidação de cache apropriada requer grande conhecimento do
aplicativo e da maneira como o HTTP é usado. Se você estiver usando
frameworks como o WordPress (wordpress.org/), o Drupal (drupal.org/) ou
o Magento (magento.com/), encontrará módulos de terceiros para
manipulá-la.
Um último conselho que posso dar referente à invalidação do cache é o
uso de chaves substitutas. Em vez de expurgar URLs ou padrões de URL,
você pode usar chaves substitutas para registrar tags na forma de um
cabeçalho de resposta HTTP chamado xkey; é apenas uma questão de
invalidar páginas por tag e não por URL.
Para executar a invalidação baseada em tag, podemos usar o vmod_xkey
(https://github.com/varnish/varnish-
modules/blob/master/docs/vmod_xkey.rst) que faz parte do pacote de
módulos do Varnish (https://github.com/varnish/varnish-modules). Não
abordarei as chaves substitutas com detalhes porque elas não integram o
escopo deste livro. Consulte a página, instale o pacote de módulos e faça
testes por conta própria. Isso pode ser muito útil quando várias
invalidações relacionadas precisarem ocorrer. A invalidação por tag parece
uma abordagem apropriada.
Vejamos outra abordagem: lembra-se da seção “Solicitações
condicionais”? Se seu backend for altamente otimizado para solicitações
condicionais, não será preciso expurgo ou banimento. As solicitações
condicionais atualizarão o cache automaticamente se os dados do
backend mudarem e retornarão um código HTTP 304, contanto que os
dados permaneçam inalterados.
A única maneira de a invalidação por solicitação condicional funcionar de forma
con ável será se o código backend puder manipular solicitações If-Modified-
Since ou If-None-match sem sofrer um aumento na carga. A m de evitar dados
obsoletos, normalmente temos tempos de vida baixos para nos bene ciar das
solicitações condicionais, o que adiciona uma pressão extra ao aplicativo backend.

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.

1 N.T.: Erro de acesso ao cache pelo fato de o elemento estar ausente.


CAPÍTULO 6

Lidando com backends

Embora a estratégia seja reduzir o uso do backend, ele continua sendo


parte crucial da equação. Sem o backend, não podemos armazenar
nenhum objeto em cache, e de preferência ele é que deve decidir o que
será armazenado e por quanto tempo os objetos permanecerão no cache.
Neste capítulo, falaremos sobre os backends e como você pode con gurar
o acesso a eles usando o VCL. Além disso, agruparemos backends e
executaremos o balanceamento de carga usando diretores. A manipulação
de backends íntegros e com problemas também será abordada no
capítulo.

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.

Sim, o Varnish tem recursos de balanceamento de carga. No entanto, não o


considero um balanceador de carga real. Para mim, o HAProxy
(http://www.haproxy.org/) é um balanceador de carga open source superior,
enquanto o Varnish é um melhor acelerador de HTTP. Se você não precisar de
alguns dos recursos mais avançados que o HAProxy oferece, o Varnish pode resolver
o problema.

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 aleatório (random)


O diretor aleatório distribui carga pelos backends usando um algoritmo de
distribuição ponderada de probabilidades aleatórias. Por padrão, o peso
de todos os backends é o mesmo, o que signi ca que a carga será
distribuída (quase) igualmente. Nesse aspecto, o diretor aleatório produz
o mesmo efeito do diretor round-robin, com pequenas variações.
Quando começamos a atribuir pesos especí cos aos backends, as
variações aumentam. Isso faz sentido se quisermos “poupar” um ou mais
servidores, como em uma situação em que um servidor é
subdimensionado ou hospeda outros aplicativos críticos para os negócios.
De acordo com os pesos, cada backend recebe
100 × (peso / (soma(todos_os_pesos_somados))) por cento da carga total.
Aqui está um exemplo:
sub vcl_init {
    new loadbalancing = directors.random();
    loadbalancing.add_backend(backend1,1.0);
    loadbalancing.add_backend(backend2,2.0);
}
O exemplo anterior declara um novo diretor aleatório com dois backends:
• O backend 1 recebe cerca de 33% da carga
• O backend 2 recebe cerca de 67% da carga
E então é atribuído o backend:
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.

Certi que-se de que seus backends tenham uma sondagem de integridade


anexada; caso contrário, o diretor fallback não terá como determinar se os backends
são ou não íntegros. Sem a presença de uma sondagem de integridade, o diretor
fallback não testará o próximo backend e retornará um erro HTTP 503.
Vejamos um exemplo do diretor fallback:
vcl 4.0;
import directors;
probe healthcheck {
    .url = "/";
    .interval = 2s;
    .timeout = 1s;
    .window = 3;
    .threshold = 2;
    .initial = 1;
    .expected_response = 200;
}
backend web001 {
    .host = "web001.example.com";
    .probe = healthcheck;
}
backend web002 {
    .host = "web002.example.com";
    .probe = healthcheck;
}
sub vcl_init {
    new loadbalance = directors.fallback();
    loadbalance.add_backend(web001);
    loadbalance.add_backend(web002);
}
sub vcl_recv {
    set req.backend_hint = loadbalance.backend();
}
Nesse exemplo, web001 é o backend preferencial. A sondagem de
integridade veri cará a disponibilidade da homepage a cada dois
segundos. Se duas das três veri cações forem bem-sucedidas, o backend
será considerado íntegro; caso contrário, o diretor fallback passará para o
backend web002.

É possível empilhar diretores e usá-los como membros de outros diretores. Essa é


uma maneira de combinar estratégias de balanceamento de carga.
Por exemplo, você poderia ter diretores round-robin, cada um com dois backends
em dois datacenters. Para assegurar o balanceamento de carga round-robin e ainda
ter alta disponibilidade, adicione os dois diretores como membros de um diretor
fallback.

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.

É importante esclarecer uma ideia mal interpretada: o modo grace só funciona


para itens armazenados em cache. É a única maneira de o recarregamento não ser
notado. Contanto que o objeto esteja em cache, ele pode ser servido e a chamada ao
backend é assíncrona.
No entanto, quando o objeto solicitado não está armazenado em cache, a
solicitação ao backend é síncrona e o usuário nal tem de esperar o resultado, ainda
que a busca seja feita por uma thread separada.

Ativando o modo grace


É muito fácil ativar o modo grace: basta atribuir um valor a beresp.grace
na sub-rotina vcl_backend_response:
sub vcl_backend_response {
    set beresp.grace = 30s;
}
Nesse exemplo, estamos permitindo que o Varnish continue servindo
dados obsoletos até 30 segundos além de seu tempo de vida. Quando esse
tempo expirar, voltaremos à busca síncrona. Isso signi ca que backends
lentos vivenciarão a lentidão novamente, e se o backend estiver inativo,
um erro HTTP 503 será retornado.

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

Melhorando sua taxa de acertos

Até o momento, você aprendeu as melhores práticas para implementar o


Varnish sob circunstâncias ideais. No entanto, quase sempre o mundo
está longe de ser ideal, e é preciso saber o que fazer quando as coisas não
ocorrem conforme o plano.
Este capítulo de nirá um equilíbrio entre otimizar o aplicativo e criar
código VCL apenas para lidar com suas limitações.

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á.

Retornando cedo demais


Outro erro muito comum é quando nos esquecemos das consequências
das instruções de retorno. A maioria das pessoas sabe que o Varnish não
armazena solicitações POST em cache e presume que o engine lidará com
isso.
Logo, elas escrevem um fragmento VCL como este para armazenar tudo
em cache, exceto as páginas de administração:
sub vcl_recv {
    if(req.url ~ "^/admin") {
        return(pass);
    } else {
        return(hash);
    } }
No entanto, nesse exemplo não há como o Varnish voltar para o VCL
interno – não foram de nidas medidas para manipular solicitações POST.
Assim, nesse caso todos os métodos de solicitação podem ser
armazenados em cache.

Lembre-se de que se você tentar armazenar em cache chamadas a POST ou


chamadas com outros métodos de solicitação não idempotentes, a solicitação inicial
feita ao backend será transformada em GET e seu corpo será descartado.

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.

Expurgando sem a lógica de expurgo


Quando as pessoas descobrem que podem expurgar URLs do Varnish
usando o método PURGE, elas se entusiasmam e esquecem de que o
suporte ao expurgo precisa ser implementado no arquivo VCL.
Já vi con gurações em que as pessoas usam o método PURGE sem que ele
seja implementado e sem que elas sequer notem isso. Nem mesmo o VCL
padrão reclamará quando você emitir um PURGE: a instrução if que veri ca
os métodos de solicitação será alcançada, sua solicitação será canalizada
para o backend e provavelmente uma mensagem HTTP 200 será
retornada.
Outra variação desse problema é a implementação do suporte a PURGE
após a veri cação do método de solicitação. Mesmo se você o
implementar, sua solicitação será canalizada.
Meu conselho
Procure usar apropriadamente PURGE e BAN. Para evitar confusões desse
tipo, você pode emitir instruções de banimento usando a interface de
linha de comando, como explicado em “Banimento na linha de comando”.

ACL de proteção contra acesso ao expurgo


A invalidação de cache com o uso do método PURGE e da lógica de
return(purge) é muito fácil de implementar. No entanto, se você não
proteger o acesso à lógica de expurgo por meio de uma ACL, pode ter
grandes problemas. Qualquer script kiddie1 poderia inspecionar o mapa
de seu site e executar chamadas a PURGE em todos os URLs dele. Todo o
armazenamento em cache seria então removido e a carga em seus
servidores backend aumentaria muito.
Meu conselho
Claro que o conselho é adicionar uma ACL! Consulte “Expurgo”, para ver
um exemplo. Se quiser reforçar a segurança da lógica de PURGE/BAN, use a
interface de linha de comando e proteja o acesso com um rewall.
Novamente, leia “Banimento na linha de comando”, para obter mais
informações.

Armazenamento de respostas 404 em cache


Lembra-se de algum momento em que você excluiu um arquivo e em
seguida refez seu upload rapidamente para que ninguém notasse? Bem,
com certeza notaram, porque enquanto você estava fazendo o upload,
alguém acessou a página e agora a resposta 404 está armazenada em
cache.
O Varnish armazena em cache respostas que têm os seguintes códigos de
status:
• 200 – OK
• 203 – Informação não autorizada
• 300 – Múltipla escolha
• 301 – Movido permanentemente
• 302 – Movido temporariamente
• 307 – Redirecionamento temporário
• 410 – Gone (indisponível)
• 404 – Não encontrado
Nenhum dos outros códigos de status é armazenado em cache.
Quer se certi car de que códigos 404 não sejam armazenados em cache?
Use o fragmento VCL a seguir:
sub vcl_backend_response {
    if (beresp.status == 404) {
        set beresp.ttl = 0s;
        return(deliver);
    }
}

De nindo um cabeçalho Age


Em “Expiração”, mencionei como a expiração funciona em HTTP.
Também adicionei um aviso, dizendo que o Varnish usa o cabeçalho Age
para determinar por quanto tempo ainda terá de armazenar um objeto em
cache.
Se você começar a de nir seus próprios cabeçalhos Age, isso desorganizará
a duração do cache, o que pode se tornar um problema.
Meu conselho
Não de na um cabeçalho Age por conta própria; deixe o Varnish fazer
isso para você.

Max-age versus s-maxage


A maioria das pessoas do segmento da indústria na web já ouviu falar
sobre max-age. Um número muito menor sabe o que s-maxage faz. A
presença dos dois mecanismos em seu cabeçalho Cache-control pode
gerar confusão, principalmente se os valores diferirem.
Meu conselho
Use sempre s-maxage e, se quiser que o navegador faça algum
armazenamento adicional em cache, use max-age. Utilize os instrumentos
que o HTTP fornece e empregue-os da maneira certa. Quando em
dúvida, leia o Capítulo 3.

Adicionando autenticação básica para ambientes de aceitação


Imagine esta situação – presumo que parecerá familiar: você está
trabalhando em um novo projeto para um cliente. Ele está quase
concluído e você deseja que o cliente teste os últimos recursos. O
ambiente de produção está pronto para operar, mas para evitar expor
detalhes para o meio externo cedo demais, você adicionou autenticação
básica no lado do servidor.
Durante os testes, você nota que a taxa de acertos caiu muito. E sim, isso
faz sentido, pois o VCL interno não armazena em cache solicitações que
incluam um cabeçalho Authorization.
Meu conselho
Em vez da autenticação básica, use regras de rewall ou acesso de VPN.
Se quiser realmente usar a autenticação básica, manipule-a em um nó na
frente do Varnish. Se você zer a terminação de SSL/TLS, esse nó pode
agir como servidor de autenticação.
Você também pode usar vmod_basicauth (http://git.gnu.org.ua/cgit/vmod-
basicauth.git) e manipular a autenticação no nível do Varnish em vez de
fazê-lo no do backend.
Aqui está um exemplo de código:
vcl 4.0;
import basicauth;
sub vcl_recv {
    if (!basicauth.match("/var/www/.htpasswd",req.http.Authorization))
{
        return(synth(401,"Authentication required"));
    }
    unset req.http.Authorization;
}

Cookies de sessão em todos os lugares


Uma das coisas da qual mais reclamo é o uso de cookies de sessão “a
título de prevenção”. Esse é o tipo de cookie gerado na primeira etapa do
uxo do aplicativo – porque nunca se sabe, certo?
Meu conselho
Reduza o uso de cookies. Use cookies de sessão em locais em que eles
sejam necessários. Outras metainformações, como o idioma do usuário,
podem ser armazenadas em cookies separados.
Cookies dedicados fazem mais sentido e são mais fáceis de controlar no
Varnish. Se esses cookies atrapalharem sua taxa de acertos, você pode usar
listas negras ou listas brancas de URLs para decidir onde os cookies
devem ser usados e de onde devem ser removidos.

Inexistência de variações de cache


Um caso típico em que a falta de variações de cache traz problemas seria
um site multilíngue que usasse o cabeçalho Accept-Language para
determinar o idioma e renderizar a saída no idioma apropriado.
Se não houver variação de cache nesse cabeçalho, o idioma da primeira
solicitação é que será armazenado em cache. Como desenvolvedor, você
deve car alerta para isso e adicionar um cabeçalho Vary: Accept-Language
a suas respostas.
O mesmo problema ocorre quando não executamos variação de cache no
cabeçalho Accept-Encoding: um conteúdo compactado que não ofereça
suporte à compactação pode ser servido para o cliente.
Meu conselho
Fique alerta para as variações de cache e saiba como e onde usar o
cabeçalho Vary.

Deseja realmente armazenar recursos estáticos em cache?


Em muitos casos, o número de arquivos a serem armazenados em cache é
bem maior que o espaço de armazenamento disponível no Varnish.
Quando o Varnish ca sem espaço de armazenamento, ele usa a estratégia
Menos Utilizado Recentemente (LRU, Least Recently Used) para liberar
espaço removendo itens que tenham menor número de acessos.
Infelizmente, não temos controle sobre o resultado. Porém, sejamos
francos: grande parte do armazenamento de objetos é consumida por
recursos estáticos como imagens, vídeos, documentos PDF e outros
arquivos semelhantes. Eles são chamados de recursos estáticos porque não
mudam e sua saída não é renderizada por um runtime. São apenas
arquivos transmitidos pelo servidor web.
Quase sempre, não são as imagens, os arquivos JavaScript ou mesmo os
arquivos CSS que causam carga no backend – são os scripts dinâmicos.
Scripts escritos em linguagens como PHP, Ruby, Python, ASP.NET e
muitas outras. Scripts que dependem de recursos externos como bancos
de dados, feeds ou web services. Scripts que são renderizados por um
runtime e consomem muita RAM e CPU.
É nessas situações que o armazenamento em cache é importante e o
Varnish pode fazer a diferença. Esses scripts são minúsculos e consomem
pouco espaço no armazenamento de objetos do Varnish. O número de
scripts dinâmicos em uma máquina não é tão grande e é controlado pela
implantação.
Imagens e documentos, no entanto, são com frequência controlados pelos
usuários: eles podem fazer o upload de imagens e documentos usando
um CMS. É difícil controlar o número de arquivos (razoavelmente)
grandes dos quais os usuários nais fazem upload.
Logo, em vez de nos arriscar e acreditar que a estratégia LRU funcionará,
também podemos decidir não armazenar recursos estáticos em cache no
Varnish. A única razão para armazenarmos recursos estáticos no Varnish
seria evitar estabelecer conexões demais com o backend.
Um servidor web como o Nginx (http://nginx.org/) pode manipular essas
coisas tranquilamente. A concorrência é alta? Sem problemas.
Se você acha que imagens e outros arquivos grandes estão enchendo
demais o seu cache, use o VCL a seguir:
vcl 4.0;
sub vcl_recv {
    if (req.url ~ "^[^?]*\.
(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|
        gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|ot
f|
        ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|
ttf
        |txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?
$") {
        return (pass);
    }
}
Você também poderia fornecer um nome de host separado para esses
arquivos estáticos e ignorar totalmente o Varnish – por exemplo,
http://static.example.com/image.jpg.

Listas negras e listas brancas de URLs


O controle do que será ou não armazenado em cache costuma ser feito
com listas negras e listas brancas de URLs. Ou seja, basta comparar URLs
ou padrões de URLs e decidir se eles serão ou não armazenados.
Aqui está um exemplo de lista negra. Ela faz parte de um template VCL
para o Drupal 7:
sub vcl_recv {
    if (req.url ~ "^/status\.php$" ||
        req.url ~ "^/update\.php$" ||
        req.url ~ "^/ooyala/ping$" ||
        req.url ~ "^/admin"        ||
        req.url ~ "^/admin/.*$"    ||
        req.url ~ "^/user"         ||
        req.url ~ "^/user/.*$"     ||
        req.url ~ "^/users/.*$"    ||
        req.url ~ "^/info/.*$"     ||
        req.url ~ "^/flag/.*$"      ||
        req.url ~ "^.*/ajax/.*$"   ||
        req.url ~ "^.*/ahah/.*$")
    {
        return (pass);
    }
}
Normalmente a lista negra desse exemplo passa solicitações ao backend
em que o URL representa partes do Drupal que contêm dados especí cos
do usuário. Esse também é o local em que cookies de sessão são usados
para identi car o usuário.
Você também poderia inverter a situação e usar uma lista branca:
sub vcl_recv {
    if (req.url ~ "^/products(/.*)?$")
    {
        return (hash);
    }
}
Nesse exemplo, estamos armazenando em cache não só a página
/products, mas também todas as páginas subordinadas como
/products/cellphones.

Decida o que será armazenado em cache com cabeçalhos Cache-control


Na seção anterior, listas negras e listas brancas foram usadas na de nição
do que seria ou não armazenado em cache. Embora elas sejam e cazes,
constituem código VCL adicional e, portanto, não são muito portáveis;
pre ro passar a responsabilidade para o aplicativo e seus desenvolvedores.
Uma maneira melhor de fazê-lo é deixando o aplicativo enviar um valor
no-store para recursos que não devam estar no cache. Isso dá mais
controle aos desenvolvedores. Alterações no comportamento do cache não
requerem mudanças no VCL nesse caso.
A seguir temos um código que ilustra o fato:
Cache-control: private, no-cache, no-store
Com o envio desses cabeçalhos, o Varnish não armazenará a resposta em
cache e adicionará a solicitação ao cache hit-for-pass.
No entanto, há uma grande desvantagem: a decisão ocorre no nível da
resposta, não no da solicitação. Isso di culta muito lidar com cookies.
Aqui está uma maneira não convencional de fazer esse esquema
funcionar, mesmo quando há cookies:
sub vcl_recv {
    if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
    }
    return(hash);
}
Basicamente, você está armazenando em cache tudo que for GET ou HEAD,
mesmo se houver cookies envolvidos. Há o risco de serem armazenadas
páginas que demandem valores de cookies, mas isso é responsabilidade
do desenvolvedor. Todas as páginas que demandarem interação com
cookies devem ter um cabeçalho de resposta no-store.

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

Sempre haverá cookies


Não gosto de cookies. Eles me incomodam. No entanto, precisamos deles
porque transformam um protocolo stateless, como o HTTP, em stateful. E
às vezes é disso que precisamos: poder passar informações adicionais
sobre o usuário entre solicitações. Por padrão, o Varnish não faz o
armazenamento em cache quando há um cabeçalho Cookie, e em uma
con guração ideal evitaríamos o uso de cookies.
A verdade é que sempre haverá cookies, mesmo se você não usá-los em
seu código. É fato: assim que começar a usar o Google Analytics, você terá
cookies de rastreamento. E esse é apenas um dos exemplos de cookies de
rastreamento.
Porém, ainda há mais: não existe uma solução de nitiva para esse
problema. Tudo depende do tipo de cookie e de sua função dentro do
aplicativo. Em vez de uma longa explicação conceitual, mostrarei alguns
casos de uso e exemplos de código.

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.

Remova os cookies de rastreamento


Os cookies de rastreamento têm má reputação: as pessoas acham que eles
são usados para nos “espionar”. No entanto, os pro ssionais de marketing
os usam para recuperar métricas do usuário.
Sejamos francos: se você gerencia um site, vai instalar o Google Analytics
e vai querer saber quantos visitantes diários possui, que tipo de conteúdo
eles estão consumindo e como encontraram seu site. Adivinhe: isso
requer cookies de rastreamento. Mesmo se seu site for baseado no velho e
bom HTML, ainda haverá cookies.
Contudo, os cookies não são processados pelo servidor web ou pelo
runtime do aplicativo; o navegador os processa usando JavaScript. E a
verdade é que eles atrapalham e queremos exterminá-los.
A boa notícia é que podemos fazê-lo. Com a remoção dos cookies de
rastreamento, o Varnish começará a armazenar seu site em cache
novamente. O código JavaScript que processa os cookies é executado pelo
navegador. Quando o Varnish remover os cookies, eles já terão sido
processados.
O código a seguir é simples e foi extraído de “Arquivo VCL do mundo
real”:
sub vcl_recv {
    # Alguma manipulação genérica de cookie, útil para todos os
templates
    # que vêm a seguir
    # Remove o cookie "has_js"
    set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(;
)?", "");
    # Remove qualquer cookie baseado no Google Analytics
    set req.http.Cookie = regsuball(req.http.Cookie, "__gads.=[^;]+(;
)?", "");
    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.=[^;]+(;
)?", "");
    # Remove cookies DoubleClick ofensivos
    set req.http.Cookie = regsuball(req.http.Cookie, "  gads=[^;]+(;
)?", "");
    # Remove os cookies da Quant Capital (adicionados por algum plugin,
    # todos _qca)
    set req.http.Cookie = regsuball(req.http.Cookie, "  qc.=[^;]+(;
)?", "");
    # Remove os cookies da AddThis
    set req.http.Cookie = regsuball(req.http.Cookie, "  atuv.=[^;]+(;
)?", "");
    # Remove um prefixo ";" do cookie se presente
    set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
    # Sobraram cookies apenas com espaços ou que estejam vazios?
    if (req.http.cookie ~ "^\s*$") {
        unset req.http.cookie;
    }
}
Esse exemplo executa a mágica de busca e substituição baseada em regex.
Ele identi ca cookies especí cos e os remove do cabeçalho de cookies.
Esse é apenas um conjunto de cookies de rastreamento comuns; você
pode estender a lista e remover ainda mais cookies.
Se após as ações de busca e substituição o cabeçalho de cookies não
passar de um conjunto de tabulações ou espaços, você poderá removê-lo
totalmente.

É bom lembrar que o vmod_cookie (https://github.com/varnish/varnish-


modules/blob/master/docs/vmod_cookie.rst) é um módulo Varnish que
oferece funções de limpeza, exclusão e ltragem de cookies sem ser preciso escrever
expressões regulares complexas. Esse VMOD não vem incluído por padrão e faz
parte do conjunto de módulos Varnish (https://github.com/varnish/varnish-
modules). Se por algum motivo você não puder instalá-lo, o exemplo anterior que
usa expressões regulares atenderá igualmente bem.

Remova todos, exceto alguns


Você também pode aplicar a lógica inversa: em vez de remover alguns
cookies, remova todos, exceto os que forem realmente necessários. Isso
facilita as coisas porque não será preciso editar seu código VCL sempre
que um novo cookie tiver de ser removido.
Aqui está o código que mantém só os cookies lang e PHPSESSID. Todos
os outros são removidos:
sub vcl_recv {
if (req.http.Cookie) {
    set req.http.Cookie = ";" + req.http.Cookie;
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    set req.http.Cookie = regsuball(req.http.Cookie,
        ";(lang|PHPSESSID)=", "; \1=");
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$",
"");
    if (req.http.cookie ~ "^\s*$") {
        unset req.http.cookie;
    }
}
Variações de cookie
Um cenário muito comum é o uso de cookies para rastrear preferências
do usuário. É provável que language seja o mais comum. O perigo de
armazenar essas páginas em cache é que o idioma não varia para a página
armazenada. Não armazenar a página em cache por causa do cookie de
idioma pode ser uma oportunidade perdida.
Se você tiver um controle rigoroso sobre seu cookie de idioma, poderá
executar variações de cache em VCL baseadas nele.
Vejamos um código:
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"));
    }
}
Já vimos esse código no Capítulo 4, mas ele é um bom exemplo e um
excelente caso de uso.
Não se esqueça também de que a seleção de idioma ocorre em uma
splash screen (tela de abertura). Depois que a seleção for feita, ela exibirá
o site no idioma selecionado. Essa splash screen só será exibida se não
houver um cookie de idioma ativado. Isso signi ca que se não houver um
cookie ativado, não poderemos fazer o armazenamento em cache.
Sei que parece o oposto do que tenho postulado, mas nesse caso é
essencial. O código a seguir é necessário para fazer isso funcionar:
sub vcl_recv {
    if(!req.http.Cookie ~ "language=(nl|fr|en|de|es)"){
        return(pass);
    }
}

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]+", "");
}

Quase sempre, a porta não é mencionada no URL. No entanto, adicionando a


porta 80 a um URL comum, você poderia realmente causar um cache miss.

Classi cação de strings de consulta


“Nunca con e no usuário nal”. Essa alegação foi comprovada na seção
anterior, na qual os usuários prejudicaram a taxa de acertos adicionando
uma porta. A string de consulta também é vulnerável.
No exemplo a seguir, estamos aplicando a função std.querysort para
classi car alfabeticamente parâmetros de string de consulta. Se os
usuários colocarem os parâmetros em uma ordem diferente, teremos
outro URL, um hash diferente e um cache miss como resultado.
Ao classi car os parâmetros de string de consulta, estamos eliminando
esse risco:
import std;
sub vcl_recv {
    set req.url = std.querysort(req.url);
}
Removendo parâmetros de URL do Google Analytics
O Google Analytics não adiciona apenas cookies de rastreamento às
solicitações; ele também pode injetar parâmetros de URL de
rastreamento. Esse é um truque de marketing comum para o rastreamento
em campanhas.
Como no caso dos cookies de rastreamento, esses parâmetros são
processados pelo navegador, não são úteis para o servidor e podem ser
removidos.
Aqui está um código que remove os parâmetros de URL de rastreamento:
sub vcl_recv {
    if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|
        utm_content|gclid|cx
    |ie|cof|siteurl)=") {
        set req.url = regsuball(req.url,
            "&(utm_source|utm_medium|utm_campaign
        |utm_content|gclid|cx|ie|cof
        |siteurl)=([A-z0-9_\-\.%25]+)", "");
        set req.url = regsuball(req.url, "\?(utm_source|utm_medium|
            utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)
            = ([A-z0-9_\-\.%25]+)", "?");
        set req.url = regsub(req.url, "\?&", "?");
        set req.url = regsub(req.url, "\?$", "");
    }
}

Removendo a cerquilha do URL


Você deve conhecer o sinal # (hash, ou cerquilha) do URL: ele é usado
como âncora HTML para fazer a vinculação a uma seção especí ca de
uma página. Esse é um recurso do lado do cliente, não do lado do
servidor. Podemos removê-lo desta forma:
sub vcl_recv {
    if (req.url ~ "\#") {
        set req.url = regsub(req.url, "\#.*$", "");
    }
}
Removendo o ponto de interrogação nal
Em um URL, o ponto de interrogação é usado para indicar o início dos
parâmetros de URL. Se o ponto de interrogação estiver no m de seu
URL, é porque você não tem nenhum parâmetro de URL. Então, por que
mantê-lo?
Você pode remover um ponto de interrogação nal desta forma:
sub vcl_recv {
    if (req.url ~ "\?$") {
        set req.url = regsub(req.url, "\?$", "");
    }
}

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";
    }
}

Se quiser considerar o marcador de acerto/erro como informação sigilosa, insira


uma ACL nele e só retorne o cabeçalho se o endereço IP do cliente existir na ACL.
Poderíamos até avançar um pouco mais e exibir o número de acertos:
sub vcl_deliver {
    set resp.http.X-Hits = obj.hits;
    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.

Armazenando blocos em cache


Em seu código, as diferentes seções de conteúdo podem ser construídas e
exibidas como blocos. A gura 7.1 mostra um dos mais tradicionais
leiautes de site com quatro blocos básicos:
• Cabeçalho
• Rodapé
• Navegação
• Bloco principal
Se sua seção de cabeçalho não for armazenável em cache, o resto da
página também não será. O Varnish armazena páginas em cache e não
entende blocos de conteúdo. O mínimo denominador comum desses
blocos é um erro de acesso, logo a página não será armazenada em cache.

Figura 7.1 – De nição de blocos típica com cabeçalho, rodapé, navegação e


bloco principal.
Devemos perder a esperança? Na verdade, não. Há maneiras de contornar
essas limitações:
• AJAX
• Edge Side Includes (ESI)

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!

Edge Side Includes


O AJAX é assíncrono, carregado pelo navegador e depende inteiramente
de JavaScript. Embora ele resolva muito bem o problema de
encadeamento de blocos, o servidor perde o controle sobre a saída real e
como ela é renderizada. Essa pode não ser uma solução aceitável para
você.
Se for esse o caso, o Edge Side Includes (ou ESI, como costumamos chamá-
lo; https://www.w3.org/TR/esi-lang) pode ser uma alternativa viável. O
objetivo do ESI é incluir fragmentos HTTP na saída originada por
diferentes URLs. A composição da saída ocorre na borda (edge), em vez de
no servidor web. Cada fragmento pode usar cabeçalhos Cache-control
para controlar sua própria capacidade de armazenamento em cache.
Em nosso caso, a borda é o Varnish e ele representa a extremidade mais
externa de nossa pilha web (web stack). O ESI não foi inventado pelo ou
para o Varnish. É um padrão que também é usado por redes de
distribuição de conteúdo (CDNs, content delivery networks), mas o
Varnish só dá suporte a um subconjunto de seus recursos.
Os chamados fragmentos são carregados com o uso de uma tag ESI, como
ilustrado a seguir:
<esi:include src="http://example.com/include.php" />
Essa tag é simplesmente um placeholder a partir do qual o atributo src é
processado pelo Varnish. É muito semelhante ao antigo Server-Side
Includes (SSI, https://www.w3.org/Jigsaw/Doc/User/SSI.html#include),
exceto pelo fato de que as tags SSI eram processadas pelo servidor web. As
tags ESI são processadas na borda. É como um frameset
(https://www.w3.org/TR/html401/present/frames.html#h-16.2.1) processado
no lado do servidor, porém sem a má aparência.
O código HTML a seguir é um exemplo de uma página em que o
conteúdo principal é carregado pelo servidor web – e o cabeçalho, a
navegação e o rodapé são carregados na borda:
<!DOCTYPE html>
<html>
<head>
    <title>My ESI placeholder</title>
</head>
<body>
    <header>
        <esi:include src="http://example.com/header.php" />
    </header>
    <nav>
        <esi:include src="http://example.com/nav.php" />
    </nav>
    <main>
        <!--É aqui que o conteúdo principal será carregado-->
    </main>
    <footer>
        <esi:include src="http://example.com/footer.php" />
    </footer>
</body>
</html>

Fazendo o Varnish analisar o ESI


O Varnish não analisa automaticamente tags ESI, já que consumiria
muitos recursos. Em seu código VCL, você precisa ativar a análise de ESI
de maneira explícita por solicitação.
A variável beresp.do_esi é usada para ativar e desativar a análise de ESI.
Há várias maneiras de implementar isso. Aqui está um exemplo em que
um pre xo de URL é usado para ativar a análise de ESI:
sub vcl_backend_response {
    if(bereq.url ~ "^/esi/.*$") {
        set beresp.do_esi=true;
    }
}
Nesse exemplo, é esperado que todos os URLs que comecem com /esi/
tenham tags ESI em seu conteúdo que precisem de análise. No entanto,
como ensinei várias vezes, é melhor deixar o aplicativo assumir o controle
da situação.
O próximo exemplo apresenta a análise de ESI baseada em um cabeçalho
de resposta enviado pelo aplicativo:
sub vcl_backend_response {
    if(beresp.http.x-parse-esi) {
        set beresp.do_esi=true;
    }
}
Contudo, há uma maneira mais o cial de fazê-lo. Aqui está o código que
recomendo:
sub vcl_recv {
    set req.http.Surrogate-Capability="key=ESI/1.0";
}
sub vcl_backend_response {
    if(beresp.http.Surrogate-Control~"ESI/1.0") {
        unset beresp.http.Surrogate-Control;
        set beresp.do_esi=true;
        return(deliver);
    }
}
Nesse exemplo, enviamos um cabeçalho de solicitação Surrogate-
Capability ao backend, indicando que estamos aptos a analisar o ESI. O
backend pode ir em frente e nos enviar tags ESI, sabendo que temos como
manipulá-las.
Depois que a resposta do backend retornar para o Varnish, a sub-rotina
vcl_backend_response veri cará se um cabeçalho de resposta Surrogate-
Control foi enviado contendo ESI/1.0. Com o envio desse cabeçalho, o
aplicativo anuncia que está retornando tags ESI que o Varnish deve
analisar.
Para obter mais informações sobre esses cabeçalhos, leia a Edge
Architecture Speci cation do W3C (https://www.w3.org/TR/edge-arch/).

Se você enviar cabeçalhos Surrogate-Control a partir de seu aplicativo, faça isso


somente na página de espaço reservado que contém suas tags ESI. Não é necessário
fazê-lo dentro dos recursos que são carregados por meio do ESI.
ESI versus AJAX
Defendi o uso tanto do ESI quanto do AJAX. Qual você deve escolher?
Pessoalmente, pre ro o ESI porque não dependemos do navegador – ou
de JavaScript. No entanto, ele tem algumas limitações:
• Por padrão, o Varnish requer que fragmentos HTTP carregados pelo
ESI sejam compatíveis com XHTML. Qualquer desvio causará um
erro.
• As tags ESI são analisadas sequencialmente. Se você tiver várias tags
para analisar e as páginas correspondentes forem um pouco lentas,
isso pode causar muita espera.
• A implementação do ESI no Varnish não oferece graceful
degradation2, o que signi ca que o Varnish não se recuperará de um
erro em uma subsolicitação ESI.
O ESI do Varnish também apresenta algumas vantagens:
• Podemos ter tags ESI aninhadas. A profundidade é limitada pela
variável max_esi_depth. A profundidade máxima padrão é de nida com
cinco níveis.
• O objeto req_top (https://www.varnish-
cache.org/docs/4.1/reference/vcl.html#req-top) nos permite obter
informações de solicitações a partir da solicitação de nível superior de
dentro de uma subsolicitação ESI.
• Podemos veri car o nível do aninhamento ESI usando a variável
req.esi_level.
A limitação da compatibilidade com o XHTML pode ser contornada com
a de nição de uma ag de recurso feature=esi_disable_xml_check na hora
da inicialização. Falamos sobre isso em “Parâmetros de runtime”.
O AJAX, por outro lado, tem várias vantagens óbvias:
• Para muitos desenvolvedores web, o uso do AJAX é prática comum e,
portanto, ele é mais fácil de implementar.
• Não é necessário fazer nenhuma mágica com o VCL.
• As chamadas AJAX podem ser executadas em paralelo.
• Quando uma chamada AJAX falha, ocorre uma graceful degradation: o
componente defeituoso pode ser ignorado sem interrupções e o resto
da página é exibido.
Uma das desvantagens do AJAX é que as solicitações são enviadas a partir
do cliente – e as respostas também são analisadas por ele. Se você estiver
em uma conexão não con ável, acabará tendo de lidar com várias
chamadas HTTP que podem tornar seu site lento. O tráfego móvel é um
exemplo: se você estiver em uma conexão 3G ou 2G de baixa qualidade,
as idas e vindas do HTTP serão muito caras. Se em vez disso usar o ESI,
todas as subsolicitações serão feitas no lado do servidor e um único
trajeto de ida e volta será su ciente.
Escolha com cuidado!

Tornando seu código pronto para o cache de blocos


Sei que já falei isso tantas vezes que a essa altura pode soar tedioso, mas
sou um forte defensor de capacitar o aplicativo para que tome as decisões
certas no que diz respeito ao cache. Isso também se aplica ao cache de
blocos!
Nem sempre um aplicativo está posicionado atrás de um proxy de cache
reverso, imagine de um que suporte o ESI. Recomendo que você detecte se
um cabeçalho Surrogate-Capability foi de nido antes de exibir as tags ESI
de seus blocos. Se esse cabeçalho não tiver sido de nido, não me
arriscaria e faria a renderização dos blocos por intermédio do AJAX.
Também há uma terceira opção: renderizar os blocos nativamente e não
aplicar nenhuma lógica de cache de blocos.
Muitos frameworks têm view helpers que criam automaticamente tags ESI
ou lógica AJAX. Em geral, eles têm inteligência su ciente para analisar a
subsolicitação internamente se o cabeçalho Surrogate-Capability não tiver
sido de nido. Usando os chamados view helpers para isso, você restringirá
o contexto à camada da view e não terá de adicionar uma lógica extra aos
seus controladores MVC. Esse pequeno widget se encarregará das
subsolicitações e facilitará sua vida. E no m das contas, as camadas de
modelo e controlador não se preocupam com a maneira como a saída é
visualizada.
A próxima seção contém um exemplo de código com fragmentos HTTP
carregados por intermédio do ESI e do AJAX. Con ra.

Exemplo de código contendo todas as práticas


Terminaremos este capítulo com um exemplo de código abrangente que
aplica todas as práticas recomendadas. O código foi escrito em PHP
(http://php.net/) e usa o framework Silex (https://silex.sensiolabs.org/), que é
um microframework baseado no Symfony (https://symfony.com/). O
framework é amigável com o HTTP e oferece a maioria das práticas
recomendadas prontas para uso.
O exemplo – disponível no GitHub
(https://github.com/ThijsFeryn/cacheable-site-silex) – usa as melhores
práticas HTTP a seguir:
• Usa cabeçalhos Cache-control para decidir o que será ou não
armazenado em cache
• Usa a diretiva s-maxage para de nir por quanto tempo o Varnish
poderá armazenar em cache
• Aplica uma variação de cache de idioma usando o cabeçalho Vary
• Usa uma combinação de tags ESI e chamadas AJAX para ter um
tempo de vida separado em cada bloco de conteúdo
• Usa view helpers para renderizar os blocos de conteúdo
• Dá suporte a solicitações condicionais para retornar ETags e veri car o
cabeçalho If-None-Match
Este é o código VCL necessário para o exemplo funcionar. Como você
pode ver, ele é bem limitado:
vcl 4.0;
sub vcl_recv {
    set req.http.Surrogate-Capability="key=ESI/1.0";
    if ((req.method != "GET" && req.method != "HEAD")
            || req.http.Authorization) {
        return (pass);
    }
    return(hash);
}
sub vcl_backend_response {
    if(beresp.http.Surrogate-Control~"ESI/1.0") {
        unset beresp.http.Surrogate-Control;
        set beresp.do_esi=true;
        return(deliver);
    }
}
O código VCL processa o ESI e tenta armazenar em cache tudo que for
uma solicitação GET ou HEAD. Cabe ao aplicativo decidir se isso é bom. Se
não for, o objeto acabará indo para o cache hit-for-pass.

Antes de você poder usar o código do exemplo, precisa carregar um conjunto de


dependências. Essas dependências são gerenciadas pelo Composer
(https://getcomposer.org/).
Você deve declarar suas dependências em um arquivo composer.json e executar o
comando composer install para carregá-las.

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

Registrando, avaliando e depurando

É fácil instalar o Varnish, con gurar parâmetros e ajustar o VCL, mas o


que fazer para conhecer o nível de e cácia da instalação? Podemos
examinar a estatística de carga dos servidores Varnish e backends. Se eles
estiverem bem, saberemos que o ambiente não está para explodir.
Lamentavelmente, esse esquema fornece poucas informações sobre a taxa
de acertos do cache – seria interessante identi car os hot spots do
aplicativo e veri car se eles estão sendo armazenados em cache
apropriadamente. Se certas páginas não estiverem sendo armazenadas em
cache quando deveriam estar, você vai querer saber a causa, certo? Talvez,
pela otimização de seu aplicativo ou do VCL, a carga diminua e isso leve à
redução da infraestrutura.
Felizmente, o Varnish oferece maneiras de depurar e avaliar as solicitações
HTTP, as respostas HTTP e o cache. Neste capítulo, abordaremos as
seguintes ferramentas:
• varnishstat
• varnishlog
• varnishtop
Todos esses binários usam o log compartilhado em memória, sobre o qual
falamos em “Armazenamento de log compartilhado em memória”.

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.

A taxa de amostragem padrão é de 60 segundos. Se quiser alterar esse valor, use a


opção -p para modi car a taxa de amostragem do varnishtop.

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

O que essa decisão signi ca para os negócios?

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.

Usar ou não usar uma CDN


Uma rede de distribuição de conteúdo (CDN) nada mais é do que um
conjunto de proxies de cache reversos que cam hospedados em vários
locais. A CDN é um exemplo perfeito de cache na borda.
As empresas adotam a CDN porque ela é oferecida como serviço e há
suporte disponível. Em muitos casos, a escolhem apenas para o
armazenamento em cache, não para distribuição geográ ca. A
desvantagem é o preço, mas já que o momento é de crise, dinheiro não é
problema.
Na Combell (https://www.combell.com/en/?
utm_source=Varnishbookthijs&utm_medium=pd ink) e na Sentia
(https://sentia.com/?utm_source=Varnishbookthijs&utm_medium=pd ink),
empresas para as quais trabalho, conseguimos convencer alguns de nossos
clientes a parar de pagar por uma CDN e, em vez disso, usar o Varnish.
Graças ao poder do VCL, obtivemos uma taxa de acertos muito melhor e
ganhamos mais informações devido a ferramentas como o varnishlog. E
para hospedar o Varnish eles estão pagando apenas parte do valor que
pagariam por uma CDN.
Não estou dizendo que as CDNs são inúteis. Claro que não! O Varnish
pode ser uma boa alternativa a CDNs caras, mas tudo depende do
contexto do projeto. Portanto, isso deve ser considerado. Alguns de nossos
maiores clientes precisam de uma CDN porque têm uma abrangência
global que requer vários pontos de presença, ou porque o alto número de
conexões estava saturando os dispositivos de rede. E algumas CDNs são
ótimas para evitar ataques DDoS – a menos que você tenha recursos de
rede poderosos, eles são difíceis de evitar.

Embora eu esteja apresentando o Varnish como concorrente das CDNs, várias


delas o utilizam como seus proxies de cache reversos. A Varnish Software tem até
um produto chamado Varnish Extend (https://www.varnish-
software.com/products/varnish-extend/) que nos permite instalar nossa
própria CDN privada ou híbrida.
Na verdade, essa é uma maneira fácil de estender o alcance de sua CDN: o Varnish
Extend permite adicionar servidores à CDN em regiões em que não haja ponto de
presença, basicamente criando uma instalação híbrida. Já que estamos lidando
apenas com software, podemos instalar o Varnish Extend nos servidores e em um
local de nossa preferência.

O VCL é mais barato


Quando o Varnish é implementado, geralmente isso ocorre em tempos de
crise: os servidores estão sob carga pesada e o site está lento ou
indisponível. Não há tempo a perder. Refatorar código ou otimizar
consultas a bancos de dados não são opções.
Momentos extremos fazem até mesmo o gerente mais conservador
considerar com atenção tecnologias que até então eram ignoradas. Onde
o software open source era com frequência estigmatizado como amador,
agora passa a ser uma opção genuína. Qualquer linha de ação é aceita
nesse caso. E embora eu tenha ensinado melhores práticas HTTP de nível
de aplicativo no decorrer do livro, co feliz em admitir que nessas
situações o VCL é mais barato. Até algumas linhas de um breve e
deselegante código VCL pode salvar vidas.
É nessas circunstâncias que os tomadores de decisões começam a apreciar
o Varnish. Mostre para seu gerente a sintaxe simples do VCL como
ilustrado no Capítulo 4. Exponha alguns cenários comuns de uso do VCL
como os do Capítulo 7. Compare o custo e o esforço menores com os
oferecidos pela alternativa e verá que um pouco de VCL tem grande
alcance e é difícil de vencer.
Se for convincente, pode ter certeza de que o próximo projeto de seu
gerente terá o Varnish na pilha web. Empresas que antes de uma crise não
conheciam cabeçalhos como Cache-control terão uma boa noção de como
se bene ciar do HTTP em projetos futuros.

Varnish como bloco de construção


Saímos da situação de não termos o Varnish para a de o termos quando o
caos se instala. Chamo isso de melhoria. No entanto, a verdadeira lição a
se aprender aqui é: por que não ter um proxy de cache reverso desde o
início? Como mencionado em “Armazenar em cache não é um truque”:
não reprocesse se os dados não tiverem mudado. Por que não tratar o
cache como uma estratégia?
Muitos projetos open source, como WordPress (https://wordpress.org/),
Drupal (https://www.drupal.org/) e Magento (https://magento.com/),
oferecem suporte ao Varnish. Esses plugins Varnish sabem como invalidar
o cache, vêm com um arquivo VCL e em alguns casos suportam o cache
de blocos.
Os proxies de cache reversos estão se tornando uma commodity. Se você
executar servidores Varnish dedicados, o custo aumentará. Contudo, a
economia gerada com o uso do Varnish compensa essas despesas. E se
você quiser ser econômico, basta instalá-lo em seu servidor web local –
não há nada de errado nisso.
Trabalho na indústria de hospedagem e percebo que os vendedores e
projetistas de soluções são rápidos no gatilho quando se trata de sugerir o
uso do Varnish. Quase sempre, é fácil fazê-lo. Às vezes damos uma olhada
no aplicativo e recomendamos uma refatoração ou simplesmente
escrevemos algum código VCL para a obtenção de uma taxa de acertos
decente.
Há frameworks de desenvolvimento como o Symfony
(http://symfony.com/) que vêm com um proxy de cache reverso interno que
segue as mesmas regras básicas do Varnish. É um ponto de vista
interessante: o Varnish é apenas uma implementação. Nem sempre é
importante o tipo de tecnologia que usamos, contanto que respeite
convenções e faça o que deve ser feito.
Em máquinas de desenvolvimento local, não é sempre que o Varnish está
disponível. A presença de um proxy de cache reverso interno é certamente
uma conveniência. E quando ele se comporta da mesma maneira que o
Varnish, usar o Varnish no teste/preparação/produção não é uma
operação de alto risco.
Conduzir as empresas para uma “mentalidade de armazenamento em
cache” resultará em tempos de resposta mais rápidos. Consulte “Por que o
desempenho na web é importante?”.

O caso do cliente original


No início o Varnish não era um projeto puramente open source; ele era
um software personalizado construído para o VG.no (http://www.vg.no/),
o maior site de notícias da Noruega. Poul-Henning Kamp
(http://phk.freebsd.dk/) foi trazido para o projeto para construí-lo e a
Linpro (https://www.redpill-linpro.com/) portou-o para o Linux, forneceu
as ferramentas e construiu o site. Em um dado momento a Varnish
Software (https://www.varnish-software.com/) surgiu da Linpro e agora é a
entidade comercial do projeto.
O proxy de cache reverso que foi construído para o VG.no acabou sendo
um verdadeiro sucesso e o código era su cientemente estável e limpo para
passar para a iniciativa open source.
Sem o VG.no, não haveria Varnish nem casos de qualquer outro cliente.

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.

Empresas que usam o Varnish atualmente


Há milhares de empresas usando o Varnish: pequenas, grandes e de
tamanho intermediário. Nesta seção, destacarei dois casos de clientes
interessantes em que não importa apenas a empresa, mas o que ela faz
com o Varnish.

NU.nl: investir cedo compensa


Ao investir em cache e no Varnish desde o início, você economizará
dinheiro a longo prazo. Com controle sobre os caches e know-how para
fazer a invalidação quando necessário, evitamos gastos com servidores
adicionais para ns de escalabilidade horizontal.
Acho interessantíssimo o estudo de caso do site NU.nl (http://www.nu.nl/)
da Ibuildings (https://www.ibuildings.nl/) que explica como uma estratégia
de cache agressiva permitiu que a empresa lidasse com o tráfego massivo
do site de notícias quando um avião caiu no aeroporto de Schiphol em
2009. Fotos tiradas por testemunhas foram compartilhadas no site e os
meios de comunicação tradicionais não conseguiram acompanhar o
ritmo.
O site NU.nl foi o centro das atenções no mundo inteiro naquele dia com
mais de 20 milhões de visualizações. E não sucumbiu porque o Varnish
foi capaz de servir todo o conteúdo a partir do cache. Foram necessários
apenas dois servidores Varnish para manipular esse tipo de carga.
Embora esse seja um caso antigo ocorrido em 2009, ainda gosto de contar
a história. Funcionários da Ibuildings zeram uma apresentação e a
chamaram de “Sobrevivendo a uma queda de avião” (Surviving a plane
crash, https://www.slideshare.net/peter_ibuildings/surviving-a-plane-crash).
Era sobre economizar dinheiro no custo da infraestrutura!

SFR: construa sua própria CDN


A SFR (http://www.sfr.fr/) é uma empresa francesa que fornece serviços
pro ssionais e de telecomunicações de voz, vídeo, dados e internet para
consumidores e empresas. Ela tem 21 milhões de clientes e oferece acesso
de alta velocidade à internet para 5 milhões de domicílios.
O site principal da SFR é um dos dez mais visitados na França. Os custos
de manipulação de tráfego eram tão altos que a empresa decidiu buscar
iniciativas de redução de custos e maneiras de lidar com as despesas e
esforços internamente.
A empresa decidiu construir sua própria CDN usando o Varnish. Ela
começou com o Varnish comum, mas entrou rapidamente em contato
com a Varnish Software e acabou usando o Varnish Plus. A empresa tem
tantos objetos para armazenar em cache que as opções de armazenamento
do Varnish comum não atenderam seus requisitos. O Massive Storage
Engine (https://www.varnish-software.com/plus/massive-storage-engine/)
resolveu esse problema.
A SFR também adicionou alguns VMODs que proporcionaram
otimização de largura de banda e identi cação de sessão para usuários
que consumiam vídeo a partir da CDN.

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.

Combell: Varnish em hospedagem compartilhada


Na Combell (https://www.combell.com/en/?
utm_source=Varnishbookthijs&utm_medium=pd ink), oferecemos o
Varnish até mesmo em nosso ambiente de hospedagem compartilhada
(https://www.combell.com/en/hosting/web-hosting/options?
utm_source=Varnishbookthijs&utm_medium=pd ink). Fazemos isso por
razões totalmente diferentes das sugeridas pelos casos anteriores.
Os casos do NU.nl, da SFR e da Wikipedia tinham o tema subjacente do
tráfego massivo e de como o Varnish permite que essas empresas lidem
com isso. Na Combell, oferecemos o Varnish em hospedagem
compartilhada não para ns de escalabilidade, mas para obtenção do
desempenho bruto.
Sejamos francos: a hospedagem compartilhada não é construída para
manipular tráfego pesado. Porém, sites pequenos podem car lentos por
causa de um design técnico inadequado ou de execução insatisfatória em
termos de código. Com o acréscimo do Varnish à pilha, essas solicitações
lentas podem ser aceleradas – o aumento da escalabilidade é apenas um
bônus.
No entanto, devido ao armazenamento em cache e ao design de nossa
plataforma, executamos sites no ambiente compartilhado que pode
manipular facilmente 50 mil visitantes por dia. Quando os sites têm uma
boa taxa de acertos, o Varnish permite que eles tenham muito mais
visitantes sem qualquer espera.

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

Passando para o próximo nível

Chegamos a um ponto em que você atingiu certo nível de entendimento:


• Sabe o que é Varnish e qual o seu papel
• Sabe como instalar e con gurar o Varnish
• Conhece algumas das práticas HTTP recomendadas que o Varnish
segue
• Sabe interpretar fragmentos VCL e escrever os de sua própria autoria
• Sabe como invalidar o cache (partes dele)
• Está familiarizado com os recursos de balanceamento de carga do
Varnish
• Sabe usar algumas das ferramentas de logging e monitoramento do
Varnish
• Sabe como adaptar seu aplicativo ou seu VCL a cenários do mundo
real
Então, o que vem a seguir? Este capítulo lhe mostrará a direção certa se
você quiser passar para o próximo nível. Abordarei alguns tópicos
especí cos que não fazem parte do escopo do livro e que se referem a
recursos úteis.
Falaremos sobre serviços RESTful, VMODs, o futuro do projeto Varnish e
maneiras de obter ajuda se você tiver perguntas.

E quanto aos serviços RESTful?


No decorrer deste livro enfoquei sites e aplicativos web. No entanto,
atualmente arquiteturas orientadas a serviços se tornaram comuns. A
ideia de que softwares não são consumidos apenas por humanos, mas
também por outros sistemas tornou-se corriqueira. O fato de um
aplicativo ter um feed ou uma API não parece mais tão exótico. Hoje,
geralmente o aplicativo é uma API REST e a GUI é apenas o código
frontend que a consome.
Dito isso, os serviços RESTful são muito fáceis de armazenar em cache
com o Varnish. Na verdade, Roy Fielding
(http://www.ics.uci.edu/~ elding/), que introduziu o conceito REST em sua
dissertação de PHD
(https://www.ics.uci.edu/~ elding/pubs/dissertation/top.htm), de niu-o
como “um estilo arquitetônico para descrever o design e o
desenvolvimento da arquitetura da web moderna”.
Em sua dissertação, ele aplica o padrão REST ao protocolo HTTP e
descreve sua experiência. Também se refere a vários elementos de dados
(https://www.ics.uci.edu/~ elding/pubs/dissertation/rest_arch_style.htm#tab
_5_1) que podem ser usados na identi cação e no armazenamento de
recursos em cache.
Logo, se você criar serviços que sejam realmente RESTful, já estará
aplicando as melhores práticas e não precisará alterar muito o VCL. A
recomendação do Capítulo 3 certamente é aplicável aqui!

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.

Estendendo o comportamento do Varnish com VMODs


Como vimos no Capítulo 4, a sintaxe do VCL é extensa e oferece muitas
maneiras de in uenciarmos o comportamento do Varnish. No entanto,
dependendo de seu caso de uso, pode haver algumas limitações – talvez o
VCL não dê suporte a um recurso de que você precise.
Em versões anteriores do Varnish, o uso de código C inline
(https://www.varnish-cache.org/docs/4.1/users-guide/vcl-inline-c.html) era
incentivado. Já que o Varnish compila VCL em código C, era muito fácil
processar código C adicional. Todavia, como você pode imaginar, o menor
dos erros travava totalmente o Varnish.

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.

VMODs que vêm com o Varnish


Se você instalou o Varnish, já tem dois VMODs à sua disposição:
• vmod_std (https://www.varnish-
cache.org/docs/4.1/reference/vmod_std.generated.html) que oferece um
conjunto de funções-padrão
• vmod_directors (https://www.varnish-
cache.org/docs/4.1/reference/vmod_directors.generated.html) que oferece
recursos de balanceamento de carga
Tudo o mais precisa ser instalado separadamente.

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.

O futuro do projeto Varnish


No momento em que você estiver lendo este texto, o Varnish versão 5
(https://www.varnish-cache.org/docs/5.0/whats-new/relnote-5.0.html) já terá
sido lançado, mas isso não signi ca que o livro está desatualizado.
Geralmente a taxa de adoção do público é muito lenta. Várias instalações
do Varnish ainda usam a versão 3.
O Varnish 5 apresenta algumas alterações (https://www.varnish-
cache.org/docs/5.0/whats-new/changes-5.0.html#whatsnew-changes-5-0),
mas nada com o que devamos nos preocupar. A sintaxe do VCL
permanece inalterada.
Atualmente, a equipe do Varnish mudou de um cronograma de
lançamentos baseado em recursos para um cronograma baseado em
períodos. Ou seja, podemos esperar uma nova versão do Varnish a cada
seis meses. O principal recurso novo do Varnish 5 é o suporte
experimental ao HTTP/2 (https://www.varnish-cache.org/docs/5.0/whats-
new/changes-5.0.html#very-experimental-http-2-support). Ele ainda não
está pronto para produção, mas manipula tráfego HTTP/2
(https://http2.github.io/) quando a ag de recurso http2 é ativada.
Há alguns outros recursos e melhorias. Escrevi uma postagem sobre isso –
consulte-a (https://blog.feryn.eu/varnish-5-features/)!
Com os dois lançamentos anuais esperados, será mais fácil para os
usuários verem a direção que o Varnish está tomando. Espero que o
HTTP/2 permaneça sendo o principal ponto de discussão. Aguardo
muitas melhorias na próxima versão no que diz respeito ao suporte ao
HTTP/2.
O futuro do Varnish é brilhante. Mantenha-se atento e que de olho nas
novas versões!

1 N.T.: Dta signi ca “don’t trust anyone” (“não con e em ninguém”).

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

Compre agora e leia

Domine os fundamentos do desenvolvimento de aplicações web


implementando uma aplicação simples a partir do zero, baseada em
banco de dados, usando HTML, JavaScript e outras ferramentas de
código aberto. Por meio de tutoriais que permitem pôr a mão na
massa, este guia prático mostra como criar uma interface de
usuário, implementar um servidor, desenvolver uma comunicação
cliente-servidor e usar um serviço baseado em nuvem para
implantar a aplicação aos desenvolvedores inexperientes de
aplicações web. Todo capítulo inclui problemas práticos, exemplos
completos e modelos mentais do fluxo de trabalho do
desenvolvimento. Este livro, ideal para disciplinas de nível
universitário, ajuda você a dar início ao desenvolvimento de
aplicações web, proporcionando uma base sólida durante o
processo. •Defina um fluxo de trabalho básico com um editor de
texto, um sistema de controle de versões e um navegador web
•Estruture uma interface de usuário com HTML e inclua estilos
usando CSS •Use jQuery e JavaScript para acrescentar
interatividade à sua aplicação •Faça a ligação entre o cliente e o
servidor por meio de AJAX, objetos JavaScript e JSON •Aprenda o
básico da programação do lado do servidor com o Node.js
•Armazene dados fora de sua aplicação usando Redis e MongoDB
•Compartilhe sua aplicação carregando-a na nuvem com o
CloudFoundry •Obtenha dicas básicas sobre como escrever códigos
que facilitem a manutenção, tanto no cliente quanto no servidor.

Compre agora e leia


Padrões para Kubernetes
Ibryam, Bilgin
9788575228159
272 páginas

Compre agora e leia

O modo como os desenvolvedores projetam, desenvolvem e


executam software mudou significativamente com a evolução dos
microsserviços e dos contêineres. Essas arquiteturas modernas
oferecem novas primitivas distribuídas que exigem um conjunto
diferente de práticas, distinto daquele com o qual muitos
desenvolvedores, líderes técnicos e arquitetos estão acostumados.
Este guia apresenta padrões comuns e reutilizáveis, além de
princípios para o design e a implementação de aplicações nativas
de nuvem no Kubernetes. Cada padrão inclui uma descrição do
problema e uma solução específica no Kubernetes. Todos os
padrões acompanham e são demonstrados por exemplos concretos
de código. Este livro é ideal para desenvolvedores e arquitetos que
já tenham familiaridade com os conceitos básicos do Kubernetes, e
que queiram aprender a solucionar desafios comuns no ambiente
nativo de nuvem, usando padrões de projeto de uso comprovado.
Você conhecerá as seguintes classes de padrões: • Padrões
básicos, que incluem princípios e práticas essenciais para
desenvolver aplicações nativas de nuvem com base em contêineres.
• Padrões comportamentais, que exploram conceitos mais
específicos para administrar contêineres e interações com a
plataforma. • Padrões estruturais, que ajudam você a organizar
contêineres em um Pod para tratar casos de uso específicos. •
Padrões de configuração, que oferecem insights sobre como tratar
as configurações das aplicações no Kubernetes. • Padrões
avançados, que incluem assuntos mais complexos, como
operadores e escalabilidade automática (autoscaling).

Compre agora e leia


Candlestick
Debastiani, Carlos Alberto
9788575225943
200 páginas

Compre agora e leia

A análise dos gráficos de Candlestick é uma técnica amplamente


utilizada pelos operadores de bolsas de valores no mundo inteiro.
De origem japonesa, este refinado método avalia o comportamento
do mercado, sendo muito eficaz na previsão de mudanças em
tendências, o que permite desvendar fatores psicológicos por trás
dos gráficos, incrementando a lucratividade dos investimentos.
Candlestick – Um método para ampliar lucros na Bolsa de Valores é
uma obra bem estruturada e totalmente ilustrada. A preocupação do
autor em utilizar uma linguagem clara e acessível a torna leve e de
fácil assimilação, mesmo para leigos. Cada padrão de análise
abordado possui um modelo com sua figura clássica, facilitando a
identificação. Depois das características, das peculiaridades e dos
fatores psicológicos do padrão, é apresentado o gráfico de um caso
real aplicado a uma ação negociada na Bovespa. Este livro possui,
ainda, um índice resumido dos padrões para pesquisa rápida na
utilização cotidiana.

Compre agora e leia


Avaliando Empresas, Investindo em
Ações
Debastiani, Carlos Alberto
9788575225974
224 páginas

Compre agora e leia

Avaliando Empresas, Investindo em Ações é um livro destinado a


investidores que desejam conhecer, em detalhes, os métodos de
análise que integram a linha de trabalho da escola fundamentalista,
trazendo ao leitor, em linguagem clara e acessível, o conhecimento
profundo dos elementos necessários a uma análise criteriosa da
saúde financeira das empresas, envolvendo indicadores de balanço
e de mercado, análise de liquidez e dos riscos pertinentes a fatores
setoriais e conjunturas econômicas nacional e internacional. Por
meio de exemplos práticos e ilustrações, os autores exercitam os
conceitos teóricos abordados, desde os fundamentos básicos da
economia até a formulação de estratégias para investimentos de
longo prazo.

Compre agora e leia


Manual de Análise Técnica
Abe, Marcos
9788575227022
256 páginas

Compre agora e leia

Este livro aborda o tema Investimento em Ações de maneira inédita


e tem o objetivo de ensinar os investidores a lucrarem nas mais
diversas condições do mercado, inclusive em tempos de crise.
Ensinará ao leitor que, para ganhar dinheiro, não importa se o
mercado está em alta ou em baixa, mas sim saber como operar em
cada situação. Com o Manual de Análise Técnica o leitor aprenderá:
- os conceitos clássicos da Análise Técnica de forma diferenciada,
de maneira que assimile não só os princípios, mas que desenvolva
o raciocínio necessário para utilizar os gráficos como meio de
interpretar os movimentos da massa de investidores do mercado; -
identificar oportunidades para lucrar na bolsa de valores, a longo e
curto prazo, até mesmo em mercados baixistas; um sistema de
investimentos completo com estratégias para abrir, conduzir e fechar
operações, de forma que seja possível maximizar lucros e minimizar
prejuízos; - estruturar e proteger operações por meio do
gerenciamento de capital. Destina-se a iniciantes na bolsa de
valores e investidores que ainda não desenvolveram uma
metodologia própria para operar lucrativamente.
Compre agora e leia

Você também pode gostar