Otimização de performance do Nginx

Nginx com configurações padrão já é muito performático, mas para VPS com alto tráfego ou muitas conexões simultâneas, ajustes no número de workers, keepalive, cache de arquivos abertos e parâmetros do kernel Linux podem triplicar o throughput sem upgrade de hardware.

Configurações de workers e conexões

Ajuste o número de workers e o limite de conexões para o hardware disponível:

nginx
# /etc/nginx/nginx.conf

# worker_processes: número de processos worker
# auto = número de CPUs disponíveis (recomendado)
worker_processes auto;

# worker_cpu_affinity: associar workers a CPUs específicas
# Para 4 CPUs: 1000 0100 0010 0001
worker_cpu_affinity auto;

# Limite de descritores de arquivo por worker
# Deve ser >= worker_connections
worker_rlimit_nofile 65536;

events {
    # Máximo de conexões simultâneas por worker
    # Total = worker_processes × worker_connections
    worker_connections 4096;

    # Usar epoll (Linux) — event-driven, mais eficiente que select/poll
    use epoll;

    # Aceitar múltiplas conexões de uma vez (padrão: off)
    multi_accept on;
}

http {
    # Número máximo de requisições por conexão keepalive (cliente)
    keepalive_requests 1000;

    # Timeout de conexão keepalive com o cliente
    keepalive_timeout 65s;

    # Aumentar o limite de descritores de arquivo no sistema:
    # sudo nano /etc/security/limits.conf
    # nginx   soft  nofile  65536
    # nginx   hard  nofile  65536
}

Otimizar buffers e timeouts

Buffers mal configurados causam uso excessivo de memória ou quedas de performance:

nginx
# /etc/nginx/nginx.conf — bloco http {}

# Buffers de proxy (respostas do backend para o Nginx)
proxy_buffers 16 32k;             # 16 buffers de 32k
proxy_buffer_size 32k;            # buffer para o início da resposta (headers)
proxy_busy_buffers_size 64k;

# Timeouts
proxy_connect_timeout 5s;         # tempo para conectar ao backend
proxy_send_timeout 60s;           # tempo para enviar dados ao backend
proxy_read_timeout 60s;           # tempo para receber dados do backend
send_timeout 30s;                  # timeout entre bytes enviados ao cliente

# Buffers de leitura do cliente (body da requisição)
client_body_buffer_size 128k;
client_header_buffer_size 4k;
large_client_header_buffers 4 16k;

# Desabilitar buffer de proxy para respostas em streaming (SSE, WebSocket)
# location /events/ { proxy_buffering off; }

# sendfile: transferir arquivos sem copiar para userspace (muito mais rápido)
sendfile on;

# tcp_nopush: enviar headers e início do arquivo em um pacote TCP
tcp_nopush on;

# tcp_nodelay: desabilitar algoritmo de Nagle para low-latency
tcp_nodelay on;

Open file cache: evitar syscalls de I/O repetidas

Cache de descritores de arquivos abertos reduz syscalls ao servir estáticos:

nginx
# /etc/nginx/nginx.conf — bloco http {}

# open_file_cache: cachear informações de arquivos (inode, permissões)
open_file_cache max=10000 inactive=20s;
open_file_cache_valid 30s;          # revalidar a cada 30s
open_file_cache_min_uses 2;         # cachear arquivos acessados ≥ 2 vezes
open_file_cache_errors on;          # cachear também os erros (404)

# Benefício: em vez de stat(), open() e close() para cada requisição de arquivo,
# o Nginx reutiliza o descritor cacheado — reduz syscalls em 60-80% para estáticos

# Para VPS com muitos arquivos estáticos (imagens, CSS, JS):
# max=50000 para sites com muitos assets diferentes

Tuning do kernel Linux para alta concorrência

Parâmetros do kernel que afetam diretamente a performance do Nginx:

bash
# /etc/sysctl.conf — parâmetros de kernel para VPS de produção
# Aplicar: sudo sysctl -p

# Aumentar limites de conexões simultâneas
net.core.somaxconn = 65536          # tamanho da fila de conexões pendentes
net.core.netdev_max_backlog = 65536 # tamanho da fila de pacotes de entrada

# TCP: reutilizar portas rapidamente após fechamento
net.ipv4.tcp_tw_reuse = 1

# Aumentar range de portas efêmeras
net.ipv4.ip_local_port_range = 1024 65535

# Buffer TCP
net.core.rmem_max = 134217728       # 128 MB read buffer
net.core.wmem_max = 134217728       # 128 MB write buffer
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728

# File descriptors
fs.file-max = 2097152

# Aplicar:
sudo sysctl -p

# Verificar limite atual de file descriptors:
ulimit -n
# Aumentar para o processo Nginx:
sudo systemctl edit nginx
# [Service]
# LimitNOFILE=65536

Benchmark e verificação de performance

Medir a performance antes e depois das otimizações:

bash
# Apache Bench — teste simples de throughput:
ab -n 10000 -c 100 https://seudominio.com.br/

# wrk — benchmark mais avançado com múltiplas threads:
sudo apt install -y wrk
wrk -t4 -c100 -d30s https://seudominio.com.br/

# wrk com script Lua (simular POST com JSON):
cat > post.lua << 'EOF'
wrk.method = "POST"
wrk.body   = '{"teste": "dados"}'
wrk.headers["Content-Type"] = "application/json"
EOF
wrk -t4 -c100 -d30s -s post.lua https://api.seudominio.com.br/api/test

# Métricas a observar:
# Requests/sec: throughput total
# Latency avg/p99: latência média e percentil 99
# Non-2xx responses: erros durante o teste

# Monitorar recursos durante o benchmark:
# CPU: htop (ver uso por core)
# Conexões: ss -s
# Nginx stats: curl http://127.0.0.1:8080/nginx-status

Não quer configurar manualmente?

Implante o VPS em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

worker_processes auto é a resposta correta para 99% dos casos, Nginx detecta o número de CPUs e cria um worker por CPU, distribuindo a carga otimamente. Um worker por CPU aproveita todo o processamento paralelo sem overhead de context switch. Usar mais workers que CPUs não melhora performance.

Sim, especialmente para servir arquivos grandes. Sem sendfile: kernel copia o arquivo para userspace (buffer do Nginx) e depois de volta para o socket. Com sendfile: o kernel transfere diretamente do disco para o socket, sem cópia para userspace, reduz uso de CPU e memória significativamente. Para arquivos pequenos: a diferença é menor.

Depende do tráfego. Cada conexão WebSocket ou keepalive HTTP ocupa uma entrada. Com worker_processes 4 e worker_connections 1024: capacidade total de 4096 conexões simultâneas. Para sites com muitos acessos simultâneos: aumente para 4096 ou 8192. O limite real é o número de file descriptors do sistema (worker_rlimit_nofile).

Algoritmo de Nagle agrupa pequenos pacotes TCP para reduzir overhead de rede, bom para throughput, ruim para latência. tcp_nodelay on desabilita o Nagle: cada pacote é enviado imediatamente, sem esperar acumular dados. Para APIs e aplicações interativas onde latência importa mais que throughput: tcp_nodelay on. Para transferências de arquivos grandes: o Nagle pode ajudar.

Durante o benchmark: veja upstream_response_time nos logs (tempo que o backend levou) vs request_time (tempo total). Se upstream_response_time ≈ request_time: gargalo é o backend. Se request_time >> upstream_response_time: gargalo é o Nginx (improvável) ou a rede. Use htop para ver CPU por processo, se os workers estão todos a 100%: gargalo é CPU do Nginx. Se backend está a 100%: escale o backend.