Acelere o Nginx: Dicas Essenciais de Buffers, Compressão e Cache

Desbloqueie o desempenho máximo do Nginx com este guia essencial sobre otimização de buffers, compressão Gzip e estratégias inteligentes de cache. Aprenda a configurar buffers de cliente e proxy para manipulação eficiente de dados, implementar compressão de conteúdo robusta para reduzir largura de banda e aproveitar o cache do navegador e do proxy Nginx para tempos de resposta ultrarrápidos. Repleto de exemplos práticos de configuração do Nginx e melhores práticas, este artigo fornece insights acionáveis para aumentar significativamente a velocidade e eficiência do seu servidor web.

Acelere o Nginx: Dicas Essenciais de Buffers, Compressão e Cache

O Nginx é rápido por padrão, mas as configurações padrão são intencionalmente conservadoras. Elas funcionam para um site pequeno, um servidor de teste ou um proxy reverso com tráfego modesto. Nem sempre são a melhor opção quando você começa a lidar com cookies grandes, upstreams lentos, respostas de API grandes ou ativos estáticos baixados milhares de vezes por hora.

O ajuste útil geralmente se resume a três áreas: buffers, compressão e cache. Os buffers decidem se o Nginx pode manter os dados de solicitação e resposta na memória ou precisa gravá-los em arquivos temporários. A compressão decide quantos dados baseados em texto você envia pela rede. O cache decide se o Nginx e o navegador podem evitar fazer o mesmo trabalho novamente. Nenhuma dessas configurações é mágica. Uma regra de cache ruim pode vazar conteúdo privado, e buffers superdimensionados podem desperdiçar memória. O objetivo é ajustar deliberadamente, testar com seu padrão de tráfego real e manter a configuração legível o suficiente para que a próxima pessoa possa raciocinar sobre ela.

Otimizando Buffers do Nginx para Manipulação Eficiente de Dados

O Nginx usa vários buffers para armazenar temporariamente dados durante o processamento de solicitações e respostas. Dimensionar corretamente esses buffers é crucial para o desempenho. Buffers dimensionados incorretamente podem levar ao consumo excessivo de memória ou a gravações frequentes em disco (spooling), ambos degradando o desempenho. Vamos examinar os buffers relacionados ao cliente e os buffers de proxy/FastCGI.

Buffers Relacionados ao Cliente

Esses buffers gerenciam os dados que vêm do cliente para o Nginx.

  • client_body_buffer_size: Esta diretiva define o tamanho do buffer para ler o corpo da solicitação do cliente. Se um corpo de solicitação exceder esse tamanho, ele será gravado em um arquivo temporário em disco. Embora isso evite o esgotamento da memória para uploads grandes, gravações frequentes em disco podem diminuir o desempenho.

    • Dica: Para aplicações web típicas que não lidam com uploads de arquivos muito grandes via solicitações POST, 8k ou 16k geralmente é suficiente. Aumente se você lidar com formulários maiores ou pequenos uploads de arquivos diretamente via Nginx.
    http {
        client_body_buffer_size 16k;
        # ...
    }
    
  • client_header_buffer_size: Define o tamanho do buffer para ler o cabeçalho da solicitação do cliente. Um único buffer é alocado para cada conexão.

    • Dica: 1k é o padrão e geralmente suficiente para a maioria dos cabeçalhos. Aumente apenas se encontrar erros de "cabeçalho do cliente muito grande", geralmente devido a muitos cookies ou cabeçalhos de autenticação complexos.
    http {
        client_header_buffer_size 1k;
        # ...
    }
    
  • large_client_header_buffers: Esta diretiva define o número máximo e o tamanho dos buffers usados para ler cabeçalhos de solicitação grandes do cliente. Se o cabeçalho exceder client_header_buffer_size, o Nginx tenta alocar buffers usando esta diretiva.

    • Dica: 4 8k (4 buffers de 8KB cada) é uma configuração comum. Ajuste se você vir consistentemente erros de cabeçalho após aumentar client_header_buffer_size.
    http {
        large_client_header_buffers 4 8k;
        # ...
    }
    

