...

Optimera NGINX Keepalive-förfrågningar: Högsta möjliga webbserverprestanda genom målinriktad finjustering

Med nginx keepalive Jag sänker kostnaderna för uppkoppling, minskar antalet handskakningar och förbättrar svarstiderna märkbart. Noggrant anpassade timeouts, begäranbegränsningar per anslutning och återanvända uppströms-socklar ger mätbara prestandaförbättringar utan ny hårdvara.

Centrala punkter

  • Tidsfrister Välj på ett klokt sätt: Låt tomgångstiden vara så kort som möjligt, men så lång som den är användbar.
  • Förfrågningar Begränsa per anslutning: Hållbara anslutningar, inga avbrott.
  • Upstream-pooler Aktivera: Permanenta backend-anslutningar per arbetare.
  • Arbetare och anpassa anslutningarna: Tillräckligt med platser för inaktiva och aktiva klienter.
  • Övervakning etablera: Övervaka anslutningshastighet, latens och fel.

NGINX Keepalive: Effekt och kostnader

Jag låter medvetet TCP-anslutningarna vara öppna, eftersom Handskakningar är kostsamma och dominerar vid många små förfrågningar. Persistenta socklar sparar inte bara RTT:er, utan jämnar också ut CPU-belastningen, eftersom kryptografin för TLS behöver köras mindre ofta. Varje öppen anslutning tar dock upp Resurser, till exempel filbeskrivare och buffertar, som jag måste hålla koll på. Konsten ligger i balansen: tillräckligt med återanvändning för att upprätthålla hastigheten, tillräckligt med resurser för nya anslutningar vid belastningstoppar. Den som lyckas hitta den rätta balansen uppnår konstant låga TTFB-värden och en snabb användarupplevelse.

HTTP/2 och HTTP/3: Multiplexing möter Keepalive

Med HTTP/2 och HTTP/3 Antalet nödvändiga anslutningar per klient minskar eftersom flera strömmar går via en och samma linje. Keepalive är dock fortfarande viktigt: den enda anslutningen bör förbli öppen på ett tillförlitligt sätt, annars går fördelen med multiplexering förlorad på grund av frekventa återanslutningar.

Jag ser till att det finns särskilda viloparametrar för moderna protokoll och att värdena stämmer överens med mina klient-timeouts. Vid tester börjar jag på en måttlig nivå och höjer värdena när belastningen är stabil, tills antalet återanslutningar minskar och fördröjningarna förblir konstanta.

http {
    # HTTP/2: Väntetid för oanvända men öppna strömmar
    http2_idle_timeout 60s;

    # HTTP/3/QUIC: liknande logik för UDP-baserade anslutningar
    http3_idle_timeout 60s;

    # TLS-återupptagning minskar handskakningskostnaderna vid nya anslutningar
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
}

Multiplexering minskar det antal parallella TCP/QUIC-anslutningar som krävs, men inte betydelsen av korrekta timeouts. Den som använder HTTP/2/3 kan ofta ställa in klientens tidsgränser något generösare, eftersom många små resurser skickas via samma kanal. Viktigt: Förbli mätbar Tid till första byte, felprocent och öppna strömmar per anslutning.

Ställa in Client-Keepalive korrekt

För webbläsarklienter styr jag återanvändningen via keepalive_timeout och keepalive_requests, så att socklarna håller tillräckligt länge utan att blockeras i evigheter. Som utgångspunkt använder jag en timeout på 30–60 sekunder och 100–300 förfrågningar per anslutning, och justerar sedan utifrån mätvärdena. En detaljerad översikt finns här Guide till keepalive-timeout, som förklarar hur detta påverkar latensen och serverresurserna. Kortare timeout-tider lämpar sig vid ett mycket stort antal korta anrop, medan längre tidsfönster är lämpliga vid periodiska API-anrop. Till att börja med ställer jag in tydliga standardvärden och mäter effekten på öppna anslutningar samt felmönster.

http {
    # Inaktiva anslutningar till klienten
    keepalive_timeout 60s;
    # Övre gräns för antalet förfrågningar per TCP-anslutning
    keepalive_requests 200;

    # Valfritt: inaktivera Keep-Alive för vissa klienter (äldre buggar)
    # keepalive_disable msie6;
}

