Con nginx keepalive Riduco i costi di instaurazione della connessione, diminuisco gli handshake e accelero sensibilmente i tempi di risposta. Timeout mirati, limiti di richieste per connessione e socket upstream riutilizzati garantiscono miglioramenti misurabili delle prestazioni senza bisogno di nuovo hardware.
Punti centrali
- Timeout Scegliere con criterio: il tempo di inattività deve essere il più breve possibile, ma abbastanza lungo da essere utile.
- Richieste Limitare per connessione: socket a lunga durata, nessun blocco.
- Pool a monte Attiva: connessioni persistenti al backend per ogni worker.
- Lavoratore e ottimizzare le connessioni: slot sufficienti per i client inattivi e quelli attivi.
- Monitoraggio Configurare: monitorare la velocità di connessione, la latenza e gli errori.
NGINX Keepalive: effetti e costi
Lascio intenzionalmente aperte le connessioni TCP perché Strette di mano sono costose e prevalgono in presenza di molte piccole richieste. I socket persistenti non solo riducono i tempi di andata e ritorno (RTT), ma livellano anche il carico della CPU, poiché la crittografia per TLS viene avviata meno frequentemente. Tuttavia, ogni connessione aperta occupa Risorse, come i descrittori di file e i buffer, che devo tenere d’occhio. Il segreto sta nel giusto equilibrio: riutilizzo sufficiente per garantire la velocità, risorse sufficienti per creare nuove connessioni nei momenti di picco di carico. Chi riesce a trovare questo equilibrio ottiene valori TTFB costantemente bassi e un’esperienza utente fluida.
HTTP/2 e HTTP/3: il multiplexing incontra il keepalive
Con HTTP/2 e HTTP/3 Il numero di connessioni necessarie per ogni client diminuisce, poiché più flussi passano attraverso un’unica linea. Il keepalive rimane comunque importante: una connessione dovrebbe rimanere aperta in modo affidabile, altrimenti il vantaggio del multiplexing viene vanificato dalle frequenti riconnessioni.
Presto attenzione ai parametri di inattività specifici per i protocolli moderni e mi assicuro che i valori siano compatibili con i timeout del mio client. Per i test, inizio con valori moderati e li aumento, una volta che il carico si è stabilizzato, finché il tasso di riconnessione non diminuisce e le latenze rimangono costanti.
http {
# HTTP/2: tempo di inattività per gli stream inattivi ma aperti
http2_idle_timeout 60s;
# HTTP/3/QUIC: logica simile per le connessioni basate su UDP
http3_idle_timeout 60s;
# La ripresa della sessione TLS riduce i costi dell'handshake nelle nuove connessioni
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
}
Il multiplexing riduce il numero necessario di connessioni TCP/QUIC parallele, ma non l'importanza della timeout corretti. Chi utilizza HTTP/2/3 può spesso impostare i timeout del client in modo un po’ più generoso, poiché molte piccole risorse transitano attraverso lo stesso canale. Importante: rimanere misurabili Tempo al primo byte, tassi di errore e flussi aperti per ogni connessione.
Configurare correttamente il client keepalive
Per i client browser, gestisco il riutilizzo tramite keepalive_timeout e keepalive_requests, affinché i socket rimangano attivi abbastanza a lungo senza rimanere bloccati all’infinito. Come punto di partenza utilizzo un timeout di 30–60 secondi e 100–300 richieste per connessione, poi regolo i valori in base alle metriche. Una classificazione dettagliata è fornita da questo Guida al timeout di keepalive, che spiega l'impatto sulla latenza e sulle risorse del server. I timeout più brevi sono indicati in caso di un numero molto elevato di richieste brevi, mentre quelli più lunghi sono utili per gli accessi periodici all'API. Per iniziare, imposto valori predefiniti chiari e misuro l'effetto sulle connessioni aperte e sui tipi di errore.
http {
# Connessioni inattive con il client
keepalive_timeout 60s;
# Limite massimo di richieste per connessione TCP
keepalive_requests 200;
# Opzionale: disabilitare il Keep-Alive per determinati client (bug legacy)
# keepalive_disable msie6;
}
Keepalive a monte nel proxy inverso
Tra NGINX e le applicazioni backend utilizzo socket upstream persistenti, poiché la connessione a PHP-FPM, Node.js o ai servizi Python avviene anch’essa Latenza costa. A tal fine, attivo nel pool upstream un numero adeguato di connessioni riutilizzabili per ogni worker. È importante che l’HTTP/1.1 sia impostato verso il backend e che l’header Connection sia vuoto; altrimenti, la richiesta „close“ del client interrompe la persistenza del backend. Mi baso sul numero di richieste simultanee e configuro il pool in modo che non si verifichino quasi mai nuove connessioni. In questo modo si riduce il tempo di connessione al backend e l’intera catena garantisce prestazioni più fluide Risposte.
upstream backend {
server 127.0.0.1:9000;
keepalive 64; # Numero di connessioni upstream persistenti per worker
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
# Keepalive TCP per i socket upstream a livello di sistema operativo
proxy_socket_keepalive on;
}
}
Dimensionamento della piscina e budget per i collegamenti
Calcolo i pool in modo realistico: il numero di connessioni upstream persistenti risulta da worker_processes × keepalive per ogni upstream. Chi utilizza 8 worker e un valore di keepalive pari a 64 mantiene aperti fino a 512 socket per ogni upstream – per ogni istanza. Se si utilizza un bilanciatore di carico o si hanno più destinazioni upstream, il numero può aumentare rapidamente.
Il mio obiettivo: un numero sufficiente di socket aperti affinché la maggior parte delle richieste senza il nuovo Connect viene soddisfatta, ma rimane ancora margine per picchi di traffico. Monitoro la metrica „nuove connessioni upstream al secondo“ e la riduco fino a quando ulteriori aumenti delle dimensioni del pool non comportano più miglioramenti significativi della latenza.
Tengo anche conto di Equità: I pool troppo grandi possono penalizzare i client appena arrivati, poiché gli slot dei worker occupano le connessioni inattive. Un limite moderato, abbinato a un monitoraggio attivo, è solitamente più efficace rispetto a valori massimi fissati a caso.
Messa a punto: timeout e limiti di richiesta
Combino il timeout e il limite di richieste in modo tale che le connessioni vengano effettivamente riutilizzate senza arrivare al Sciatore di fondo . Valori elevati su entrambi gli assi riducono al minimo i “connects”, ma aumentano il rischio di socket bloccati in caso di problemi di rete. Valori bassi garantiscono connessioni fresche, ma comportano handshake aggiuntivi. Procedo a piccoli passi, osservo gli errori e effettuo aggiustamenti a intervalli regolari. La tabella seguente mostra intervalli iniziali ragionevoli per diversi modelli di utilizzo e fornisce una sintesi Orientamento.
| Scenario | keepalive_timeout | keepalive_requests | Suggerimento |
|---|---|---|---|
| Molte visualizzazioni brevi delle pagine | 10–30 s | 100-300 | Reuse veloce, basso consumo in modalità idle |
| Sito web tipico | 60–120 s | 200–400 | Buona media per gli asset e l'HTML |
| API con chiamate periodiche | 60–120 s | 300–1000 | Tasso di riutilizzo più elevato per i clienti |
| Servizi interni / Gateway | 30–90 s | 500–1000+ | La costanza è più importante dei “connects” minimi |
Ottimizzazione dei worker e connessioni
Ho messo processi_lavoratori su "auto" o sul numero di core della CPU e assicurati di pianificare una quantità sufficiente connessioni_lavoratore perché i socket inattivi occupano degli slot. Limiti troppo bassi impediscono l’accettazione di nuove connessioni, anche se sarebbe ancora disponibile capacità della CPU. Chi utilizza pool di keepalive di grandi dimensioni necessita di un numero sufficiente di descrittori e slot di evento per ogni worker. Una buona introduzione è fornita da „Scalabilità di Worker-Connections“, che illustra le relazioni tra eventi, connessioni e carico. Valori ben ponderati garantiscono che il riutilizzo in stato di inattività e le nuove connessioni possano coesistere.
worker_processes auto;
events {
worker_connections 4096;
# Opzionale: reuseport può migliorare la distribuzione a livello di kernel
# multi_accept on;
}
http {
keepalive_timeout 60s;
keepalive_requests 200;
upstream backend {
server 127.0.0.1:9000;
keepalive 64;
}
}
Ottimizzazione del sistema operativo e dei socket
Sto verificando i limiti di sistema affinché Keepalive possa esprimere appieno il proprio potenziale. Un numero insufficiente di descrittori o code di socket troppo strette causano colli di bottiglia artificiali. Oltre a ulimit e worker_rlimit_nofile, anche i limiti del kernel sono determinanti.
# Valori sysctl di esempio (da modificare con cautela e dopo aver effettuato dei test)
fs.file-max = 1000000
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 16384
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_syn_backlog = 262144
Adatto questi valori al contesto: molte connessioni di breve durata traggono vantaggio da un intervallo di porte più ampio e da tempi FIN/TIME_WAIT ridotti. Per quanto riguarda il keepalive upstream, riduco Neuconnects, il che riduce i picchi di TIME_WAIT. Inoltre, tengo conto di NAT-Dispositivi tra proxy e backend: i timeout di inattività troppo aggressivi nella rete interrompono le connessioni in modo imprevedibile. È consigliabile impostare un limite moderato di richieste per socket e utilizzare i keepalive TCP (proxy_socket_keepalive on;) prevengono le connessioni „stale“.
Impostare correttamente l'intestazione e la versione HTTP
Presto attenzione a HTTP/1.1 sul backend, perché Upstream-Keepalive funziona solo in questo modo. Inoltre, rimuovo la gestione attiva delle connessioni tramite header, in modo che NGINX gestisca autonomamente la persistenza. Sul lato client, lascio che Keep-Alive funzioni in conformità con lo standard e ne limito la durata tramite timeout e limite di richieste. Inoltre, controllo i timeout di inattività del backend e li imposto a un valore leggermente superiore rispetto a quello di NGINX, per evitare errori di reset. Header ben strutturate garantiscono la Riutilizzo senza chiusure indesiderate.
Esempio #: proxy con header corretti
location /api/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
Differenza: HTTP Keep-Alive vs. TCP Keep-Alive
Faccio una distinzione rigorosa tra HTTP Keep-Alive (più richieste HTTP per connessione) e TCP-Conservazione (Probe a livello di sistema operativo per individuare i terminali inattivi). Gestisco l'HTTP Keep-Alive con keepalive_timeout e keepalive_requests, mentre i keepalive TCP, a seconda dello stack, tramite proxy_socket_keepalive on; e i parametri di sistema. Per i backend che operano su reti instabili, attivo i keepalive TCP per liberare più rapidamente i socket bloccati.
Processo a lunga durata e casi particolari: WebSockets, SSE, gRPC
I WebSocket e gli eventi inviati dal server sono Sciatore di fondo, che mantengono aperta una connessione per un lungo periodo – in questo caso il classico Reuse ha un ruolo secondario. Mi occupo di trovare soluzioni adeguate proxy_read_timeout e proteggimi con send_timeout contro Slowloris-Effetti. Per gRPC (basato su HTTP/2) valgono le considerazioni relative al multiplexing; imposto i timeout di inattività in modo tale che gli stream non vengano chiusi inutilmente.
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
send_timeout 30s;
}
Monitoraggio e metriche
Misuro il successo attraverso indicatori quali il tasso di nuove connessioni upstream, tempo_di_connessione_a_stream e la percentuale di connessioni aperte per ogni worker. Un calo dei tassi di connessione a parità o aumento delle richieste indica un riutilizzo efficace. Timeout anomali o reset delle connessioni segnalano incongruenze nei timeout tra NGINX e il backend. Inoltre, monitoro la memoria, i descrittori di file e le code degli eventi sotto carico. Chi effettua controlli regolari individua tempestivamente le tendenze ed evita costose Fallimenti.
Miglioramenti alla registrazione per una maggiore trasparenza sul riutilizzo
Per avere un quadro più chiaro, aggiungo i dettagli di connessione al log di Access. In questo modo posso capire con quale frequenza viene riutilizzata una connessione TCP e come si evolvono i tempi di connessione.
log_format keepalive_fmt
'$remote_addr $host "$request" $status $body_bytes_sent '
'$request_time $upstream_connect_time '
'conn:$connection reqs:$connection_requests';
access_log /var/log/nginx/access_keepalive.log keepalive_fmt;
Sto osservando i valori mediani e P95/P99 di tempo_di_connessione_a_stream nonché la distribuzione di $_richieste_di_connessione. Un aumento del numero di Reuse a parità di latenza indica che i pool e i timeout sono stati impostati correttamente.
Ostacoli e soluzioni tipiche
Le pool troppo grandi occupano gli slot di connessione mentre i nuovi client rimangono in attesa, per questo mantengo le dimensioni moderate e le regolo con attenzione. Timeout di inattività diversi tra il proxy e il backend causano reset, quindi imposto il timeout del backend a un valore leggermente superiore rispetto a NGINX. Un „Connection: close“ dimenticato nell'intestazione del proxy interrompe la persistenza, pertanto svuoto sistematicamente l'intestazione. La negoziazione TLS può sovraccaricare la CPU in caso di numerose nuove connessioni, problema che risolvo aumentando la percentuale di riutilizzo. In caso di errori di rete sporadici, è utile impostare un limite moderato di richieste per socket, in modo che le vecchie Sessioni non vivere per sempre.
Configurazioni orientate alla pratica
Per i siti web molto frequentati, scelgo un timeout breve e un limite di richieste medio-alto, in modo che le risorse funzionino in modo efficiente. Nel caso di API con chiamate ricorrenti, aumento il limite per ridurre ulteriormente gli handshake TCP e TLS. Dimensiono i pool upstream in base al parallelismo previsto ed eseguo test con traffico realistico. Ogni ambiente si comporta in modo diverso, pertanto dopo ogni modifica verifico la latenza e i profili di errore. Due esempi illustrano valori iniziali, che poi affino utilizzando delle metriche.
# Scenario 1: sito web molto frequentato
http {
keepalive_timeout 30s;
keepalive_requests 300;
upstream app {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 443 ssl http2;
Monitoraggio del tempo di inattività HTTP/2 (#)
http2_idle_timeout 45s;
}
}
# Scenario 2: API con chiamate periodiche
http {
keepalive_timeout 75s;
keepalive_requests 1000;
upstream api_backend {
server 127.0.0.1:9001;
keepalive 64;
}
server {
listen 443 ssl http2;
# Finestra di inattività leggermente più lunga per le chiamate ricorrenti
http2_idle_timeout 75s;
}
}
Lista di controllo per l'ottimizzazione iterativa
Inizio con un’analisi dello status quo: i modelli di traffico, i tempi di risposta e il tasso di errore dettano il ritmo. Successivamente, imposto il timeout del client e il limite di richieste su valori iniziali affidabili e attivo i pool upstream. Impostiamo i timeout di inattività del backend a valori leggermente superiori rispetto a quelli di NGINX, in modo da evitare che si verifichino Reset si verificano. Successivamente monitoro il numero di connessioni, il tempo di connessione e i socket aperti per ogni worker. Chi desidera approfondire il concetto di riutilizzo troverà spunti su Riutilizzo delle connessioni e limiti massimi ragionevoli.
Diagnosi aggiuntiva: discrepanze e comportamento temporale
Quando le connessioni si interrompono apparentemente „senza motivo“, cerco Discordanze nella catena: inattività del client vs. timeout di NGINX vs. inattività del backend e NAT/gateway intermedi. Aumento leggermente il timeout del backend oltre il valore di NGINX, controllo i codici di reset nel log degli errori e osservo se tempo_di_connessione_a_stream mostra picchi. Spesso è sufficiente un piccolo margine (ad es. +10–20%) nel timeout del backend per eliminare i reset.
Faccio inoltre notare che „lingering close“Fasi “-”: durante la chiusura, NGINX lascia scorrere brevemente i dati in entrata, occupando risorse dei worker. Un numero molto elevato di chiusure simultanee può bloccare gli eventi. In questi casi, calibro le finestre temporali di chiusura e mantengo sotto controllo il numero totale di connessioni aperte impostando valori di keepalive adeguati.
Sintesi: il keepalive come leva per migliorare le prestazioni
Utilizzo Keepalive in modo mirato perché riduce i costi di instaurazione della connessione, diminuisce la latenza e alleggerisce il carico sulla CPU. La combinazione di un timeout adeguato, un limite di richieste ben definito e pool upstream adeguati porta a notevoli Velocità. Senza monitoraggio, il potenziale rimane inutilizzato; per questo motivo controllo costantemente gli indicatori e ne adeguo i valori passo dopo passo. Chi ha bisogno di risorse aggiuntive deve prestare attenzione al numero di worker, agli slot di connessione e alla corretta gestione delle intestazioni. Configurazioni professionali, ad esempio nel caso di webhoster.de, sfruttano appieno queste possibilità di regolazione e forniscono servizi rapidi e affidabili.


