Jeg konfigurerer NGINX Upstream Keepalive, så reverse-proxyen opretter færre forbindelser, giver lavere latenstider og pålideligt afbøder belastningsspidser. I den forbindelse tilpasser jeg Poolstørrelse, tidsgrænser og headere målrettet, så forbindelser genbruges, og datastien forbliver slank.
Centrale punkter
- HTTP/1.1 Tvinge og rense Connection-headere
- keepalive Dimensionere korrekt pr. medarbejder
- Timeouts tilpasse til backend-værdier
- Anmodninger/Forbindelse begrænse og genbruge
- Overvågning for forbindelseshastighed og latenstid
Hvorfor Upstream Keepalive reducerer forbindelsesomkostningerne drastisk
Uden genbrug opretter NGINX en ny backend-forbindelse for hver anmodning, hvilket medfører ekstra håndtryk, flere CPU-cyklusser og yderligere kernelressourcer; det er netop her, at Keepalive . Jeg lader NGINX cache allerede oprettede, midlertidigt inaktive sockets og bruge dem til efterfølgende forespørgsler, hvilket mærkbart reducerer forbindelsestiderne. Det sænker antallet af forbindelser pr. sekund, mindsker spidsbelastninger i backloggen og begrænser kontekstskift i operativsystemet. Især ved TLS til backend sparer jeg mærkbart tid ved at genbruge sessioner. På den måde forbliver svarkæden stabil, selv ved høj gennemstrømning pålidelig og reagerer smidigt.
Grundprincippet og keepalive-direktivet i upstream
Direktivet keepalive I upstream-blokken begrænser man antallet af inaktive backend-forbindelser, der caches pr. worker. Denne begrænsning gælder ikke globalt, men udelukkende pr. worker-proces, og derfor holder jeg altid øje med antallet af workere. Når puljen er fuld, lukker NGINX først den forbindelse, der har været ubenyttet længst, så der bliver plads til nye sockets. For at kunne genbruge forbindelserne kræver proxysiden HTTP/1.1 og en neutraliseret Connection-header. Uden disse forudsætninger forbliver puljen tom, selvom jeg indstiller „keepalive“ i upstream, hvilket mange administratorer i starten overrasket.
upstream backend_pool {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
keepalive 32; # inaktive forbindelser pr. worker
keepalive_requests 1000; # genbrug efter N anmodninger
keepalive_timeout 60s; # levetid for inaktive forbindelser
}
server {
listen 80;
location / {
proxy_pass http://backend_pool;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
Obligatoriske retningslinjer i Location-blokken: HTTP/1.1 og kontrol af headere
Jeg tvinger NGINX til at bruge HTTP/1.1 i proxystien, fordi Keepalive ikke fungerer korrekt med HTTP/1.0, og forbindelserne afbrydes unødigt; direktivet proxy_http_version 1.1 er derfor obligatorisk. Derudover fjerner jeg Connection-headeren for almindelige anmodninger, så backendet ikke modtager en „close“-instruktion. Ved opgraderinger som f.eks. WebSockets indstiller jeg målrettet „Connection: Upgrade“ via map uden at påvirke den normale genbrug. På den måde forbliver forbindelsespolitikken konsistent og adskilt fra klient-headere. Netop denne lille ændring forhindrer mange svært definerbare Fejlbilleder.
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;
"" "";
}
Finjustering: Vælg de rigtige indstillinger for keepalive_requests og keepalive_timeout
Ved hjælp af to justeringsskruer styrer jeg forbindelsernes levetid og fornyelse, så poolen forbliver opdateret, og der ikke er nogen forladte sockets, der forstyrrer; det er keepalive_requests og keepalive_timeout. Efter N anmodninger lukker NGINX forbindelsen målrettet og genopretter den om nødvendigt, hvilket afbøder aldringseffekter i netværket. Jeg indstiller idle-timeout til en ret kort tid, som regel mellem 30 og 120 sekunder, så backend-serverne ikke afbryder forbindelsen før tid. Det er vigtigt at afstemme indstillingerne: NGINX-værdien må aldrig være længere end app-serverens timeout, ellers vil der opstå mange forbindelsesnulstillinger. Hvis du vil dykke dybere ned i emnet, finder du praktiske tip i artiklen Keepalive-timeout, der forklarer typiske værdier og sammenhænge.
For at give et hurtigt overblik viser jeg her de gængse startværdier og deres respektive formål i en overskuelig Bord. Vejledende værdier fungerer som udgangspunkt og ender ofte lidt højere eller lavere efter overvågning. En for kort tidsperiode medfører unødvendige genopbygninger, mens en for lang tidsperiode fastholder gamle forbindelser. Antallet af anmodninger pr. forbindelse beskytter mod afvigelser, uden at puljen tømmes. Med disse nøgletal opnår jeg meget hurtigt velfungerende Standardindstillinger.
| Parametre | Formål | referenceværdi | Bemærkning vedrørende tuning |
|---|---|---|---|
| keepalive | Størrelsen på idle-puljen pr. worker | 32-64 | Tilpas efter den samtidige belastning pr. worker |
| keepalive_requests | Maks. antal anmodninger pr. forbindelse | 500–1000 | Ved lange streams skal man indstille den lidt højere |
| keepalive_timeout | Maks. inaktivitetstid pr. forbindelse | 60'erne | Kortere eller samme timeout for backend-inaktivitet |
Bestem poolstørrelsen ud fra antallet af samtidige forbindelser
Jeg vælger ikke poolstørrelsen ud fra antallet af anmodninger pr. sekund, men ud fra Samtidighed pr. worker. Først beregner jeg det gennemsnitlige og det maksimale antal parallelle backend-anmodninger. Derefter deler jeg disse tal med antallet af NGINX-workere og afrunder op. Ved 200 samtidige forespørgsler og fire arbejdere ender jeg på ca. 50 pr. arbejdstager, hvilket betyder, at keepalive 64 passer som startværdi. På den måde holder jeg soklerne tilgængelige uden unødigt mange åbne Forbindelser til at binde.
Bevidst udnytte de særlige egenskaber ved nyere NGINX-versioner
De nyeste versioner tillader ofte genbrug som standard, men sætter ret konservative grænser; jeg indtaster værdierne alligevel eksplicit . Det sikrer reproducerbarhed, letter finjusteringen og forhindrer uventede problemer efter en opdatering. Via parameteren „local“ kan jeg valgfrit begrænse genbrugen til en bestemt placering, hvis sikkerhedsprofiler eller header-politikker afviger. På den måde forbliver adskillelsen klar, uden at fordelene ved genbrug på globalt plan går tabt. Med klare værdier dokumenterer jeg hensigter og sparer senere Analysetid.
Overvågning og målinger: Virker konfigurationen virkelig?
Først tjekker jeg antallet af nye backend-forbindelser pr. sekund; et markant fald viser, at foranstaltningerne virker Genbrug. Derefter overvåger jeg upstream_connect_time, som ligger tæt på nul, når der er hits i poolen. Fejl i logfilerne, især forbindelsesafbrydelser, tyder på tidsgrænser, der ligger bag backend-værdierne. Derudover korrelerer jeg backend-CPU og latenstider med andelen af genbrugte forbindelser. For en dybere forståelse af Genbrug af forbindelser Eksempler, der viser virkningerne ved forskellige belastningsmønstre, er til hjælp.
Hurtigt afhjælp typiske fejlkilder
Hvis der mangler HTTP/1.1 til backend, vil forbindelserne være kortvarige, uanset hvor højt jeg keepalive sætter. Hvis klienten sender „Connection: close“, og jeg videresender headeren ufiltreret, lukker backend’en hver forbindelse umiddelbart efter svaret. Hvis idle-timeouts ikke stemmer overens, afbryder app-siden forbindelsen først, og NGINX modtager en reset ved den næste anmodning. En overdimensioneret pool holder for mange sockets åbne og spilder hukommelse og porte. Jeg tjekker disse fire punkter ved hver analyse som Først, fordi de forklarer 90 % af alle problemer.
Praksisexempel: Standardkonfiguration til høj gennemstrømning
Med blot nogle få retningslinjer får jeg en stærkt belastet proxy til at fungere hurtigt og pålideligt og sikrer, at headere videresendes korrekt; følgende mønster har vist sig at fungere godt og er let at Tilpas. Jeg indstiller keepalive til 64, begrænser antallet af anmodninger pr. forbindelse til 1000 og holder en inaktivitetstid på 60 sekunder. Derudover videresender jeg host- og forwarded-oplysninger korrekt, så backend-systemerne kan anvende logik og hastighedsbegrænsning. Denne kombination skåner CPU’en, forkorter svartiderne og håndterer belastningsspidser mere roligt. På netop denne måde opnår jeg en godt forudsigelig Ydelse.
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;
}
}
Hostingmiljøer og driftsmæssige aspekter, der virkelig tæller
Jeg placerer ofte NGINX foran PHP-FPM-, Node.js- eller Java-tjenester og sørger for, at netværksforsinkelserne holdes på et lavt niveau, og at backend-timeouts er ensartede; det giver Planlægbarhed. En solid kernel-netværkskonfiguration med passende socket-grænser forhindrer, at mange åbne forbindelser kolliderer. Jævn CPU-fordeling og hurtige lagringsveje hjælper backend-serverne med at opretholde korte svartider. Derudover sørger jeg for versionerede konfigurationer, så ændringer forbliver sporbare. Med denne disciplin forbliver systemet stabilt selv under trafikspidser reagerbar.
Bedste praksis for løbende drift
Jeg starter med keepalive 32–64, 500–1000 anmodninger pr. forbindelse og 60 sekunders inaktivitetstid, måler derefter systematisk og justerer værdierne; det giver hurtige succeser. Hver ændring ledsager jeg med målinger af forbindelseshastighed, latenstid og fejlmønstre, indtil kurverne udviser en mere stabil udvikling. Jeg tilpasser poolens størrelse efter antallet af samtidige forespørgsler, ikke efter den rå gennemstrømning pr. sekund. Timeouts må aldrig være længere end de tilsvarende i backend-stakken, ellers risikerer man sporadiske resets. Hvis du ønsker at finjustere yderligere, finder du vejledning til finjustering under Optimering af keepalive-anmodninger, hvilket gør genanvendelsen let at håndtere.
Justering af proxy-timeouts og TCP-keepalive
Ud over de rene keepalive-parametre tilpasser jeg transporttidsgrænserne nøjagtigt. Kombinationen af proxy_connect_timeout, proxy_send_timeout og proxy_read_timeout bestemmer, hvor tålmodig NGINX er ved opbygning, afsendelse og modtagelse. Jeg indstiller disse værdier aldrig højere end de tilsvarende værdier i backend, men lidt lavere, så fejl bliver synlige tidligt og ikke eskalerer på app-siden. Derudover aktiverer jeg proxy_socket_keepalive, så operativsystemet med jævne mellemrum sender livstegn via inaktive sockets og registrerer halvåbne forbindelser. Dette forhindrer, at døde forbindelser forbliver i puljen og forårsager forsinkelsestop ved den næste anmodning.
server {
listen 80;
location / {
proxy_pass http://backend_pool;
proxy_connect_timeout 3s; # hurtigt fejl, hvis forbindelse ikke er mulig
proxy_send_timeout 30s; # Skrivning til backend
proxy_read_timeout 30s; # Svar fra backend
proxy_socket_keepalive on; # Aktiver OS-TCP-keepalive
}
}
For langvarige streams (f.eks. SSE eller WebSockets) øger jeg udelukkende read-timeout, mens Connect forbliver lukket. På den måde reagerer jeg hurtigt på defekte mål, men lader legitime, lange svar køre uforstyrret igennem.
Ressourceplanlægning: worker_connections, FD’er og midlertidige porte
En ren keepalive-pulje nytter ikke noget, hvis filbeskrivelsesgrænser eller portområder udtømmes. Derfor planlægger jeg arbejdstager_forbindelser og worker_rlimit_nofile med en vis margen. Groft regnet: Åbne FD’er ≈ (samtidige klientforbindelser + samtidige backend-forbindelser + poolede inaktive sockets) pr. worker. Hvis jeg bruger flere upstreams med puljer, bliver behovet mangedoblet. Ligeledes er jeg opmærksom på systemets ephemeral-port-område, da NGINX fungerer som TCP-klient i retning af backend og akkumulerer TIME_WAIT-tilstande.
worker_processes auto;
worker_rlimit_nofile 131072;
events {
worker_connections 8192;
}
# Linux-eksempler (sysctl):
net.core.somaxconn = 4096
net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.tcp_fin_timeout = 15
Jeg vælger en konservativ tilgang: Jeg afbryder ikke TIME_WAIT for aggressivt, men sænker i stedet forbindelsesfrekvensen via Keepalive. På den måde forbliver kerneparametrene ukritiske, og adfærden forbliver forudsigelig.
Upstream-zoner, balanceringsstrategi og DNS-rotation
Hvis der er flere arbejdere, deler jeg balancertilstanden via en zone, så nedbrud og belastning forbliver ensartede. Keepalive-sockets forbliver ganske vist fortsat pr. worker, men fordelingen bliver mere jævn. Ved dynamiske backends, der flytter via DNS, indstiller jeg „løse“ i serverlinjerne og definer en resolver. Vigtigt: Når IP-adresserne skifter, genbruger puljen ikke straks alle gamle sockets; jeg mener derfor, at keepalive_requests og tidsfrister inden for realistiske rammer, så fornyelsen hurtigt slår igennem.
upstream backend_pool {
zone backend_zone 128k; # deler balancer-tilstand
least_conn; # retfærdig fordeling ved lange anmodninger
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; # få, målrettede gentagelser
For sessioner, der er bundet til en bestemt backend-node (f.eks. sticky-state), kombinerer jeg genbrug med ip_hash eller en ekstern sessionsmekanisme. Dette forhindrer, at forbindelsespooling forstyrrer sessionskonsistensen.
TLS til backend: SNI, genbrug af sessioner og krypteringsalgoritmer
Jo mere TLS der bruges i backend-stien, desto mere værdifuld er Keepalive. Jeg aktiverer SNI, angiver det forventede navn og sørger for, at TLS-sessionen genbruges. Det reducerer håndtryksomkostningerne og udjævner spidsbelastninger i latenstiden. Jeg vælger krypteringssuiter og protokoller med omhu, uden at udelukke ældre backends. Ved certifikatvalidering (valgfrit) skal tillidskæden være fuldstændig, ellers falder forbindelserne sporadisk ud.
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;
# optional: proxy_ssl_verify on;
# optional: proxy_ssl_trusted_certificate /etc/nginx/ca.pem;
}
}
Når jeg selv har kontrol over backend-siden, aktiverer jeg session-tickets eller -caches der og bruger målinger til at kontrollere, om genoptagelsesprocenten stiger. I kombination med Keepalive opnår jeg på den måde vedvarende lave forbindelses- og handshake-tider.
Særlige tilfælde: gRPC, WebSockets og forbindelsesbaseret autentificering
Med gRPC fungerer NGINX upstream via HTTP/2. Her giver få langvarige forbindelser med mange streams ofte de bedste resultater; puljen forbliver lille, men stabil. For WebSockets Jeg indstiller lange læsetimeouts og beholder header-logikken fra map-løsningen, så opgraderingsforbindelser ikke ved en fejltagelse lukkes. NTLM eller andre forbindelsesbaserede autentificeringer kræver connection pinning; jeg opdeler sådanne stier i egne lokationer og begrænser pooling eller genbrug dér, så sikkerhedshandshakes ikke blandes sammen mellem klienter.
# gRPC-eksempel
location /grpc.Service/ {
grpc_pass grpc://backend_pool;
grpc_read_timeout 300s; Tillad # lange streams
}
Det er afgørende at fastlægge en konsekvent forbindelsespolitik for hver rute og kun anvende keepalive i stort omfang dér, hvor det ikke er semantisk kritisk.
Målbarhed i praksis: Access-logfiler med upstream-timinger
Jeg udvider Access-loggen med upstream-metrikker. På den måde kan jeg med et blik se, om et svar kom fra en socket i poolen (meget kort forbindelsestid), og hvor ofte der opstår backend-fejl. Derudover logger jeg forbindelsesnummeret og antallet af anmodninger via den aktuelle klientforbindelse for at finde sammenhænge.
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;
Derudover bruger jeg status-endpunkter og operativsystemets socket-statistikker. En sund tilstand viser: faldende forbindelseshastighed til backend, kortere upstream_connect_time, stabile svartider og næsten ingen forbindelsesnulstillinger. Afvigelser tyder næsten altid på uafstemte tidsgrænser eller for små/for store puljer.
Udrulningsstrategi og risikominimering
Jeg går frem trin for trin: små skridt, måling, justering. Først aktiverer jeg Keepalive i moderat omfang, derefter justerer jeg timeouts og antal anmodninger pr. forbindelse. Ændringerne implementerer jeg ved at genindlæse siden uden at afbryde aktive forbindelser. På den måde forbliver risikoen lav, og effekterne kan tydeligt tilskrives de enkelte ændringer.
# Valider ændringer og indlæs dem uden nedetid
nginx -t && nginx -s reload
Når jeg kører flere upstreams, finjusterer jeg dem én efter én, begyndende med den mest kritiske vej. Hvert trin får et observationsvindue, så mønstre i målingerne tydeligt kan fremstå. Først derefter skalerer jeg værdierne op eller ned.
Kort oversigt over din reverse proxy
Jeg bruger HTTP/1.1, tømmer Connection-headeren og vælger poolstørrelsen ud fra antallet af samtidige anmodninger, ikke ud fra RPS; det understøtter Strøm. Med keepalive_requests og keepalive_timeout holder jeg forbindelserne aktive og undgår uventede problemer som følge af forældede sockets. Overvågningen viser, om upstream_connect_time nærmer sig nul, og om forbindelseshastigheden til backend falder. Ved fejl tjekker jeg først protokolversion, header-videresendelse, tidsgrænser og poolstørrelse. Sådan holder du din NGINX-proxy kørende under høj belastning lydhør og forudsigelig.


