Configurarei o Keepalive do Upstream do NGINX de forma a que o proxy reverso estabeleça menos ligações, ofereça menores latências e absorva de forma fiável os picos de carga. Para tal, ajustarei Dimensões da piscina, limites de tempo e cabeçalhos de forma específica, para que as ligações sejam reutilizadas e o percurso de dados se mantenha otimizado.
Pontos centrais
- HTTP/1.1 forçar e limpar os cabeçalhos de ligação
- keepalive dimensionar corretamente por trabalhador
- Intervalos adaptar aos valores do backend
- Pedidos/Ligação reduzir e reciclar
- Monitorização para a velocidade de ligação e a latência
Por que é que o Upstream Keepalive reduz drasticamente o esforço de estabelecimento de ligações
Sem reutilização, o NGINX abre uma nova ligação ao backend por cada pedido, o que implica handshakes adicionais, mais ciclos de CPU e recursos adicionais do kernel; é precisamente aqui que entra em ação Manter vivo . Configurei o NGINX para armazenar em cache os sockets já estabelecidos que se encontram inativos e para os utilizar em pedidos subsequentes, o que reduz significativamente os tempos de ligação. Isto diminui a taxa de ligações por segundo, reduz os picos de backlog e limita as mudanças de contexto no sistema operativo. Especialmente no caso do TLS para o backend, poupo tempo de forma significativa através da reutilização de sessões. Desta forma, a cadeia de respostas mantém-se estável mesmo com um elevado débito fiável e responde com fluidez.
Princípio básico e a diretiva keepalive no upstream
A diretiva keepalive No bloco „upstream“, limita-se o número de ligações backend inativas armazenadas em cache por cada worker. Este limite não se aplica globalmente, mas sim estritamente a cada processo worker, razão pela qual estou sempre atento ao número de workers. Quando o pool está cheio, o NGINX encerra primeiro a ligação que está inativa há mais tempo, para que haja espaço para novos sockets. Para a reutilização, o lado do proxy necessita de HTTP/1.1 e de um cabeçalho «Connection» neutralizado. Sem estes pré-requisitos, o pool permanece vazio, apesar de eu definir «keepalive» no upstream, o que muitos administradores no início surpreendido.
upstream backend_pool {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
keepalive 32; # ligações inativas por trabalhador
keepalive_requests 1000; # reciclagem após N pedidos
keepalive_timeout 60s; # tempo de inatividade
}
servidor {
escutar 80;
localização / {
proxy_pass http://backend_pool;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
Diretivas obrigatórias no bloco «Location»: HTTP/1.1 e controlo de cabeçalhos
Obrigo o NGINX a utilizar o HTTP/1.1 no caminho do proxy, porque o Keepalive não funciona corretamente com o HTTP/1.0 e as ligações terminam desnecessariamente; a diretiva versão_do_proxy_http 1.1 é, portanto, obrigatório. Além disso, removo o cabeçalho „Connection“ das solicitações normais, para que o backend não receba uma instrução „close“. Para atualizações como WebSockets, defino especificamente «Connection: Upgrade» através de um mapa, sem comprometer a reutilização normal. Desta forma, a política de ligação mantém-se consistente e desacoplada dos cabeçalhos do cliente. É precisamente esta pequena alteração que evita muitos problemas difíceis de identificar Imagens de erros.
location / {
proxy_pass http://backend_pool;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
map $http_upgrade $connection_upgrade {
default upgrade;
"" "";
}
Controlo de precisão: selecionar corretamente os valores de keepalive_requests e keepalive_timeout
Com dois parafusos de ajuste, controlo a duração e a renovação das ligações, para que a piscina se mantenha atualizada e não haja sockets abandonados a causar problemas; estes são keepalive_requests e keepalive_timeout. Após N pedidos, o NGINX encerra a ligação de forma seletiva e restabelece-a, se necessário, o que atenua os efeitos de envelhecimento na rede. Costumo definir o tempo de inatividade (Idle Timeout) num valor bastante curto, geralmente entre 30 e 120 segundos, para que os backends não interrompam a ligação antes do tempo. O importante é o equilíbrio: o valor do NGINX nunca deve ser superior ao tempo de espera dos servidores de aplicações, caso contrário, as reinicializações de ligação multiplicam-se. Quem quiser aprofundar os conceitos encontrará dicas práticas no artigo Tempo limite de keepalive, que explica os valores típicos e as interações.
Para uma orientação rápida, apresento os valores iniciais mais comuns e a respetiva finalidade numa tabela clara Tabela. Os valores de referência servem como ponto de partida e, após a monitorização, acabam por ficar frequentemente um pouco acima ou abaixo desses valores. Um período demasiado curto gera recriações desnecessárias, enquanto um período demasiado longo mantém ligações antigas. O número de pedidos por ligação protege-me de valores atípicos, sem esvaziar o conjunto. Com estes dados-chave, consigo obter resultados muito rapidamente Predefinições.
| Parâmetros | Objetivo | valor de referência | Nota sobre o tuning |
|---|---|---|---|
| keepalive | Tamanho do conjunto de processos inativos por trabalhador | 32-64 | Ajustar à carga simultânea por trabalhador |
| keepalive_requests | Pedidos máximos por ligação | 500–1000 | Em transmissões longas, defina um valor ligeiramente superior |
| tempo de espera de keepalive | Tempo máximo de inatividade por ligação | anos 60 | Tempo de espera de inatividade do backend mais curto ou igual |
Determinar o tamanho do pool com base nas ligações simultâneas
Não escolho o tamanho do pool com base no número de pedidos por segundo, mas sim com base em Concorrência por worker. Primeiro, calculo o número médio e o número máximo de pedidos paralelos ao backend. Em seguida, divido esses valores pelo número de workers do NGINX e arredondo para cima. Para 200 pedidos simultâneos com quatro workers, chego a um valor de cerca de 50 por worker, pelo que o valor inicial de keepalive 64 é adequado. Desta forma, mantenho os sockets disponíveis sem abrir um número desnecessário de Ligações para ligar.
Aproveitar deliberadamente as funcionalidades específicas das versões mais recentes do NGINX
As versões atuais permitem, muitas vezes por predefinição, a reutilização, mas estabelecem limites bastante conservadores; mesmo assim, vou indicar os valores explícito . Isto garante a reprodutibilidade, facilita o ajuste e evita surpresas após uma atualização. Através do parâmetro „local“, posso, opcionalmente, limitar a reutilização a uma localização específica, caso os perfis de segurança ou as políticas de cabeçalhos sejam diferentes. Desta forma, a separação mantém-se clara, sem perder globalmente as vantagens da reutilização. Com valores claros, documento as intenções e poupo trabalho mais tarde Tempo de análise.
Monitorização e métricas: a configuração está realmente a funcionar?
Começo por verificar o número de novas ligações ao backend por segundo; uma diminuição significativa indica que as medidas estão a surtir efeito Reutilização. Em seguida, observo o «upstream_connect_time», que se situa próximo de zero quando há acertos no pool. Erros nos registos, especialmente reinicializações de ligação, indicam limites de tempo que estão por trás dos valores do backend. Além disso, correlaciono a utilização da CPU do backend e as latências com a percentagem de ligações reutilizadas. Para uma compreensão mais aprofundada da Reutilização de ligações São úteis exemplos que mostram os efeitos em diferentes padrões de carga.
Eliminar rapidamente as fontes de erro típicas
Se não houver HTTP/1.1 para o backend, as ligações terão uma duração curta, independentemente do valor que eu keepalive defino. Se o cliente enviar „Connection: close“ e eu passar o cabeçalho sem filtrar, o backend encerra cada ligação imediatamente após a resposta. Se os tempos de espera de inatividade não coincidirem, o lado da aplicação encerra a ligação primeiro e o NGINX recebe um reinício na próxima solicitação. Um pool sobredimensionado mantém demasiados sockets abertos e desperdiça memória e portas. Verifico estes quatro pontos em cada análise como Primeiro, porque explicam 90 % de todos os problemas.
Exemplo prático: configuração de referência para elevado débito
Com apenas algumas instruções, consigo tornar um proxy sobrecarregado num servidor rápido e fiável e garantir um reencaminhamento correto dos cabeçalhos; o modelo seguinte tem-se revelado eficaz e é fácil de personalizar. Defino o keepalive para 64, limito as solicitações por ligação a 1000 e mantenho um tempo de inatividade de 60 segundos. Além disso, transmito corretamente as informações de host e de reencaminhamento, para que os backends possam aplicar a lógica e a limitação de taxa. Esta combinação poupa a CPU, reduz os tempos de resposta e permite lidar com picos de carga de forma mais tranquila. É exatamente assim que consigo uma Desempenho.
upstream app_backend {
server 10.0.1.10:3000 max_fails=2 fail_timeout=30s;
server 10.0.1.11:3000 max_fails=2 fail_timeout=30s;
keepalive 64;
keepalive_requests 1000;
keepalive_timeout 60s;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Ambientes de alojamento e aspetos operacionais que realmente importam
Costumo colocar o NGINX à frente do PHP-FPM, do Node.js ou dos serviços Java e certifico-me de que as latências de rede se mantêm baixas e que os tempos limite do backend são consistentes; isto proporciona Planeamento. Uma configuração de rede sólida ao nível do kernel, com limites de sockets adequados, evita que um grande número de ligações abertas entre em conflito. A distribuição equilibrada da CPU e os percursos de armazenamento rápidos ajudam os backends a manter tempos de resposta curtos. Além disso, garanto que as configurações sejam versionadas, para que as alterações permaneçam rastreáveis. Com esta disciplina, o sistema mantém-se estável mesmo em picos de tráfego reagível.
Melhores práticas para operações em curso
Começo com um keepalive de 32–64, 500–1000 pedidos por ligação e 60 segundos de tempo de inatividade; depois, faço medições sistemáticas e ajusto os valores; isto permite obter resultados rápidos sucessos. Acompanho cada alteração com métricas relativas à taxa de ligação, latência e padrões de erros, até que as curvas se estabilizem. Ajusto o tamanho do pool com base nas solicitações simultâneas, e não na taxa de transferência bruta por segundo. Os tempos de espera nunca devem ser superiores aos dos seus equivalentes na pilha de back-end; caso contrário, há risco de reinicializações esporádicas. Quem quiser ajustar os parâmetros com maior precisão encontrará orientações sobre o ajuste fino em Otimizar os pedidos Keepalive, o que torna a reciclagem bastante fácil de gerir.
Sincronização dos tempos de espera do proxy e do TCP Keepalive
Para além dos parâmetros de keepalive propriamente ditos, ajusto com precisão os limites de tempo de transporte. A tríade composta por tempo limite de ligação do proxy, proxy_send_timeout e tempo_limite_de_leitura_proxy determina o nível de paciência do NGINX ao estabelecer ligações, enviar e receber dados. Nunca defino estes valores acima dos correspondentes no backend, mas sim ligeiramente abaixo, para que os erros sejam detetados atempadamente e não se agravem no lado da aplicação. Além disso, ativo proxy_socket_keepalive, para que o sistema operativo envie sinais de vida a intervalos regulares através de sockets inativos e detete ligações semiabertas. Isto evita que as ligações inativas permaneçam no conjunto e provoquem picos de latência na próxima solicitação.
server {
listen 80;
location / {
proxy_pass http://backend_pool;
proxy_connect_timeout 3s; # falhar rapidamente se não for possível estabelecer ligação
proxy_send_timeout 30s; # Gravação no backend
proxy_read_timeout 30s; # Respostas do backend
proxy_socket_keepalive on; # Ativar o keepalive TCP do sistema operativo
}
}
No caso de fluxos de longa duração (por exemplo, SSE ou WebSockets), aumentei apenas o tempo limite de leitura, mantendo o tempo limite de ligação inalterado. Desta forma, consigo reagir rapidamente a destinos com falhas, mas deixo que as respostas legítimas e demoradas sejam processadas sem interrupções.
Planeamento de recursos: worker_connections, FDs e portas efémeras
Um conjunto de keepalive limpo não serve de nada se os limites dos descritores de ficheiros ou os intervalos de portas se esgotarem. Por isso, pretendo ligações_trabalhadores e worker_rlimit_nofile com margem de segurança. Faço um cálculo aproximado: FDs abertas ≈ (ligações simultâneas de clientes + ligações simultâneas ao backend + sockets inativos agrupados) por trabalhador. Se utilizar vários upstreams com pools, a necessidade multiplica-se. Da mesma forma, presto atenção à faixa de portas efémeras do sistema, uma vez que o NGINX atua como cliente TCP em direção ao backend e acumula estados TIME_WAIT.
worker_processes auto;
worker_rlimit_nofile 131072;
events {
worker_connections 8192;
}
Exemplos do Linux para # (sysctl):
net.core.somaxconn = 4096
net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.tcp_fin_timeout = 15
Adoto uma abordagem conservadora: não elimino o TIME_WAIT de forma agressiva, mas reduzo a taxa de ligações através do Keepalive. Desta forma, os parâmetros do kernel permanecem não críticos e o comportamento é previsível.
Zonas a montante, estratégia de balanceamento e rotação de DNS
Quando há vários workers, partilho o estado do Balancer através de uma zona, para que as falhas e os pesos se mantenham consistentes. Os sockets keepalive continuam a ser atribuídos por trabalhador, mas a distribuição torna-se mais uniforme. No caso de backends dinâmicos que mudam de endereço através do DNS, defino „resolver“ nas linhas do servidor e defina um resolver. Importante: quando os endereços IP são alternados, o conjunto não recicla imediatamente todos os sockets antigos; por isso, considero que keepalive_requests e prazos realistas, para que a renovação tenha efeito rapidamente.
upstream backend_pool {
zone backend_zone 128k; # partilha o estado do balanceador
least_conn; # distribuição equitativa em pedidos longos
server app-1.internal:8080 resolve;
server app-2.internal:8080 resolve;
keepalive 64;
keepalive_requests 1000;
keepalive_timeout 60s;
}
resolver 10.0.0.2 valid=30s;
resolver_timeout 5s;
proxy_next_upstream error timeout http_502 http_504;
proxy_next_upstream_tries 2; # repetições poucas e específicas
Para sessões ligadas a um nó de backend específico (por exemplo, «sticky state»), combino a reutilização com ip_hash ou um mecanismo de sessão externo. Isto evita que o agrupamento de ligações comprometa a coerência da sessão.
TLS para o backend: SNI, reutilização de sessões e algoritmos de encriptação
Quanto mais o TLS for utilizado no percurso do backend, mais valioso é o Keepalive. Ativo o SNI, defino o nome esperado e garanto a reutilização da sessão TLS. Isto reduz os custos do handshake e suaviza os picos de latência. Escolho as conjuntos de encriptação e os protocolos de forma restritiva, sem excluir backends mais antigos. Na verificação de certificados (opcional), a cadeia de confiança tem de estar completa; caso contrário, as ligações falham esporadicamente.
upstream https_backend {
server backend.example.local:443;
keepalive 32;
}
server {
listen 443 ssl;
location / {
proxy_pass https://https_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_ssl_server_name on;
proxy_ssl_name backend.example.local;
proxy_ssl_session_reuse on;
proxy_ssl_protocols TLSv1.2 TLSv1.3;
proxy_ssl_ciphers HIGH:!aNULL:!MD5;
# opcional: proxy_ssl_verify on;
# opcional: proxy_ssl_trusted_certificate /etc/nginx/ca.pem;
}
}
Se eu próprio controlar o lado do backend, ativo lá os tickets ou caches de sessão e verifico, através de métricas, se as taxas de retoma aumentam. Em combinação com o Keepalive, consigo assim tempos de ligação e de handshake consistentemente baixos.
Casos especiais: gRPC, WebSockets e autenticação ligada à ligação
Em gRPC O NGINX funciona a montante através de HTTP/2. Neste caso, um número reduzido de ligações de longa duração com muitos fluxos costuma proporcionar os melhores resultados; o conjunto de ligações mantém-se pequeno, mas estável. Para WebSockets Defino tempos de espera de leitura longos e mantenho a lógica dos cabeçalhos da solução «map», para que as ligações de atualização não sejam encerradas acidentalmente. NTLM ou outras formas de autenticação ligadas à ligação exigem o «connection pinning»; separo esses percursos em localizações próprias e reduzo aí o pooling ou a reutilização, para que os handshakes de segurança não se misturem entre clientes.
Exemplo de gRPC #
location /grpc.Service/ {
grpc_pass grpc://backend_pool;
grpc_read_timeout 300s; Permitir fluxos longos #
}
É fundamental definir uma política de ligação consistente para cada caminho e utilizar o Keepalive de forma generalizada apenas nos casos em que tal não seja semanticamente crítico.
A mensurabilidade na prática: registos de acesso com tempos de upstream
Estou a ampliar o registo de acesso com métricas de upstream. Desta forma, consigo perceber à primeira vista se uma resposta provém de um socket em pool (tempo de ligação muito curto) e com que frequência ocorrem erros no backend. Além disso, registo o número da ligação e o número de pedidos efetuados através da ligação atual do cliente, para identificar correlações.
log_format upstream_timing '$remote_addr - $host "$request" '
'up=$upstream_addr '
'sc=$status usc=$upstream_status '
'cc=$connection cr=$connection_requests '
'tc=$upstream_connect_time '
'th=$upstream_header_time '
'tr=$upstream_response_time';
access_log /var/log/nginx/access_upstream.log upstream_timing;
Além disso, utilizo os pontos finais de estado e as estatísticas de socket do SO. Um estado saudável caracteriza-se por: uma taxa de ligação ao backend em descida, um «upstream_connect_time» mais curto, tempos de resposta estáveis e quase nenhuma reinicialização de ligação. Os desvios indicam quase sempre limites de tempo mal ajustados ou pools demasiado pequenos ou demasiado grandes.
Estratégia de implementação e ajustes com baixo risco
Procedo de forma iterativa: pequenos passos, medir, ajustar. Primeiro, ativo o Keepalive de forma moderada; depois, ajusto os tempos de espera e o número de pedidos por ligação. Aplico as alterações através de uma atualização da página, sem interromper as ligações ativas. Desta forma, o risco mantém-se baixo e os efeitos podem ser atribuídos com clareza.
# Validar alterações e carregar sem tempo de inatividade
nginx -t && nginx -s reload
Quando tenho vários upstreams em funcionamento, faço o ajuste de cada um deles sucessivamente, começando pelo caminho mais crítico. A cada etapa é atribuída uma janela de observação, para que os padrões nas métricas se tornem claramente visíveis. Só depois é que aumentei ou reduzo os valores.
Resumo conciso sobre o teu proxy reverso
Utilizo o HTTP/1.1, esvazio o cabeçalho «Connection» e defino o tamanho do pool com base no número de pedidos simultâneos, e não no RPS; isso contribui para a Desempenho. Com as opções `keepalive_requests` e `keepalive_timeout`, mantenho as ligações ativas e evito surpresas causadas por sockets desatualizados. A monitorização mostra se o valor de `upstream_connect_time` tende para zero e se a taxa de ligações ao backend está a diminuir. Em caso de erros, verifico primeiro a versão do protocolo, a transmissão de cabeçalhos, os limites de tempo e o tamanho do pool. Assim, o teu proxy NGINX mantém-se estável sob carga elevada reativo e previsível.