Upstream-Keepalive i omvänd proxy

Mellan NGINX och backend-apparna använder jag persistenta upstream-socklar, eftersom anslutningen till PHP-FPM, Node.js eller Python-tjänster också Fördröjning kostar. För detta aktiverar jag ett lämpligt antal återanvändbara anslutningar per arbetare i uppströms-poolen. Det är viktigt att använda HTTP/1.1 bakåt och en tom Connection-header, annars bryter klientens begäran „close“ backend-persistensen. Jag utgår från antalet samtidiga förfrågningar och ställer in poolen så att det knappt uppstår några nya anslutningar. På så sätt minskar anslutningstiden till backend, och hela kedjan levererar snabbare Svar på frågor.

upstream backend {
    server 127.0.0.1:9000;
    keepalive 64; # Antal beständiga uppströmsanslutningar per arbetare
}

server {
    location / {
 proxy_pass http://backend;
        proxy_http_version 1.1;
 proxy_set_header Connection "";
 # TCP-keepalive för uppströms-socklar på operativsystemsnivå
 proxy_socket_keepalive on;
    }
}

Dimensionering av poolen och anslutningsbudget

Jag beräknar pooler på ett realistiskt sätt: Antalet bestående uppströmsanslutningar beräknas utifrån worker_processes × keepalive per uppströmsmål. Den som använder 8 arbetare och keepalive 64 håller upp till 512 socklar öppna per uppströmsmål – per instans. Bakom en lastbalanserare eller vid flera uppströmsmål kan detta snabbt bli ett stort antal.

Mitt mål: tillräckligt många öppna socklar för att majoriteten av förfrågningarna utan ny Connect tillgodoses, men det finns fortfarande utrymme för toppar. Jag övervakar mätvärdet „nya uppströmsanslutningar per sekund“ och sänker det tills ytterligare ökningar av poolstorleken inte längre ger någon märkbar förbättring av latensen.

Jag tar också hänsyn till Rättvisa: För stora pooler kan missgynna nyanlända klienter, eftersom arbetarslots upptas av inaktiva anslutningar. En rimlig gräns i kombination med aktiv övervakning är oftast snabbare än att sätta maximivärden på gissning.

Finjustering: Timeouts och begäranbegränsningar

Jag kombinerar timeout och begäranbegränsning så att anslutningarna effektivt återanvänds utan att leda till Längdskidåkare att bli. Höga värden på båda axlarna minimerar antalet anslutningar, men ökar risken för att socklar fastnar vid nätverksproblem. Låga värden säkerställer nya anslutningar, men kräver ytterligare handskakningar. Jag går framåt i små steg, observerar fel och justerar med jämna mellanrum. Följande tabell visar lämpliga startintervall för olika användningsmönster och ger en kompakt Orientering.

Scenario keepalive_timeout keepalive_requests Ledtråd
Många korta sidvisningar 10–30 sekunder 100-300 Snabb återanvändning, låg belastning vid inaktivitet
En typisk webbplats 60–120 sekunder 200–400 Bra medelvärde för Assets och HTML
API med periodiska anrop 60–120 sekunder 300–1000 Högre återanvändningsgrad för kunder
Interna tjänster / Gatewayer 30–90 sekunder 500–1000+ Konstans är viktigare än minimala anslutningar

Arbetstagaranpassning och kopplingar

Jag satte arbetare_processer på ”auto” eller på antalet CPU-kärnor och planera för tillräckligt många arbetare_anslutningar eftersom inaktiva socklar upptar plats. För låga gränsvärden förhindrar nya anslutningar, trots att det fortfarande finns ledig CPU-kapacitet. Den som använder stora keepalive-pooler behöver tillräckligt med deskriptorer och händelseplatser per arbetare. En bra introduktion finns i „Skala upp Worker-Connections“, som förklarar sambanden mellan händelser, anslutningar och belastning. Väl genomtänkta värden säkerställer att återanvändning vid inaktivitet och nya anslutningar kan existera parallellt.

worker_processes auto;

events {
    worker_connections 4096;
    # Valfritt: reuseport kan förbättra fördelningen på kärnnivå
    # multi_accept on;
}

http {
    keepalive_timeout 60s;
    keepalive_requests 200;

 upstream backend {
 server 127.0.0.1:9000;
 keepalive 64;
    }
}

