Jeg skalerer nginx-workere målrettet for at kunne håndtere tusindvis af samtidige anmodninger med lav Forsinkelse at betjene. Nøglen ligger i en afstemt kombination af worker_processes, worker_connections, fildeskriptorer og Begivenheder.
Centrale punkter
- Kapacitet = worker_processes × worker_connections, ved reverse proxy ofte bestemt af klient- og upstream-forbindelser fordoblet.
- Filbeskrivelser (worker_rlimit_nofile, ulimit) tilpasset den forventede forbindelsesbelastning løft.
- Begivenheder-Blokering med epoll, multi_accept og kernel-backlogs ved høj belastning trimme.
- Overvågning via stub_status og belastningstests til iterative Tilpasning.
- Skalering Kombinere lodret og vandret, konfiguration afkoble.
NGINX-arkitektur: Master, Worker og begivenheder
NGINX anvender en master-proces, der starter flere worker-processer og koordinerer disse effektivt med Begivenheder betjenes. I stedet for tråde pr. anmodning behandler hver worker adskillige forbindelser på en ikke-blokerende måde via en begivenhedsbaseret model med lav Overhead. Jeg indstiller direktivet `worker_processes` til `auto`, så NGINX udnytter CPU-kernerne, og hver enhed får sin egen worker. På den måde fordeler jeg indgående forbindelser bedre og holder latenstiden nede under spidsbelastning lav. For en mere indgående gennemgang af procesplanlægningen henviser jeg til Optimering af Worker-processer, for en korrekt parallelisering bestemmer den mulige forbindelseskapacitet. Det er afgørende, at worker_connections pr. worker er dimensioneret hensigtsmæssigt, så multiplikationen med processerne giver den forventede Spidsbelastning dækker.
Kapacitetsformel: worker_processes × worker_connections
Jeg beregner den omtrentlige kapacitet ved at gange worker_processes med worker_connections, idet proxyerede anmodninger ofte optager to forbindelser pr. brugeradgang og dermed halverer det effektive antal kan. Mange standardinstallationer starter med 512 forbindelser pr. worker, hvilket ofte er for lidt til produktive arbejdsbelastninger er. Praktiske startværdier ligger typisk mellem 1024 og 4096 og afhænger af trafikprofilen og hardwaren. Jeg regner med en sikkerhedsmargen, altså mindst en faktor to i forhold til den målte spidsbelastning, for sikkert at kunne håndtere spidsbelastninger at afbøde. Det er stadig vigtigt at validere resultaterne ved hjælp af tests og live-metrikker, så tallene ikke blot bliver en teoretisk leg blive.
| Scenarie | arbejdsprocesser | arbejdstager_forbindelser | Teoretisk maks. | Effektiv (proxy) | FD pr. medarbejder |
|---|---|---|---|---|---|
| Lille hjemmeside | 2 | 1024 | 2048 | ~1024 | ≥1024 |
| API ved middel belastning | 4 | 2048 | 8192 | ~4096 | ≥2048 |
| Spidsbelastningstider i butikken | 8 | 4096 | 32768 | ~16384 | ≥4096 |
HTTP/1.1, HTTP/2 og TLS: Indvirkning på arbejdere og latenstid
Protokoller bestemmer forbindelsesprofilen. Med HTTP/1.1 ser jeg ofte mange samtidige TCP-forbindelser pr. klient, mens HTTP/2 reducerer antallet til få, men til gengæld mere udnyttede streams bundter. Det sparer på filbeskrivere, men lægger i stedet en større byrde på buffere og prioritering. Under TLS sørger jeg for at genbruge sessioner, så dyre håndtryk ikke skal udføres ved hver eneste forespørgsel sætte farten ned. En fælles session-cache og passende timeouts reducerer CPU-spidsbelastninger. Desuden indstiller jeg keepalive_requests ikke for lavt, så langvarige forbindelser kan udnytte deres fordele spille ud. For HTTP/2 beregner jeg en højere grad af samtidighed pr. forbindelse og sørger for, at sende- og modtagelsesbufferne er store nok, uden at optage for meget hukommelse spilde. Ved blandet trafik planlægger jeg konservativt og verificerer virkningerne for hver protokolvariant i Test.
Indstilling af filbeskrivere og ulimit korrekt
Hver forbindelse kræver mindst én filbeskrivelse, og ved reverse proxy ofte to, hvorfor lave ulimit-værdier kan være et stort problem Grænser indstille. Jeg øger worker_rlimit_nofile, så worker_processes × worker_connections kan realiseres, og der er reserver til logfiler, sockets og caches. På systemniveau tilpasser jeg limits.conf og fs.file-max, så operativsystemet tillader det planlagte antal åbne filer og ikke afbryder før tid Bremser. Ved hjælp af `ulimit -n` samt Systemd-parametre (LimitNOFILE) kontrollerer jeg, om konfigurationen er vedvarende og passer til NGINX. Hvis man ignorerer denne indstilling, vil man pludselig opleve afviste forbindelser og stigende Forsinkelser.
Finjustering af events-blokken: epoll, multi_accept, backlogs
Under Linux bruger jeg epoll, da denne mekanisme effektivt håndterer et stort antal forbindelser via asynkron Begivenheder håndterer. Med multi_accept on accepterer en worker flere nye forbindelser pr. begivenhed, hvilket udjævner belastningsspidser og forsinkelser ved modtagelsen sænker. Jeg justerer kerneparametre som net.core.somaxconn og net.ipv4.tcp_max_syn_backlog, så Accept-køer ikke løber over under trafikspidser. TIME_WAIT-optimeringer som tcp_tw_reuse mindsker portflaskehalse og holder gennemstrømningskurven stabil høj. Hvis man ønsker en mere indgående baggrundsviden om parallelitet og køer, er det værd at kigge på Optimering af trådpuljen, selvom NGINX primært fungerer på basis af begivenheder og derfor er meget ressourcebesparende skaleret.
Korrekt fordeling af listen-sockets: reuseport, backlog og accept_mutex
Når der er rigtig mange samtidige forbindelser, skalerer jeg modtagelsessporet aktivt. Med reuseport Hver worker får sin egen lytte-socket; dermed undgås konkurrence ved accept, og belastningen fordeles jævnt over alle kerner. Jeg indstiller listen-backlog eksplicit for at afbøde korte spidsbelastninger. Accept_mutex er ikke længere nødvendig i denne opsætning. Uden `reuseport` kan accept_mutex derimod hjælpe, for at dæmpe flokadfærd ved Accept. Vigtigt: Backlog-størrelserne i NGINX og kernen (somaxconn) bør passer sammen, ellers forsvinder effekten.
events {
use epoll;
worker_connections 4096;
# accept_mutex on; # er normalt ikke nødvendigt med reuseport
}
server {
listen 443 ssl http2 reuseport backlog=65535;
# ...
}
Derudover knytter jeg arbejdsprocesser til CPU-kerner efter behov (worker_cpu_affinity), så cache-linjer og IRQ-belastning forbliver stabile. I miljøer med stærk NUMA-påvirkning reducerer dette unødvendig Tværgående trafik i hukommelsen.
Reverse proxy, upstreams og Keep-Alive
Som reverse proxy opretholder NGINX ofte to forbindelser pr. anmodning: én til klienten og én til backend, hvilket gør kapacitetsplanlægningen realistisk dobbelt tæller. Jeg aktiverer Keep-Alive på en fornuftig måde, så upstream-forbindelser kan genbruges, og overhead pr. forespørgsel falder. På den måde reducerer jeg belastningen på PHP-FPM, applikationsserveren eller mikrotjenesterne og frigør plads til nye brugersessioner. Balancen mellem timeouts, inaktivitetstid og genbrug afgør, hvor effektivt forbindelserne genbruges blive. Hvis man ønsker at læse mere om grundlæggende emner herom, kan man finde det i Vedvarende forbindelser praktiske råd om udnyttelse og bedre netværks-Brug.
Upstream-puljer, timeouts og gentagelsesforsøg
For at undgå, at Worker skal vente på langsomme backends, sørger jeg for korte timeouts og velafvejede gentagelsesforsøg. Jeg holder upstream-keepalive-puljerne store nok til, at forbindelserne forbliver aktive, men ikke så store, at inaktive FD’er optager hukommelse og slots Bind. Jeg begrænser antallet af gentagelser til få forsøg og skifter kun over i tilfælde af tydelige transportfejl – på den måde undgår jeg »thundering herd«-effekter ved korte udfald 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; # genanvendelige upstream-forbindelser
}
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;
}
}
Samtidig justerer jeg Keep-Alive-parametrene (timeouts, antal anmodninger pr. forbindelse) for hurtigt at frigøre ressourcer fra klienter, der sjældent er aktive, at frigive.
Planlæg skalering på en fornuftig måde: kombiner vertikalt og horisontalt
Når der er tale om høje trafikmængder, foretrækker jeg at kombinere vertikal og horisontal skalering i Betragt. Vertikalt skalerer jeg ved hjælp af flere CPU-kerner, RAM, hurtige SSD’er og en optimeret netværkskonfiguration, så hver enkelt worker kører flydende værker. Horisontalt skalerer jeg med stateless NGINX-noder, centralt administreret konfiguration og distribueret logning, så den samlede kapacitet stiger lineært vokser. Lokale cacher og veldefinerede retningslinjer via Maps eller API gør det muligt hurtigt at implementere ændringer. Denne adskillelse mindsker bivirkninger og bidrager til, at nye trafikmønstre kan håndteres uden omlægninger på hvert enkelt knudepunkt betjene.
Hosting-perspektiv: Latenstid, fejlprocenter og brugeroplevelse
For få worker_connections fører til afviste forbindelser, timeouts og dårligere Brugeroplevelse. Dynamiske applikationer som CMS eller webshops mærker det straks, fordi et sidebesøg genererer flere backend-forespørgsler og slots hurtigere kort bliver. Derfor starter jeg med moderate værdier som 1024 eller 2048 pr. worker og øger disse gradvist på baggrund af reelle måleværdier. Samtidig sikrer jeg, at upstream-tjenesterne fungerer effektivt, og sørger for tilstrækkelige fildeskriptorer, så der ikke opstår kunstige Grænser virker. Benchmark-tests viser, at omhyggeligt tilpassede platforme giver reelle fordele her og håndterer spidsbelastninger pålideligt afskærmning.
Hukommelse, buffering og I/O-stier
Hver forbindelse optager RAM til metadata og buffere. Jeg dimensionerer proxy_buffers, client_body_buffer_size og large_client_header_buffers, så typiske anmodninger kan rummes, uden at der generelt bruges for meget RAM på grund af afvigende anmodninger. Bind. For statisk indhold fremskynder sendfile og tcp_nopush leveringen, mens tcp_nodelay er velegnet til små svar, hvor ventetiden er afgørende Vigtigt forbliver. Hvis data ligger på en langsommere lagringsenhed, hjælper aio threads plus thread_pool med at afbøde blokerende effekter. Med open_file_cache reducerer jeg filadgange og stat()-kald, men vær opmærksom på det ekstra behov for filhåndteringsdeskriptorer (FD). Jeg skriver logfiler med buffering (access_log … buffer=… flush=…), så I/O-spidsbelastninger ikke påvirker responstiderne påvirke.
Balance mellem sikkerhed og TLS-ydeevne
TLS-håndtryk er CPU-krævende. Jeg kombinerer genbrug af sessioner med moderate nøgleparametre og aktiverer optimeringer, der kan stables, såsom sessionscacher og billetter, forudsat at det er driftsmæssigt passer. Den optimale balance mellem sikkerhed og ydeevne holder latenstiderne stabile uden at gå på kompromis med krypteringskvaliteten. Ved højere belastning overvåger jeg 95.- og 99.-percentilen hver for sig, da TLS-spidsbelastninger ellers ville blive skjult bag gennemsnitsværdierne gemme sig. HTTP/2 mindsker antallet af forbindelser, men kræver omhyggelighed med strømstyring og header-komprimering for at holde CPU- og hukommelsesforbruget under kontrol beholde.
Modstandsdygtighed under overbelastning: Grænser og blid aflastning
For at bevare latensen er det nødvendigt med målrettet Formning uundværligt ved spidsbelastning. Med limit_conn begrænser jeg antallet af parallelle forbindelser pr. nøgle (f.eks. IP eller session), mens limit_req dæmper spidsbelastninger og beskytter backend-systemerne mod synkrone Storme. Jeg isolerer kritiske slutpunkter ved hjælp af strengere regler end for statiske ressourcer. Hvis der opstår en pludselig stigning i belastningen, returnerer jeg veldefinerede 429/503-fejlkoder med »Retry-After« i stedet for at behandle alle anmodninger ens sulte ihjel at lade. Jeg stopper langvarige forbindelser (lingering_close) for at frigive ressourcer på en kontrolleret måde og for at forhindre Slowloris-mønstre modbevise. Denne aktive shedding holder p95/p99-latensen inden for det grønne område, selv når det samlede behov til tider overstiger den nominelle kapacitet løgne.
Container- og systemintegration: Fjerne begrænsninger der, hvor de opstår
I containere gælder der ofte strammere begrænsninger. Jeg tjekker cgroup-grænser (CPU, RAM), indstiller ulimit -n passende inden for containeren og fastlægger LimitNOFILE i servicedfinitionen. sysctl-parametre som somaxconn og tcp_max_syn_backlog skal på Vært træder i kraft; navneområder isolerer ikke altid disse indstillinger på en gennemsigtig måde. På orkestrerede platforme planlægger jeg kapaciteten pr. pod/node, tildeler arbejdsprocesser til bestemte kerner og sørger for stabile netværksveje (f.eks. ingen unødvendige NAT-hop), så latenstidskurven stille og roligt forbliver. Jeg bruger worker_shutdown_timeout i forbindelse med rolling-opdateringer, så eksisterende forbindelser afsluttes korrekt udløbe.
Overvågning og iterativ optimering
Uden synlighed forbliver tuning-trinene Risiko. Jeg aktiverer stub_status eller alternative løsninger for løbende at overvåge aktive forbindelser, acceptprocenter og afvisninger. I belastningstests simulerer jeg realistiske adgangsmodeller og identificerer flaskehalse i acceptkøer, upstream-forsinkelser eller CPU-Mætning. Derefter justerer jeg forsigtigt worker_connections, processer, filgrænser og TCP-parametre og kontrollerer igen, hvordan det påvirker systemet. Denne cyklus sikrer, at platformen fungerer pålideligt og forhindrer uventede problemer på uheldige tidspunkter Tider.
Eksempel på konfiguration og beregningsmetode
Hvis jeg forventer 2000 samtidige in-flight-anmodninger i spidsbelastningsperioder og bruger en reverse proxy, regner jeg groft med 4000 forbindelsesslots plus Buffer. Hvis NGINX kører på fire CPU-kerner, starter jeg f.eks. med `worker_processes auto` og `worker_connections` på 1000 til 2000 pr. worker. Jeg indstiller grænsen for filbeskrivere pr. worker til et tilstrækkeligt højt niveau, så forbindelser, logfiler og interne sockets har plads nok Sted har. Jeg indstiller Events-blokken til epoll, aktiverer multi_accept og øger kernel-backlogs i overensstemmelse med min spidsbelastning. Et minimalistisk uddrag kan se sådan ud, som jeg derefter finjusterer med benchmarks Afstemning:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
use epoll;
worker_connections 2048;
multi_accept on;
}
http {
keepalive_timeout 65;
sendfile on;
# yderligere proxy-/cache-indstillinger ...
}
Derudover tilføjer jeg optimeringer af lister og upstream for at finpudse modtagelses- og backend-stien under belastning:
events {
use epoll;
worker_connections 4096;
# worker_cpu_affinity auto; # tildel kerner fast efter behov
}
http {
# Eksempler på TLS-/session-optimeringer
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;
}
}
}
Kort sagt: Konkrete retningslinjer
Jeg tilpasser `worker_processes` til antallet af CPU-kerner og indstiller `worker_connections` typisk til mellem 1024 og 4096. Ved reverse proxy planlægger jeg to forbindelser pr. anmodning og sørger for mindst det dobbelte af det målte spidsbelastnings-Belastning. Jeg indstiller worker_rlimit_nofile samt systemomfattende grænser højt nok til, at tallene fra nginx.conf forbliver reelt anvendelige. Jeg tilpasser Events-blokken til epoll og multi_accept, mens kernel-backlogs håndterer korte trafikspidser afbøde. Ved hjælp af overvågning og gradvise justeringer skaber jeg derudfra en pålidelig trafikmotor, der på en velfungerende måde håndterer det stigende antal besøgende bærer.


