Jag skalar nginx-arbetare på ett målinriktat sätt för att hantera tusentals samtidiga förfrågningar med låg Fördröjning att hantera. Nyckeln ligger i en väl avvägd kombination av worker_processes, worker_connections, fildeskriptorer och Händelser.
Centrala punkter
- Kapacitet = worker_processes × worker_connections, vid omvänd proxy ofta genom klient- och uppströmsanslutningar fördubblats.
- Filbeskrivningar (worker_rlimit_nofile, ulimit) anpassat efter den förväntade anslutningsbelastningen hiss.
- Händelser-Block med epoll, multi_accept och kärnbackloggar vid hög belastning klippa.
- Övervakning via stub_status och belastningstester för iterativa Anpassning.
- Skalning Kombinera vertikalt och horisontellt, konfiguration frikoppla.
NGINX-arkitektur: Master, Worker och händelser
NGINX använder en masterprocess som startar flera arbetare och samordnar dem effektivt med Händelser hanteras. Istället för trådar per begäran hanterar varje arbetare ett stort antal anslutningar på ett icke-blockerande sätt via en händelsebaserad modell med låg Overhead. Jag ställer in direktivet `worker_processes` på `auto`, så att NGINX utnyttjar CPU-kärnorna och varje enhet får en egen worker. På så sätt fördelar jag inkommande anslutningar bättre och håller latensen nere även vid toppbelastning låg. För en mer ingående genomgång av processplaneringen hänvisar jag till Optimera Worker-processer, eftersom korrekt parallellisering avgör den möjliga anslutningskapaciteten. Det är avgörande att worker_connections per arbetare dimensioneras på ett rimligt sätt, så att multiplikationen med processerna ger den förväntade Toppbelastning täcker.
Kapacitetsformel: worker_processes × worker_connections
Jag beräknar den ungefärliga kapaciteten med worker_processes × worker_connections, där proxyerade förfrågningar ofta upptar två anslutningar per användaråtkomst och därmed halverar det faktiska antalet finns på följande adress. Många standardinstallationer startar med 512 anslutningar per arbetare, vilket ofta är för lite för produktiva arbetsbelastningar är. Praktiska startvärden ligger vanligtvis mellan 1024 och 4096 och beror på trafikprofilen och hårdvaran. Jag planerar med ett säkerhetsmarginal, det vill säga minst en faktor två jämfört med den uppmätta toppbelastningen, för att säkert kunna hantera trafikspikar dämpa. Det är fortfarande viktigt att validera resultaten med tester och realtidsstatistik, så att siffrorna inte blir en rent teoretisk lek bli.
| Scenario | arbetare_processer | arbetare_anslutningar | Teoretiskt max. | Effektiv (proxy) | FD per arbetare |
|---|---|---|---|---|---|
| Liten webbplats | 2 | 1024 | 2048 | ~1024 | ≥1024 |
| API med medelstor belastning | 4 | 2048 | 8192 | ~4096 | ≥2048 |
| Butikens rusningstider | 8 | 4096 | 32768 | ~16384 | ≥4096 |
HTTP/1.1, HTTP/2 och TLS: Effekter på arbetare och latens
Protokollen avgör anslutningsprofilen. Med HTTP/1.1 ser jag ofta många samtidiga TCP-anslutningar per klient, medan HTTP/2 reducerar antalet till ett fåtal strömmar som däremot utnyttjas mer intensivt buntar. Det sparar filbeskrivare, men lägger istället belastningen på buffertar och prioritering. Vid TLS ser jag till att återanvända sessioner, så att kostsamma handskakningar inte behöver utföras vid varje förfrågan sakta ner. En gemensam sessionscache och lämpliga timeouts minskar CPU-topparna. Dessutom ställer jag inte in keepalive_requests för lågt, så att långvariga anslutningar kan ge sina fördelar spela ut. För HTTP/2 räknar jag med högre samtidighet per anslutning och ser till att sändnings- och mottagningsbuffertarna är tillräckligt stora, utan att ta upp minne slösa bort. Vid blandad trafik planerar jag försiktigt och verifierar effekterna per protokollvariant i Test.
Ställa in fildeskriptorer och ulimit korrekt
Varje anslutning kräver minst en filbeskrivare, och vid omvänd proxy ofta två, vilket gör att låga ulimit-värden kan vara svåra Gränser ställa in. Jag höjer värdet på worker_rlimit_nofile så att worker_processes × worker_connections blir genomförbart och det finns reserver för loggar, socklar och cacher. Systemomfattande justerar jag limits.conf och fs.file-max så att operativsystemet tillåter det planerade antalet öppna filer och inte avbryter i förtid Bromsar. Med hjälp av `ulimit -n` och Systemd-parametrar (LimitNOFILE) kontrollerar jag om konfigurationen är beständig och passar NGINX. Den som ignorerar denna inställning kommer, trots ett högt värde på `worker_connections`, plötsligt att uppleva avvisade anslutningar och stigande Fördröjningar.
Finjustera händelseblocket: epoll, multi_accept, backloggar
Under Linux använder jag epoll, eftersom denna mekanism effektivt hanterar stora antal anslutningar via asynkrona Händelser hanteras. Med multi_accept on accepterar en arbetare flera nya anslutningar per händelse, vilket jämnar ut belastningstoppar och minskar fördröjningarna vid mottagningen sänker. Jag justerar kärnparametrar som net.core.somaxconn och net.ipv4.tcp_max_syn_backlog så att accept-köerna inte överbelastas vid trafikspikar. TIME_WAIT-optimeringar som tcp_tw_reuse minskar portflaskhalsar och håller genomströmningskurvan hög. För mer ingående information om parallellitet och köer lönar det sig att ta en titt på Optimering av trådpool, även om NGINX i första hand fungerar händelsestyrt och därmed är mycket resurssnålt skalad.
Att fördela list-sockets på rätt sätt: reuseport, backlog och accept_mutex
När det finns väldigt många samtidiga anslutningar skalar jag mottagningsvägen aktivt. Med återanvända Varje worker tilldelas en egen lyssnande socket; på så sätt undviks konkurrens vid accept och belastningen fördelas jämnt över alla kärnor. Jag ställer in listen-backloggen explicit för att hantera korta belastningstoppar. Accept_mutex behövs inte längre i denna konfiguration. Utan reuseport kan accept_mutex däremot hjälpa, för att dämpa flockbeteendet vid Accept. Viktigt: Backlog-storlekarna i NGINX och kärnan (somaxconn) bör passa ihop, annars försvinner effekten.
events {
use epoll;
worker_connections 4096;
# accept_mutex on; # med reuseport behövs oftast inte
}
server {
listen 443 ssl http2 reuseport backlog=65535;
# ...
}
Dessutom kopplar jag vid behov arbetare till CPU-kärnor (worker_cpu_affinity) för att cache-linjerna och IRQ-belastningen ska förbli stabila. I miljöer med stark NUMA-påverkan minskar detta onödig Tvärgående trafik i minnet.
Omvänd proxy, uppströms och Keep-Alive
Som omvänd proxy upprätthåller NGINX ofta två anslutningar per begäran: en till klienten och en till backend, vilket gör kapacitetsplaneringen realistisk dubbel räknas. Jag aktiverar Keep-Alive på ett lämpligt sätt så att uppströmsförbindelserna kan återanvändas och overheaden per förfrågan minskar. På så sätt minskar jag belastningen på PHP-FPM, applikationsservern eller mikrotjänsterna och frigör lediga platser för nya användarsessioner. Balansen mellan timeout, vilotid och återanvändning avgör hur smidigt anslutningarna återanvänds bli. Den som vill läsa mer om grunderna i detta ämne kan hitta information i Bestående förbindelser praktiska tips om utnyttjande och bättre nätverks-Använd.
Upstream-pooler, tidsgränser och återförsök
För att arbetare inte ska behöva vänta på tröga backend-system ser jag till att använda korta timeouts och väl avvägda omförsök. Jag håller uppströms-keepalive-poolerna tillräckligt stora för att anslutningarna ska förbli aktiva, men inte så stora att inaktiva filer och beslag tar upp minne och platser binda. Jag begränsar antalet omförsök till ett fåtal och byter endast vid uppenbara överföringsfel – på så sätt förhindrar jag ”thundering herd”-effekter vid korta avbrott i backend-systemet.
upstream app_backend {
server 10.0.0.11:8080 max_fails=3 fail_timeout=10s;
server 10.0.0.12:8080 max_fails=3 fail_timeout=10s;
keepalive 64; # återanvändbara uppströmsanslutningar
}
server {
location / {
proxy_pass http://app_backend;
proxy_connect_timeout 2s;
proxy_read_timeout 15s;
proxy_send_timeout 15s;
proxy_next_upstream error timeout http_502 http_503;
proxy_next_upstream_tries 2;
}
}
Samtidigt justerar jag Keep-Alive-parametrarna (timeouts, antal förfrågningar per anslutning) för att snabbt frigöra resurser från klienter som sällan är aktiva att godkänna.
Planera skalningen på ett genomtänkt sätt: kombinera vertikalt och horisontellt
För höga trafikvärden föredrar jag att kombinera vertikal och horisontell skalning i Betrakta. Vertikalt skalar jag genom fler CPU-kärnor, RAM, snabba SSD-enheter och en optimerad nätverkskonfiguration, så att varje worker fungerar smidigt verk. Horisontellt skalar jag ut med stateless NGINX-noder, centralt hanterad konfiguration och distribuerad loggning, så att den totala kapaciteten ökar linjärt växer. Lokala cacher och tydligt definierade riktlinjer via Maps eller API gör att ändringar snabbt kan rullas ut. Denna uppdelning minskar bieffekter och bidrar till att nya trafikmönster kan hanteras utan att varje nod behöver byggas om betjäna.
Ur ett webbhotellsperspektiv: latens, felfrekvens och användarupplevelse
För få worker_connections leder till avvisade anslutningar, timeout och sämre Användarupplevelse. Dynamiska applikationer som CMS eller webbutiker märker detta omedelbart, eftersom ett sidbesök genererar flera förfrågningar till backend-systemet och slottarna snabbare kort kommer att bli. Därför börjar jag med måttliga värden som 1024 eller 2048 per arbetare och höjer dessa stegvis utifrån faktiska mätvärden. Samtidigt ser jag till att uppströms-tjänsterna fungerar smidigt och att det finns tillräckligt med filbeskrivare, så att inga konstgjorda Gränser fungerar. I prestandatester framgår det att noggrant anpassade plattformar ger verkliga fördelar här och hanterar toppbelastningar på ett tillförlitligt sätt Intercept.
Lagring, buffring och I/O-vägar
Varje anslutning upptar arbetsminne för metadata och buffertar. Jag dimensionerar proxy_buffers, client_body_buffer_size och large_client_header_buffers så att vanliga förfrågningar får plats, utan att för mycket RAM-minne reserveras generellt för extremvärden. binda. För statiskt innehåll påskyndar `sendfile` och `tcp_nopush` leveransen, medan `tcp_nodelay` används för små svar där latensen är avgörande Viktigt kvarstår. Om tillgångar ligger på en långsammare lagringsenhet kan aio threads och thread_pool hjälpa till att dämpa blockeringseffekter. Med open_file_cache minskar jag filåtkomst och stat()-anrop, men tänk på det extra behovet av filbeskrivningar (FD). Jag skriver loggar buffrat (access_log … buffer=… flush=…), så att I/O-toppar inte påverkar svarstiderna påverka.
Balans mellan säkerhet och TLS-prestanda
TLS-handshakes är CPU-krävande. Jag kombinerar återanvändning av sessioner med måttliga nyckelparametrar och aktiverar stapelbara optimeringar som sessionscacher och biljetter, förutsatt att de är driftsmässigt passform. Den optimala balansen mellan säkerhet och prestanda håller latenserna stabila utan att kompromissa med krypteringskvaliteten. Vid högre belastning följer jag 95:e och 99:e percentilen separat, eftersom TLS-toppar annars döljs bakom genomsnittsvärdena gömma. HTTP/2 minskar antalet anslutningar, men kräver noggrannhet när det gäller flödeskontroll och header-komprimering för att hålla CPU- och minnesanvändningen under kontroll behålla.
Motståndskraft under överbelastning: gränser och mjuk avlastning
För att upprätthålla latensen krävs målinriktad Formning Oumbärligt vid toppbelastning. Med limit_conn begränsar jag antalet parallella anslutningar per nyckel (t.ex. IP eller session), medan limit_req dämpar plötsliga belastningsspikar och skyddar backend-servrarna mot synkron Stormar. Jag isolerar kritiska slutpunkter med strängare regler än statiska resurser. Om belastningen ökar plötsligt skickar jag väldefinierade 429/503-fel med Retry-After, istället för att behandla alla förfrågningar lika svälta ihjäl att låta. Jag avbryter kvarvarande anslutningar (lingering_close) för att på ett kontrollerat sätt frigöra resurser och förhindra Slowloris-mönster motbevisa. Denna aktiva avlastning håller p95/p99-latensen inom det gröna området, även om den totala efterfrågan tillfälligt överstiger den nominella kapaciteten lögner.
Container- och systemintegration: Att undanröja begränsningar där de uppstår
I containrar gäller ofta strängare begränsningar. Jag kontrollerar cgroup-gränser (CPU, RAM), ställer in ulimit -n lämpligt inom containern och förankrar LimitNOFILE i tjänstedefinitionen. sysctl-parametrar som somaxconn och tcp_max_syn_backlog måste ställas in på Värd träder i kraft; namnutrymmen isolerar inte alltid dessa inställningar på ett transparent sätt. På orkestrerade plattformar planerar jag kapacitet per pod/nod, kopplar arbetare till tilldelade kärnor och ser till att nätverksvägarna är stabila (t.ex. inga onödiga NAT-hopp), så att latenskurvan tyst kvarstår. Jag kompletterar rullande uppdateringar med worker_shutdown_timeout för att se till att befintliga anslutningar avslutas på ett korrekt sätt löpa ut.
Övervakning och iterativ optimering
Utan synlighet förblir tuning-åtgärderna Risk. Jag aktiverar stub_status eller liknande verktyg för att kontinuerligt övervaka aktiva anslutningar, godkännandegrader och avvisningar. I belastningstester simulerar jag realistiska åtkomstmönster och identifierar flaskhalsar i accept-köer, uppströmsfördröjningar eller CPU-Mättnad. Därefter justerar jag försiktigt worker_connections, processer, filbegränsningar och TCP-parametrar och kontrollerar effekten på nytt. Denna cykel säkerställer plattformens tillförlitlighet och förhindrar oväntade händelser vid olämpliga Tider.
Exempel på konfiguration och beräkningsmetod
Om jag antar att jag under toppbelastning förväntar mig 2 000 samtidiga in-flight-förfrågningar och använder en omvänd proxy, beräknar jag grovt 4 000 anslutningsslots plus Buffert. Om NGINX körs på fyra CPU-kärnor börjar jag ungefär med `worker_processes auto` och `worker_connections` mellan 1 000 och 2 000 per arbetare. Jag ställer in gränsen för filbeskrivare tillräckligt högt per arbetare så att anslutningar, loggar och interna socklar får tillräckligt med Plats har. Jag ställer in Events-blocket på epoll, aktiverar multi_accept och ökar kernel-backlogs så att de passar min topptrafik. Ett minimalistiskt utdrag kan se ut så här, vilket jag sedan finjusterar med prestandatester Omröstning:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
use epoll;
worker_connections 2048;
multi_accept on;
}
http {
keepalive_timeout 65;
sendfile on;
# ytterligare proxy-/cache-alternativ ...
}
Som ett tillägg genomför jag optimeringar av listor och uppströmsflöden för att finjustera mottagnings- och backend-flödena under belastning:
events {
use epoll;
worker_connections 4096;
# worker_cpu_affinity auto; # tilldela kärnor fast vid behov
}
http {
# exempel på TLS-/sessionoptimeringar
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1h;
upstream app_backend {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
keepalive 64;
}
server {
listen 443 ssl http2 reuseport backlog=65535;
location / {
proxy_pass http://app_backend;
proxy_connect_timeout 2s;
proxy_read_timeout 15s;
proxy_next_upstream error timeout http_502 http_503;
proxy_next_upstream_tries 2;
}
}
}
I korthet: Konkreta riktvärden
Jag anpassar `worker_processes` efter antalet CPU-kärnor och ställer vanligtvis in `worker_connections` till mellan 1024 och 4096. Vid användning av omvänd proxy planerar jag två anslutningar per begäran och ser till att ha minst dubbelt så mycket utrymme som den uppmätta toppbelastningen –Last. Jag ställer in worker_rlimit_nofile samt systemomfattande gränser till tillräckligt höga värden för att siffrorna i nginx.conf ska förbli praktiskt användbara. Jag anpassar Events-blocket till epoll och multi_accept, medan kärnbackloggar hanterar korta trafikspikar dämpa. Genom övervakning och stegvisa justeringar skapar jag en pålitlig trafikmotor som hanterar det växande antalet besökare på ett smidigt sätt bär.