Optimering av operativsystem och socklar

Jag kontrollerar systemgränserna så att Keepalive kan nå sin fulla potential. För få deskriptorer eller trånga socket-köer leder till konstgjorda flaskhalsar. Förutom ulimit och worker_rlimit_nofile spelar kärnans begränsningar en avgörande roll.

# Exempel på sysctl-värden (justera med försiktighet och efter tester)
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

Jag anpassar dessa värden efter omgivningen: många kortlivade anslutningar gynnas av ett bredare portintervall och korta FIN-/TIME_WAIT-tider. När det gäller uppströms-keepalive minskar jag Neuconnects, vilket gör att TIME_WAIT-trycket minskar. Dessutom tar jag hänsyn till NAT-Enheter mellan proxy och backend: Alltför stränga tidsgränser för inaktivitet i nätverket kan avbryta anslutningar på oförutsägbart sätt. En rimlig begränsning av antalet förfrågningar per socket och TCP-keepalives (proxy_socket_keepalive on;) förhindrar att anslutningarna blir „föråldrade“.

Ställ in rubrik och HTTP-version korrekt

Jag är uppmärksam på HTTP/1.1 till backend, eftersom Upstream-Keepalive endast fungerar med det. Dessutom tar jag bort den aktiva anslutningsstyrningen via header, så att NGINX självständigt hanterar persistensen. På klientsidan låter jag Keep-Alive köras enligt standarden och begränsar livslängden via timeout och begäranbegränsning. Dessutom kontrollerar jag backend-idle-timeouts och ställer in dem något högre än NGINX för att undvika återställningsfel. Rena rubriker säkerställer Återanvändning utan oönskade stängningar.

# Exempel: Proxy-Location med korrekta rubriker
location /api/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
}

Skillnad: HTTP Keep-Alive jämfört med TCP-Keepalive

Jag gör en strikt åtskillnad mellan HTTP Keep-Alive (flera HTTP-förfrågningar per anslutning) och TCP-Keepalive (Test på operativsystemsnivå för att upptäcka inaktiva motparter). Jag styr HTTP Keep-Alive med keepalive_timeout och keepalive_requests, medan TCP-keepalives, beroende på stacken, kan vara upp till proxy_socket_keepalive on; och systemparametrar. För backend-system som ansluter via instabila nätverk aktiverar jag TCP-keepalives för att snabbare rensa bort hängande socklar.

Långkörare och specialfall: WebSockets, SSE, gRPC

WebSockets och server-sända händelser är Längdskidåkare, som håller en anslutning öppen under lång tid – här spelar klassisk återanvändning en underordnad roll. Jag ser till att det finns lämpliga proxy_read_timeout och skydda mig med send_timeout mot Slowloris-effekter. För gRPC (HTTP/2-baserat) gäller övervägandena kring multiplexering; jag ställer in timeout-värdena för inaktivitet så att strömmar inte stängs av i onödan.

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;
}

Övervakning och mätetal

Jag mäter framgången utifrån nyckeltal som andelen nya uppströmsanslutningar, uppströms_anslutning_tid och andelen öppna anslutningar per arbetare. Sjunkande anslutningshastigheter vid oförändrat eller ökande antal förfrågningar tyder på framgångsrik återanvändning. Påfallande timeouts eller återställningar av anslutningar signalerar inkonsekventa timeouts mellan NGINX och backend. Dessutom övervakar jag minne, filbeskrivare och händelseköer under belastning. Den som kontrollerar regelbundet upptäcker trender tidigt och förhindrar kostsamma Misslyckanden.

Förbättringar av loggningen för ökad transparens vid återanvändning

För att få en bättre överblick utökar jag åtkomstloggen med uppkopplingsdetaljer. På så sätt kan jag se hur ofta en TCP-anslutning återanvänds och hur anslutningstiderna utvecklas.

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;

Jag observerar medianvärden samt P95- och P99-värden för uppströms_anslutning_tid samt fördelningen av $-anslutningsförfrågningar. Stigande Reuse-värden vid stabil latens innebär att pooler och timeouts är lämpligt valda.

Typiska stötestenar och lösningar

