BLOG | NGINX

Um guia para cache com NGINX e NGINX Plus

NGINX-Parte-de-F5-horiz-preto-tipo-RGB
Miniatura de Faisal Memon
Faisal Memon
Publicado em 23 de julho de 2015

Todos sabemos que o desempenho de aplicativos e sites é um fator crítico para seu sucesso. No entanto, o processo para melhorar o desempenho do seu aplicativo ou site nem sempre é claro. A qualidade do código e a infraestrutura são, obviamente, essenciais, mas em muitos casos você pode fazer grandes melhorias na experiência do usuário final do seu aplicativo concentrando-se em algumas técnicas básicas de entrega de aplicativos. Um exemplo disso é implementar e otimizar o cache na pilha de aplicativos. Esta postagem do blog aborda técnicas que podem ajudar usuários iniciantes e avançados a obter melhor desempenho ao utilizar os recursos de cache de conteúdo incluídos no NGINX e no NGINX Plus.

Visão geral

Um cache de conteúdo fica entre um cliente e um “servidor de origem” e salva cópias de todo o conteúdo que vê. Se um cliente solicitar conteúdo armazenado no cache, ele retornará o conteúdo diretamente, sem entrar em contato com o servidor de origem. Isso melhora o desempenho, pois o cache de conteúdo fica mais próximo do cliente e usa os servidores de aplicativos de forma mais eficiente, pois eles não precisam fazer o trabalho de gerar páginas do zero todas as vezes.

Há potencialmente vários caches entre o navegador da web e o servidor de aplicativos: o cache do navegador do cliente, caches intermediários, redes de distribuição de conteúdo (CDNs) e o balanceador de carga ou proxy reverso localizado na frente dos servidores de aplicativos. O armazenamento em cache, mesmo no nível de proxy reverso/balanceador de carga, pode melhorar muito o desempenho.

Por exemplo, no ano passado assumi a tarefa de ajustar o desempenho de um site que estava carregando lentamente. Uma das primeiras coisas que notei foi que demorava mais de 1 segundo para gerar a página inicial principal. Após alguma depuração, descobri que, como a página estava marcada como não armazenável em cache, ela estava sendo gerada dinamicamente em resposta a cada solicitação. A página em si não mudava com muita frequência e não era personalizada, então isso não era necessário. Como experiência, marquei a página inicial para ser armazenada em cache por 5 segundos pelo balanceador de carga, e só isso resultou em uma melhoria notável. O tempo para o primeiro byte caiu para alguns milissegundos e a página carregou visivelmente mais rápido.

O NGINX é comumente implantado como um proxy reverso ou balanceador de carga em uma pilha de aplicativos e tem um conjunto completo de recursos de cache. A próxima seção discute como configurar o cache básico com o NGINX.

Como configurar e configurar o cache básico

Apenas duas diretivas são necessárias para habilitar o cache básico: proxy_cache_path e proxy_cache . A diretiva proxy_cache_path define o caminho e a configuração do cache, e a diretiva proxy_cache o ativa.