Buffers de Proxy e FastCGI

Esses buffers gerenciam dados quando o Nginx atua como um proxy reverso ou está se comunicando com um backend FastCGI (como PHP-FPM).

Quando o Nginx faz proxy de solicitações, ele recebe a resposta do servidor backend em partes e as armazena em buffer antes de enviá-las ao cliente. Isso permite que o Nginx lide com respostas lentas do backend sem bloquear a conexão do cliente.

  • proxy_buffer_size: O tamanho do buffer para a primeira parte da resposta recebida do servidor proxy. Isso geralmente contém o cabeçalho da resposta.

  • proxy_buffers: Define o número e o tamanho dos buffers usados para ler a resposta do servidor proxy.

  • proxy_busy_buffers_size: Define o tamanho máximo dos buffers que podem estar ativos (ocupados) a qualquer momento, seja enviando dados para o cliente ou lendo do backend. Isso ajuda a evitar que o Nginx consuma muita memória retendo buffers por muito tempo.

    • Exemplo para Proxy Pass: Para uma aplicação web típica, proxy_buffer_size pode corresponder ao tamanho esperado do cabeçalho, e proxy_buffers pode ser definido para lidar com tamanhos médios de conteúdo sem gravar em disco.
    http {
        proxy_buffer_size          128k;
        proxy_buffers              4 256k; # 4 buffers, cada um com 256KB
        proxy_busy_buffers_size    256k;
        # ...
    }
    
  • fastcgi_buffer_size, fastcgi_buffers, fastcgi_busy_buffers_size: Essas diretivas funcionam de forma idêntica às suas contrapartes proxy_, mas se aplicam especificamente a respostas de servidores FastCGI.

    • Exemplo para FastCGI: Lógica semelhante se aplica aqui, adapte aos tamanhos de resposta da sua aplicação PHP/FastCGI.
    http {
        fastcgi_buffer_size        128k;
        fastcgi_buffers            4 256k;
        fastcgi_busy_buffers_size  256k;
        # ...
    }
    

Aviso: Definir buffers muito grandes consumirá mais RAM por conexão, o que pode esgotar rapidamente a memória em servidores ocupados. Definir buffers muito pequenos fará com que o Nginx grave arquivos temporários em disco, levando a sobrecarga de E/S. Monitore a memória do seu servidor e a E/S de disco para encontrar o equilíbrio ideal.

Habilitando Compressão Eficaz com Gzip

A compressão de conteúdo, principalmente usando Gzip, pode reduzir significativamente o tamanho dos dados transmitidos, levando a carregamentos de página mais rápidos e menor consumo de largura de banda. O módulo gzip do Nginx é altamente configurável.

Diretivas Essenciais do Gzip