För stora pooler fyller anslutningsslots medan nya klienter väntar, därför håller jag storlekarna på en rimlig nivå och mäter. Olika tidsgränser för inaktivitet mellan proxy och backend orsakar återställningar, så jag ställer in backenden till ett värde som är minimalt högre än NGINX. Ett glömt „Connection: close“ i proxy-headern avbryter persistensen, därför rensar jag headern systematiskt. TLS-förhandlingar kan belasta processorn vid många nya anslutningar, vilket jag mildrar genom en högre andel återanvändning. Vid sporadiska nätverksfel hjälper en måttlig begärandelimit per socket, så att gamla Sessioner inte leva för evigt.

Praktiska konfigurationer

För webbplatser med hög trafik väljer jag en kort timeout och en medelhög begäranbegränsning, så att resurserna fungerar effektivt. För API:er med återkommande anrop höjer jag gränsen för att ytterligare minska TCP- och TLS-handshakes. Jag dimensionerar uppströms-pooler utifrån förväntad parallellitet och testar med realistisk trafik. Varje miljö beter sig olika, därför kontrollerar jag latensen och felbilderna efter ändringar. Två exempel visar Startvärden, som jag sedan förfinar med hjälp av mätvärden.

# Scenario 1: Högt trafikerad webbplats
http {
    keepalive_timeout 30s;
    keepalive_requests 300;

 upstream app {
 server 127.0.0.1:8080;
        keepalive 32;
    }

 server {
 listen 443 ssl http2;
 # Hålla koll på HTTP/2-inaktivitet
 http2_idle_timeout 45s;
    }
}
# Scenario 2: API med periodiska anrop
http {
    keepalive_timeout 75s;
    keepalive_requests 1000;

    upstream api_backend {
 server 127.0.0.1:9001;
 keepalive 64;
    }

    server {
 listen 443 ssl http2;
 # Något längre inaktivitetsfönster för återkommande anrop
 http2_idle_timeout 75s;
    }
}

Checklista för iterativ optimering

Jag börjar med en analys av nuläget: trafikmönster, svarstider och felfrekvens anger takten. Därefter ställer jag in klient-timeout och begäranbegränsning på stabila startvärden och aktiverar uppströms-pooler. Jag ställer in backend-idle-timeouts något högre än NGINX, så att inga oväntade Återställningar uppstår. Därefter övervakar jag anslutningshastigheter, anslutningstid och öppna socklar per arbetare. Den som vill fördjupa sig i återanvändningsgraden hittar tips kring Anslutning Återanvändning och rimliga övre gränser.

Ytterligare diagnos: Mismatch och tidsbeteende

När anslutningarna avbryts utan någon uppenbar anledning letar jag efter Mismatchs i kedjan: Client-Idle vs. NGINX-Timeout vs. Backend-Idle och mellanliggande NAT/gateways. Jag höjer backend-timeouten något över NGINX-värdet, kontrollerar återställningskoder i felloggen och observerar om uppströms_anslutning_tid visar toppar. Ofta räcker det med en liten buffert (t.ex. +10–20%) vid backend-timeout för att undvika återställningar.

Jag noterar dessutom „långvarig närhet“-faser: Vid stängning låter NGINX inkommande data löpa ut en kort stund, vilket tar upp resurser hos arbetarna. Ett mycket stort antal samtidiga stängningar kan binda upp händelser. I sådana fall kalibrerar jag stängningsfönstren och håller det totala antalet öppna anslutningar i balans genom lämpliga keepalive-värden.

Sammanfattning: Keepalive som verktyg för att förbättra prestandan

Jag använder Keepalive medvetet eftersom det sänker kostnaderna för att upprätta anslutningar, minskar latensen och avlastar processorn. Kombinationen av lämplig timeout, en tydlig begäranbegränsning och lämpliga uppströmspooler ger märkbara hastighet. Utan övervakning förblir potentialen outnyttjad, därför granskar jag nyckeltalen kontinuerligt och justerar värdena steg för steg. Den som behöver ytterligare reserver bör hålla koll på antalet arbetare, anslutningsslots och korrekt hantering av rubriker. Professionella konfigurationer, till exempel vid webhoster.de, utnyttjar dessa justeringsmöjligheter fullt ut och tillhandahåller snabba, pålitliga tjänster.

Aktuella artiklar