proxy_cache_path /caminho/para/o/cache levels=1:2 keys_zone=meu_cache:10m max_size=10g inativo=60m use_temp_path=off; servidor { # ... localização / { proxy_cache meu_cache; proxy_pass http://meu_upstream; } }

Os parâmetros da diretiva proxy_cache_path definem as seguintes configurações:

  • O diretório do disco local para o cache é chamado /caminho/para/o/cache/ .
  • levels configura uma hierarquia de diretórios de dois níveis em /path/to/cache/ . Ter um grande número de arquivos em um único diretório pode tornar o acesso aos arquivos mais lento, por isso recomendamos uma hierarquia de diretórios de dois níveis para a maioria das implantações. Se o parâmetro levels não estiver incluído, o NGINX colocará todos os arquivos no mesmo diretório.
  • keys_zone configura uma zona de memória compartilhada para armazenar chaves de cache e metadados, como temporizadores de uso. Ter uma cópia das chaves na memória permite que o NGINX determine rapidamente se uma solicitação é um HIT ou um MISS sem precisar ir para o disco, acelerando muito a verificação. Uma zona de 1 MB pode armazenar dados para cerca de 8.000 chaves, então a zona de 10 MB configurada no exemplo pode armazenar dados para cerca de 80.000 chaves.
  • max_size define o limite superior do tamanho do cache (para 10 gigabytes neste exemplo). É opcional; não especificar um valor permite que o cache cresça e use todo o espaço em disco disponível. Quando o tamanho do cache atinge o limite, um processo chamado gerenciador de cache remove os arquivos que foram usados menos recentemente para trazer o tamanho do cache de volta abaixo do limite.
  • inativo especifica por quanto tempo um item pode permanecer no cache sem ser acessado. Neste exemplo, um arquivo que não foi solicitado por 60 minutos é excluído automaticamente do cache pelo processo do gerenciador de cache, independentemente de ter expirado ou não. O valor padrão é 10 minutos ( 10m ). Conteúdo inativo é diferente de conteúdo expirado. O NGINX não exclui automaticamente o conteúdo que expirou, conforme definido por um cabeçalho de controle de cache ( Cache-Control:max-age=120, por exemplo). Conteúdo expirado (obsoleto) é excluído somente quando não é acessado pelo tempo especificado por inactive . Quando o conteúdo expirado é acessado, o NGINX o atualiza a partir do servidor de origem e zera o cronômetro inativo .
  • O NGINX primeiro grava os arquivos destinados ao cache em uma área de armazenamento temporário, e a diretiva use_temp_path=off instrui o NGINX a gravá-los nos mesmos diretórios onde serão armazenados em cache. Recomendamos que você defina esse parâmetro como desativado para evitar cópias desnecessárias de dados entre sistemas de arquivos. use_temp_path foi introduzido no NGINX versão 1.7.10 e no NGINX Plus R6 .

E, finalmente, a diretiva proxy_cache ativa o cache de todo o conteúdo que corresponde à URL do bloco de localização pai (no exemplo, / ). Você também pode incluir a diretiva proxy_cache em um bloco de servidor ; ela se aplica a todos os blocos de localização do servidor que não têm sua própria diretiva proxy_cache .

Entregando conteúdo em cache quando a origem está inativa

Um recurso poderoso do cache de conteúdo do NGINX é que ele pode ser configurado para entregar conteúdo obsoleto de seu cache quando não puder obter conteúdo novo dos servidores de origem. Isso pode acontecer se todos os servidores de origem de um recurso em cache estiverem inativos ou temporariamente ocupados. Em vez de retransmitir o erro ao cliente, o NGINX entrega a versão obsoleta do arquivo do seu cache. Isso fornece um nível extra de tolerância a falhas para os servidores que o NGINX está usando como proxy e garante o tempo de atividade no caso de falhas do servidor ou picos de tráfego. Para habilitar essa funcionalidade, inclua a diretiva proxy_cache_use_stale :

localização / { # ... proxy_cache_use_stale erro tempo limite http_500 http_502 http_503 http_504; }

Com esta configuração de exemplo, se o NGINX receber um erro , tempo limite ou qualquer um dos erros 5xx especificados do servidor de origem e tiver uma versão obsoleta do arquivo solicitado em seu cache, ele entregará o arquivo obsoleto em vez de retransmitir o erro ao cliente.

Ajustando o cache e melhorando o desempenho

O NGINX tem uma variedade de configurações opcionais para ajustar o desempenho do cache. Aqui está um exemplo que ativa alguns deles:

proxy_cache_path /caminho/para/o/cache levels=1:2 keys_zone=meu_cache:10m tamanho_máx.=10g inativo=60m use_temp_path=off; servidor { # ... localização / { proxy_cache meu_cache; proxy_cache_revalidate ativado; proxy_cache_min_uses 3; proxy_cache_use_stale erro tempo limite atualizando http_500 http_502 http_503 http_504; proxy_cache_background_update ativado; proxy_cache_lock ativado; proxy_pass http://meu_upstream; } }

Essas diretivas configuram o seguinte comportamento:

  • proxy_cache_revalidate instrui o NGINX a usar solicitações GET condicionais ao atualizar o conteúdo dos servidores de origem. Se um cliente solicitar um item armazenado em cache, mas expirado, conforme definido pelos cabeçalhos de controle de cache, o NGINX incluirá o campo If-Modified-Since no cabeçalho da solicitação GET enviada ao servidor de origem. Isso economiza largura de banda, porque o servidor envia o item completo somente se ele tiver sido modificado desde o momento registrado no cabeçalho Last-Modified anexado ao arquivo quando o NGINX o armazenou em cache originalmente.
  • proxy_cache_min_uses define o número de vezes que um item deve ser solicitado pelos clientes antes que o NGINX o armazene em cache. Isso é útil se o cache estiver constantemente enchendo, pois garante que apenas os itens acessados com mais frequência sejam adicionados ao cache. Por padrão, proxy_cache_min_uses é definido como 1.
  • O parâmetro de atualização da diretiva proxy_cache_use_stale , combinado com a ativação da diretiva proxy_cache_background_update , instrui o NGINX a entregar conteúdo obsoleto quando os clientes solicitam um item expirado ou em processo de atualização do servidor de origem. Todas as atualizações serão feitas em segundo plano. O arquivo obsoleto é retornado para todas as solicitações até que o arquivo atualizado seja totalmente baixado.
  • Com proxy_cache_lock habilitado, se vários clientes solicitarem um arquivo que não esteja no cache (um MISS ), somente a primeira dessas solicitações será permitida no servidor de origem. As solicitações restantes aguardam que a solicitação seja atendida e então extraem o arquivo do cache. Sem proxy_cache_lock habilitado, todas as solicitações que resultam em perdas de cache vão diretamente para o servidor de origem.

Dividindo o cache em vários discos rígidos

Se você tiver vários discos rígidos, o NGINX pode ser usado para dividir o cache entre eles. Aqui está um exemplo que divide os clientes uniformemente em dois discos rígidos com base no URI da solicitação:

proxy_cache_path /caminho/para/hdd1 níveis=1:2 keys_zone=meu_cache_hdd1:10m max_size=10g inativo=60m use_temp_path=off;
proxy_cache_path /caminho/para/hdd2 níveis=1:2 keys_zone=meu_cache_hdd2:10m
max_size=10g inativo=60m use_temp_path=off;

split_clients $request_uri $meu_cache {
50% “meu_cache_hdd1”;
50% “meu_cache_hdd2”;
}

servidor {
# ...
localização / {
proxy_cache $meu_cache;
proxy_pass http://meu_upstream;
}
}

As duas diretivas proxy_cache_path definem dois caches ( my_cache_hdd1 e my_cache_hdd2 ) em dois discos rígidos diferentes. O bloco de configuração split_clients especifica que os resultados de metade das solicitações ( 50% ) são armazenados em cache em my_cache_hdd1 e a outra metade em my_cache_hdd2 . O hash baseado na variável $request_uri (o URI da solicitação) determina qual cache é usado para cada solicitação, o resultado é que as solicitações para um determinado URI são sempre armazenadas em cache no mesmo cache.

Observe que essa abordagem não substitui uma configuração de disco rígido RAID. Se houver uma falha no disco rígido, isso pode levar a um comportamento imprevisível no sistema, incluindo usuários vendo códigos de resposta 500 para solicitações direcionadas ao disco rígido com falha. Uma configuração adequada de disco rígido RAID pode lidar com falhas no disco rígido.

Perguntas Frequentes (FAQ)

Esta seção responde a algumas perguntas frequentes sobre o cache de conteúdo do NGINX.

O cache NGINX pode ser instrumentado?

Sim, com a diretiva add_header :

adicionar_cabeçalho X-Cache-Status $upstream_cache_status;

Este exemplo adiciona um cabeçalho HTTP X-Cache-Status em respostas aos clientes. A seguir estão os valores possíveis para $upstream_cache_status :

  • MISS – A resposta não foi encontrada no cache e, portanto, foi obtida de um servidor de origem. A resposta pode então ter sido armazenada em cache.
  • BYPASS – A resposta foi obtida do servidor de origem em vez de ser servida do cache porque a solicitação correspondia a uma diretiva proxy_cache_bypass (veja Posso fazer um furo no meu cache? abaixo). A resposta pode então ter sido armazenada em cache.
  • EXPIRADO – A entrada no cache expirou. A resposta contém conteúdo novo do servidor de origem.
  • STALE – O conteúdo está obsoleto porque o servidor de origem não está respondendo corretamente e proxy_cache_use_stale foi configurado.
  • ATUALIZAÇÃO – O conteúdo está desatualizado porque a entrada está sendo atualizada em resposta a uma solicitação anterior, e a atualização proxy_cache_use_stale está configurada.
  • REVALIDADO – A diretiva proxy_cache_revalidate foi habilitada e o NGINX verificou se o conteúdo em cache atual ainda era válido ( If-Modified-Since ou If-None-Match ).
  • HIT – A resposta contém conteúdo válido e novo diretamente do cache.

Como o NGINX determina se algo deve ou não ser armazenado em cache?

O NGINX armazena em cache uma resposta somente se o servidor de origem incluir o cabeçalho Expires com uma data e hora no futuro ou o cabeçalho Cache-Control com a diretiva max-age definida como um valor diferente de zero.

Por padrão, o NGINX respeita outras diretivas no cabeçalho Cache-Control : ele não armazena em cache respostas quando o cabeçalho inclui a diretiva Private , No-Cache ou No-Store . Ele também não armazena em cache respostas com o cabeçalho Set-Cookie . Além disso, ele armazena em cache apenas respostas a solicitações GET e HEAD . Você pode substituir esses padrões conforme descrito nas respostas abaixo.

O NGINX não armazena em cache as respostas se proxy_buffering estiver definido como off . Está ativado por padrão.

Os cabeçalhos de controle de cache podem ser ignorados?

Sim, com a diretiva proxy_ignore_headers . Por exemplo, com esta configuração:

localização /imagens/ { proxy_cache meu_cache; proxy_ignore_headers Cache-Control; proxy_cache_valid qualquer 30m; # ... }

O NGINX ignora o cabeçalho Cache-Control para tudo em /images/ . A diretiva proxy_cache_valid impõe uma expiração para os dados armazenados em cache e é necessária ao ignorar cabeçalhos Cache-Control . O NGINX não armazena em cache arquivos que não tenham expiração.

O NGINX pode armazenar em cache o conteúdo com um Set-Cookie no cabeçalho?

Sim, com a diretiva proxy_ignore_headers , conforme discutido na resposta anterior.

O NGINX pode armazenar em cache solicitações POST ?

Sim, com a diretiva proxy_cache_methods :

proxy_cache_methods OBTER POSTAGEM DE CABEÇA;

Este exemplo habilita o armazenamento em cache de solicitações POST .

O NGINX pode armazenar em cache conteúdo dinâmico?

Sim, desde que o cabeçalho Cache-Control permita isso. Armazenar em cache conteúdo dinâmico, mesmo por um curto período de tempo, pode reduzir a carga nos servidores de origem e bancos de dados, o que melhora o tempo até o primeiro byte, pois a página não precisa ser regenerada para cada solicitação.

Posso fazer um furo no meu cache?

Sim, com a diretiva proxy_cache_bypass :

localização / { proxy_cache_bypass $cookie_nocache $arg_nocache; # ... }

A diretiva define os tipos de solicitação para os quais o NGINX solicita conteúdo do servidor de origem imediatamente, em vez de tentar encontrá-lo no cache primeiro. Isso às vezes é chamado de “abrir um buraco” no cache. Neste exemplo, o NGINX faz isso para solicitações com um cookie ou argumento nocache , por exemplo http://www.example.com/?nocache=true . O NGINX ainda pode armazenar em cache a resposta resultante para solicitações futuras que não sejam ignoradas.

Qual chave de cache o NGINX usa?

O formato padrão das chaves geradas pelo NGINX é semelhante a um hash MD5 das seguintes variáveis NGINX : $scheme$proxy_host$request_uri ; o algoritmo real usado é um pouco mais complicado.

proxy_cache_path /caminho/para/o/cache levels=1:2 keys_zone=meu_cache:10m max_size=10g inativo=60m use_temp_path=off;

servidor {
# ...
localização / {
proxy_cache meu_cache;
proxy_pass http://meu_upstream;
}
}

Para esta configuração de exemplo, a chave de cache para http://www.example.org/my_image.jpg é calculada como md5(“http://my_upstream:80/my_image.jpg”) .

Observe que a variável $proxy_host é usada no valor com hash em vez do nome real do host ( www.example.com ). $proxy_host é definido como o nome e a porta do servidor proxy, conforme especificado na diretiva proxy_pass .

Para alterar as variáveis (ou outros termos) usadas como base para a chave, use a diretiva proxy_cache_key (veja também a pergunta a seguir).

Posso usar um cookie como parte da minha chave de cache?

Sim, a chave de cache pode ser configurada para ser qualquer valor arbitrário, por exemplo:

chave_cache_proxy $host_proxy$uri_de_solicitação$id_de_cookie_jession;

Este exemplo incorpora o valor do cookie JSESSIONID na chave de cache. Itens com o mesmo URI, mas valores JSESSIONID diferentes, são armazenados em cache separadamente como itens exclusivos.

O NGINX usa o cabeçalho ETag ?

No NGINX 1.7.3 e no NGINX Plus R5 e posteriores, o cabeçalho ETag é totalmente suportado junto com If-None-Match .

Como o NGINX lida com solicitações de intervalo de bytes?

Se o arquivo estiver atualizado no cache, o NGINX atenderá a uma solicitação de intervalo de bytes e fornecerá apenas os bytes especificados do item ao cliente. Se o arquivo não estiver armazenado em cache ou se estiver desatualizado, o NGINX baixa o arquivo inteiro do servidor de origem. Se a solicitação for para um intervalo de bytes único, o NGINX enviará esse intervalo ao cliente assim que ele for encontrado no fluxo de download. Se a solicitação especificar vários intervalos de bytes no mesmo arquivo, o NGINX entregará o arquivo inteiro ao cliente quando o download for concluído.

Após a conclusão do download, o NGINX move todo o recurso para o cache para que todas as solicitações futuras de intervalo de bytes, seja para um único intervalo ou vários intervalos, sejam atendidas imediatamente no cache.

Observe que o servidor upstream deve oferecer suporte a solicitações de intervalo de bytes para que o NGINX atenda às solicitações de intervalo de bytes para esse servidor upstream .

O NGINX oferece suporte à limpeza de cache?

O NGINX Plus suporta limpeza seletiva de arquivos em cache. Isso é útil se um arquivo foi atualizado no servidor de origem, mas ainda é válido no cache do NGINX Plus (o Cache-Control:max-age ainda é válido e o tempo limite definido pelo parâmetro inactive para a diretiva proxy_cache_path não expirou). Com o recurso de limpeza de cache do NGINX Plus, esse arquivo pode ser facilmente excluído. Para mais detalhes, consulte Limpando conteúdo do cache .

Como o NGINX manipula o cabeçalho Pragma ?

O cabeçalho Pragma:no-cache é adicionado pelos clientes para ignorar todos os caches intermediários e ir direto para o servidor de origem para obter o conteúdo solicitado. O NGINX não respeita o cabeçalho Pragma por padrão, mas você pode configurar o recurso com a seguinte diretiva proxy_cache_bypass :

localização /imagens/ { proxy_cache meu_cache; proxy_cache_bypass $http_pragma; # ... }

O NGINX oferece suporte às extensões stale-while-revalidate e stale-if-error para o cabeçalho Cache-Control ?

Sim, no NGINX Plus R12 e NGINX 1.11.10 e posteriores. O que essas extensões fazem:

  • A extensão stale-while-revalidate do cabeçalho HTTP Cache-Control permite usar uma resposta armazenada em cache obsoleta se ela estiver sendo atualizada.
  • A extensão stale-if-error do cabeçalho HTTP Cache-Control permite usar uma resposta armazenada em cache obsoleta em caso de erro.

Esses cabeçalhos têm prioridade menor que a diretiva proxy_cache_use_stale descrita acima.

O NGINX suporta o cabeçalho Vary ?

Sim, no NGINX Plus R5 e NGINX 1.7.7 e posteriores. Aqui está uma boa visão geral do cabeçalho Vary .

Leitura adicional

Há muitas outras maneiras de personalizar e ajustar o cache do NGINX. Para aprender ainda mais sobre cache com NGINX, dê uma olhada nos seguintes recursos:


"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."