Adicione estas diretivas dentro do seu bloco http ou de um bloco server ou location específico.

  • gzip on;: Ativa a compressão Gzip.

  • gzip_types: Especifica os tipos MIME que devem ser compactados. Apenas certos tipos baseados em texto se beneficiam significativamente da compressão.

    • Melhores Práticas: Inclua tipos web comuns, mas evite compactar imagens (image/*), vídeos (video/*) e arquivos já compactados (.zip, .rar, .gz), pois isso desperdiça ciclos de CPU sem ganho.
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
    
  • gzip_proxied: Habilita a compressão para solicitações proxy com base nas condições de resposta e solicitação. É útil principalmente quando o Nginx está na frente de um servidor de aplicação ou outro proxy.

    • any: compacta respostas proxy quando elas se qualificam.
    • no-cache, no-store, private, expired, auth: compacta apenas quando a resposta ou solicitação corresponde a essas condições. Esses tokens não são sinalizadores "não compactar"; são condições que permitem a compressão para respostas proxy.
    gzip_proxied any;
    
  • gzip_min_length: Define o comprimento mínimo de um corpo de resposta que o Nginx compactará. Arquivos pequenos não se beneficiam muito da compressão e podem até se tornar maiores devido à sobrecarga de compressão.

    • Dica: Um valor como 1000 bytes (1KB) ou 256 bytes é um bom ponto de partida.
    gzip_min_length 1000;
    
  • gzip_comp_level: Define o nível de compressão (1-9). Níveis mais altos oferecem melhor compressão, mas consomem mais recursos de CPU. Níveis mais baixos são mais rápidos, mas compactam menos efetivamente.

    • Dica: 4-6 é um bom equilíbrio entre taxa de compressão e uso de CPU para a maioria dos servidores.
    gzip_comp_level 5;
    
  • gzip_vary on;: Diz aos proxies para armazenar em cache versões compactadas e descompactadas de um arquivo, dependendo do cabeçalho Accept-Encoding enviado pelo cliente. Isso é crucial para cache e entrega adequados.

    gzip_vary on;
    
  • gzip_disable: Desabilita a compressão para certos navegadores ou agentes de usuário que podem ter problemas com Gzip.

    gzip_disable "MSIE [1-6]\."; # Exemplo: desabilitar para Internet Explorer antigo
    

Considerações: Embora o Gzip seja altamente benéfico, a compressão consome ciclos de CPU. Para arquivos estáticos servidos diretamente do disco (por exemplo, arquivos .gz pré-compactados), o Nginx pode servi-los diretamente sem recompactá-los, o que é ainda mais eficiente. Para conteúdo dinâmico, o Gzip geralmente é um ganho líquido.

Implementando Estratégias Inteligentes de Cache

O cache é indiscutivelmente a maneira mais eficaz de melhorar o desempenho do servidor web, reduzindo a necessidade de regenerar ou buscar novamente o conteúdo. O Nginx suporta cache tanto no lado do navegador (lado do cliente) quanto no lado do servidor (proxy).

Cache do Navegador (Cabeçalhos HTTP)

O cache do navegador depende de cabeçalhos HTTP para instruir os navegadores do cliente sobre por quanto tempo armazenar ativos estáticos. Isso evita downloads repetidos de recursos imutáveis, como imagens, CSS e arquivos JavaScript.

  • expires: Uma diretiva simples para definir os cabeçalhos Expires e Cache-Control: max-age.

    location ~* \.(jpg|jpeg|gif|png|webp|ico|css|js|woff|woff2|ttf|otf|eot)$ {
        expires 365d; # Cache por um ano
        add_header Cache-Control "public, no-transform";
        # Opcional: Desabilitar logs para arquivos estáticos
        access_log off;
        log_not_found off;
    }
    
  • add_header Cache-Control: Fornece controle mais granular sobre as políticas de cache. Valores comuns incluem:

    • public: Armazenável em cache por qualquer cache (navegador, proxy).
    • private: Armazenável em cache apenas pelo cache privado do cliente (por exemplo, navegador).
    • no-cache: Deve revalidar com o servidor antes do uso, mas pode armazenar uma cópia.
    • no-store: Não armazenar em cache.
    • max-age=<segundos>: Especifica por quanto tempo um recurso é considerado novo.
  • Solicitações Condicionais (Etag e If-Modified-Since): O Nginx lida automaticamente com os cabeçalhos Etag e Last-Modified para arquivos estáticos, permitindo que os navegadores enviem solicitações condicionais (If-None-Match ou If-Modified-Since). Se o conteúdo não mudou, o Nginx responde com um 304 Not Modified, economizando largura de banda.

Cache de Proxy do Nginx

O Nginx pode atuar como um poderoso proxy reverso de cache. Quando ativado, o Nginx armazena cópias das respostas dos servidores backend e as serve diretamente aos clientes, reduzindo significativamente a carga no seu backend.

1. Defina uma Zona de Cache

Isso precisa ser feito no bloco http. proxy_cache_path define o diretório para o cache, parâmetros da zona de memória e outras configurações.

http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m inactive=60m max_size=1g;
    # levels=1:2: Cria uma hierarquia de diretórios de dois níveis para arquivos de cache (por exemplo, /var/cache/nginx/c/29/...). Ajuda a distribuir arquivos.
    # keys_zone=my_cache:10m: Define uma zona de memória compartilhada chamada 'my_cache' de 10MB para armazenar chaves de cache e metadados. Isso é crucial para pesquisas rápidas.
    # inactive=60m: Itens em cache que não foram acessados por 60 minutos serão removidos do disco.
    # max_size=1g: Define o tamanho máximo do cache em disco. Quando excedido, o Nginx remove os dados menos recentemente usados.
    # ...
}

2. Habilite o Cache para um Local

Dentro de um bloco server ou location, você habilita o cache e define seu comportamento.

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend_upstream; # Ou http://127.0.0.1:8000;
        proxy_cache my_cache; # Use a zona de cache definida acima
        proxy_cache_valid 200 302 10m; # Armazena em cache respostas bem-sucedidas (200, 302) por 10 minutos
        proxy_cache_valid 404 1m;      # Armazena em cache respostas 404 por 1 minuto
        proxy_cache_revalidate on;     # Use cabeçalhos If-Modified-Since e If-None-Match para revalidação
        proxy_cache_min_uses 1;       # Armazena em cache apenas se um item foi solicitado pelo menos uma vez
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
                                       # Sirva conteúdo obsoleto se o backend estiver inativo ou atualizando

        # Adicione um cabeçalho para ver se a resposta foi armazenada em cache
        add_header X-Cache-Status $upstream_cache_status;

        # Opcional: Ignorar o cache para condições específicas
        # proxy_cache_bypass $http_pragma $http_authorization;
        # proxy_no_cache $http_pragma $http_authorization;
    }
}

Diretivas Importantes de Cache

  • proxy_cache_valid: Define regras de cache com base em códigos de status HTTP e duração. Você pode especificar várias regras.

  • proxy_cache_revalidate on;: Permite que o Nginx use cabeçalhos If-Modified-Since e If-None-Match ao verificar se o conteúdo em cache ainda é novo. Isso é mais eficiente do que simplesmente deixar o cache expirar.

  • proxy_cache_use_stale: Uma diretiva poderosa que diz ao Nginx para servir conteúdo obsoleto (expirado) do cache se o backend estiver indisponível ou lento. Isso melhora muito a experiência do usuário durante problemas no backend.

  • proxy_cache_bypass / proxy_no_cache: Use-os para definir condições sob as quais o cache deve ser ignorado (por exemplo, para solicitações autenticadas ou parâmetros de consulta específicos).

    # Exemplo para não armazenar em cache solicitações com parâmetros de consulta ou cookies específicos
    # if ($request_uri ~* "(\?|&)nocache") { set $no_cache 1; }
    # if ($http_cookie ~* "SESSIONID") { set $no_cache 1; }
    # proxy_cache_bypass $no_cache;
    # proxy_no_cache $no_cache;
    

Limpeza de Cache

Para limpar manualmente o cache do Nginx, você pode simplesmente excluir os arquivos no diretório proxy_cache_path. Para invalidação mais controlada, considere usar um módulo como ngx_cache_purge ou configurar um location específico para lidar com solicitações de invalidação de cache.

Aviso: O cache de proxy mal configurado pode levar os usuários a ver conteúdo obsoleto. Sempre teste sua estratégia de cache completamente em um ambiente de staging antes de implantar em produção. Certifique-se de que o conteúdo dinâmico que muda com frequência ou é específico do usuário não seja armazenado em cache agressivamente.

Um Plano de Implantação Prático

A maneira mais segura de ajustar o Nginx é mudar uma camada de cada vez. Comece com cabeçalhos e ativos estáticos, porque o risco é baixo e o benefício é fácil de ver. Adicione longos tempos de vida de cache do navegador apenas para arquivos versionados, como /app.8f3a2c.js ou /styles.2025-11-02.css. Se os nomes dos seus ativos não mudam quando o arquivo muda, não os armazene em cache por um ano. Use um valor expires mais curto ou corrija o pipeline de build primeiro.

Em seguida, habilite o Gzip para formatos de texto e confirme que funciona:

curl -I -H 'Accept-Encoding: gzip' https://example.com/app.js

Você deve ver Content-Encoding: gzip para respostas compressíveis e Vary: Accept-Encoding. Se imagens ou arquivos ZIP aparecerem como compactados, aperte gzip_types; esses formatos já estão compactados e geralmente desperdiçarão CPU.

Depois disso, observe o buffer. Verifique o log de erros em busca de mensagens sobre respostas upstream sendo armazenadas em buffer em arquivos temporários. Essas mensagens não são automaticamente um desastre, mas indicam que o Nginx está gravando dados de resposta em disco. Se isso acontecer durante carregamentos normais de página ou respostas de API, seus buffers de proxy podem ser muito pequenos para a carga de trabalho. Se acontecer apenas para grandes exportações ou downloads, aceitar o spooling em disco pode ser melhor do que alocar buffers grandes para cada caminho de solicitação.

O cache de proxy deve vir por último. Ele tem o maior potencial de ganho e o modo de falha mais fácil. Comece com conteúdo que é claramente seguro: páginas de documentação pública, páginas de catálogo de produtos anônimas, respostas de transformação de imagem, metadados de pacotes ou respostas de API que são idênticas para cada visitante. Evite armazenar em cache qualquer coisa vinculada a um cookie de sessão, cabeçalho Authorization, carrinho de compras, painel do usuário, página de administração ou recomendação personalizada, a menos que sua aplicação tenha sido projetada explicitamente para isso.

Aqui está um padrão de bypass de cache mais cauteloso do que os exemplos curtos que você vê frequentemente:

map $http_authorization $skip_cache_auth {
    default 1;
    ""      0;
}

map $http_cookie $skip_cache_cookie {
    default 0;
    ~*"(session|sid|auth|token)" 1;
}

server {
    location / {
        proxy_pass http://backend_upstream;
        proxy_cache my_cache;
        proxy_cache_valid 200 10m;
        proxy_cache_bypass $skip_cache_auth $skip_cache_cookie;
        proxy_no_cache $skip_cache_auth $skip_cache_cookie;
        add_header X-Cache-Status $upstream_cache_status always;
    }
}

Isso ainda precisa corresponder à sua aplicação, mas torna a ideia importante clara: solicitações autenticadas e com aparência de sessão não devem entrar silenciosamente em um cache compartilhado.

O Que Observar Após a Mudança

Não julgue o ajuste do Nginx apenas por um único benchmark. Observe o servidor por alguns ciclos normais de tráfego. Sinais úteis incluem gravações em disco em /var/lib/nginx ou /var/cache/nginx, tempo de resposta upstream, taxa de acerto de cache, uso de CPU após habilitar a compressão, erros 499/502/504 e uso de memória por worker. Se a CPU aumentar após o Gzip, mas a largura de banda mal mudar, diminua gzip_comp_level ou restrinja os tipos MIME. Se a taxa de acerto de cache for baixa, o cache pode estar sendo ignorado por cookies, strings de consulta ou cabeçalhos de resposta da aplicação.

Teste também o comportamento de falha. Pare ou desacelere o upstream em staging e confirme que proxy_cache_use_stale faz o que você espera. Uma página pública obsoleta durante uma breve interrupção do backend pode ser aceitável. Um saldo de conta, fatura ou página de administração obsoletos não são.

Notas Finais

Um bom trabalho de desempenho do Nginx é principalmente uma arrumação cuidadosa. Use buffers grandes o suficiente para evitar E/S de disco desnecessária, mas não tão grandes que cada worker ocupado se torne caro. Comprima texto, não ativos já compactados. Armazene em cache respostas públicas e repetíveis primeiro, e faça o conteúdo privado optar por sair claramente. Em seguida, continue medindo, porque a configuração certa para um pequeno aplicativo PHP, um site de documentação estática e um gateway de API ocupado não será idêntica.