...

NGINX Worker Connections – Schaalbaarheid van duizenden verzoeken voor maximale hostingprestaties

Ik schaal de Nginx-workers doelgericht op om duizenden gelijktijdige verzoeken met een lage Latency te bedienen. De sleutel ligt in een goed afgestemde combinatie van worker_processes, worker_connections, bestandsdescriptoren en Evenementen.

Centrale punten

  • Capaciteit = worker_processes × worker_connections, bij een reverse proxy vaak door client- en upstream-verbindingen verdubbeld.
  • Bestandsdescriptors (worker_rlimit_nofile, ulimit) afgestemd op de verwachte verbindingsbelasting lift.
  • Evenementen-Blokkering bij hoge belasting met epoll, multi_accept en kernel-backlogs bijwerken.
  • Controle via stub_status en belastingstests voor iteratieve Aanpassing.
  • Schalen verticaal en horizontaal combineren, configuratie ontkoppelen.

NGINX-architectuur: master, worker en events

NGINX maakt gebruik van een masterproces dat meerdere workerprocessen start en deze efficiënt aanstuurt met Evenementen verzorgd. In plaats van threads per verzoek verwerkt elke worker talrijke verbindingen op een niet-blokkerende manier via een op gebeurtenissen gebaseerd model met een lage Overhead. Ik stel de directive `worker_processes` in op `auto`, zodat NGINX de CPU-kernen benut en elke eenheid een eigen worker krijgt. Zo kan ik inkomende verbindingen beter verdelen en de latentie tijdens piekbelasting laag houden laag. Voor een diepgaandere inleiding in de planning van de processen verwijs ik naar Worker-processen optimaliseren, want een correcte parallellisatie bepaalt de haalbare verbindingscapaciteit. Het is van cruciaal belang dat het aantal `worker_connections` per worker op een zinvolle manier wordt bepaald, zodat de vermenigvuldiging met het aantal processen de verwachte Piekbelasting dekt.

Capaciteitsformule: worker_processes × worker_connections

Ik bereken de ruwe capaciteit met worker_processes × worker_connections, waarbij verzoekjes via de proxy vaak twee verbindingen per gebruikerstoegang in beslag nemen en daarmee het werkelijke aantal halveren kan. Veel standaardinstallaties beginnen met 512 verbindingen per worker, wat voor productieve workloads vaak te weinig is is. Praktische startwaarden liggen doorgaans tussen 1024 en 4096 en zijn afhankelijk van het verkeersprofiel en de hardware. Ik houd rekening met een marge, dus minimaal een factor twee ten opzichte van de gemeten piekbelasting, om pieken veilig op te vangen opvangen. Het blijft belangrijk om de resultaten te valideren met tests en live-statistieken, zodat de cijfers niet verworden tot een theoretisch spelletje worden.

Scenario werker_processen werker_verbindingen Theoretisch max. Effectief (proxy) FD per werknemer
Kleine website 2 1024 2048 ~1024 ≥1024
API gemiddelde belasting 4 2048 8192 ~4096 ≥2048
Drukke momenten in de winkel 8 4096 32768 ~16384 ≥4096

HTTP/1.1, HTTP/2 en TLS: gevolgen voor workers en latentie

Protocollen bepalen het verbindingsprofiel. Bij HTTP/1.1 zie ik vaak veel gelijktijdige TCP-verbindingen per client, terwijl HTTP/2 deze terugbrengt tot een klein aantal, maar des te zwaarder belaste streams bundels. Dat bespaart bestandsdescriptoren, maar verlegt de belasting naar buffers en prioritering. Bij TLS let ik op het hergebruik van sessies, zodat er niet bij elk verzoek dure handshakes hoeven plaats te vinden vertragen. Een gedeelde sessiecache en passende time-outs verminderen pieken in het CPU-gebruik. Bovendien stel ik keepalive_requests niet te laag in, zodat langdurige verbindingen hun voordelen kunnen bieden aflopen. Voor HTTP/2 ga ik uit van een hogere gelijktijdigheid per verbinding en zorg ik voor voldoende grote verzend- en ontvangstbuffers, zonder geheugen te verspillen. Bij gemengd verkeer stel ik een conservatief plan op en controleer ik de effecten per protocolvariant in de Test.

Bestandsdescriptoren en ulimit correct instellen

Elke verbinding heeft minimaal één bestandsdescriptor nodig, bij een reverse proxy vaak twee, waardoor lage ulimit-waarden een groot probleem vormen Grenzen instellen. Ik verhoog worker_rlimit_nofile zodanig dat worker_processes × worker_connections haalbaar wordt en er reserves zijn voor logs, sockets en caches. Systeembreed pas ik limits.conf en fs.file-max aan, zodat het besturingssysteem het geplande aantal open bestanden toestaat en niet voortijdig remmen. Met behulp van `ulimit -n` en Systemd-parameters (LimitNOFILE) controleer ik of de configuratie persistent is en aansluit bij NGINX. Wie deze instelling negeert, krijgt ondanks een hoog aantal `worker_connections` plotseling afgewezen verbindingen en stijgende Latencies.

Het evenementenblok nauwkeurig afstemmen: epoll, multi_accept, backlogs

Onder Linux gebruik ik epoll, omdat dit mechanisme grote aantallen verbindingen efficiënt verwerkt via asynchrone Evenementen afhandelt. Met `multi_accept on` accepteert een worker meerdere nieuwe verbindingen per gebeurtenis, wat pieken in de belasting afvlakt en vertragingen bij het accepteren verlaagt. Ik pas kernelparameters zoals net.core.somaxconn en net.ipv4.tcp_max_syn_backlog aan, zodat de accept-queues bij pieken niet overlopen. TIME_WAIT-optimalisaties zoals tcp_tw_reuse verminderen poortbottlenecks en houden de doorvoercurve stabiel hoog. Voor meer diepgaande achtergrondinformatie over parallellisme en wachtrijen is het de moeite waard om eens te kijken naar Threadpool-optimalisatie, ook al werkt NGINX voornamelijk op basis van gebeurtenissen en is daardoor zeer zuinig geschaald.

Listen-sockets correct toewijzen: reuseport, backlog en accept_mutex

Bij een zeer groot aantal gelijktijdige verbindingen schaal ik het ontvangstpad actief op. Met hergebruik Elke worker krijgt een eigen listening-socket; hierdoor ontstaat er geen concurrentie bij het accepteren van verbindingen en wordt de belasting gelijkmatig over alle kernen verdeeld. Ik stel de listen-backlog expliciet in om korte pieken op te vangen. De accept_mutex is in deze opstelling niet meer nodig. Zonder `reuseport` kan accept_mutex daarentegen helpen, om kuddegedrag bij Accept te temperen. Belangrijk: de backlog-groottes in NGINX en de kernel (somaxconn) moeten in elkaar passen, anders verdwijnt het effect.

events {
    use epoll;
    worker_connections 4096;
    # accept_mutex on;   # is bij reuseport meestal niet nodig
}

server {
    listen 443 ssl http2 reuseport backlog=65535;
    # ...
}

Daarnaast koppel ik workers indien nodig aan CPU-kernen (worker_cpu_affinity), zodat cache-lijnen en IRQ-belasting stabiel blijven. In omgevingen met een sterk NUMA-karakter vermindert dit onnodige Dwarsverkeer in het geheugen.

Reverse proxy, upstreams en keep-alive

Als reverse proxy onderhoudt NGINX vaak twee verbindingen per verzoek: één met de client en één met de backend, waardoor capaciteitsplanning realistisch is dubbel telt. Ik schakel Keep-Alive op een zinvolle manier in, zodat upstream-verbindingen herbruikbaar blijven en de overhead per verzoek vermindert. Zo verminder ik de belasting van PHP-FPM, de applicatieserver of de microservices en creëer ik vrije slots voor nieuwe gebruikerssessies. De balans tussen time-outs, inactieve tijd en hergebruik bepaalt hoe netjes verbindingen worden gerecycled worden. Wie hierover meer wil lezen, vindt in Permanente verbindingen praktische tips voor het benutten van de capaciteit en een beter netwerk-Gebruik.

Upstream-pools, time-outs en herhalingspogingen

Om te voorkomen dat workers moeten wachten op trage backends, hanteer ik korte time-outs en zorgvuldig afgewogen herpogingen. Ik houd de upstream-keepalive-pools groot genoeg om verbindingen in stand te houden, maar niet zo groot dat inactieve FD’s geheugen en slots binden. Ik beperk het aantal herhalingspogingen tot een paar en schakel alleen over bij duidelijke transportfouten – zo voorkom ik ‘thundering herd’-effecten bij korte storingen in de backend.

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;  # herbruikbare upstream-verbindingen
}

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

Tegelijkertijd pas ik de keep-alive-parameters (time-outs, aantal verzoeken per verbinding) aan, zodat de resources van zelden actieve clients snel weer vrij te geven.

Schaalbaarheid verstandig plannen: verticaal en horizontaal combineren

Bij hoge bezoekersaantallen geef ik de voorkeur aan een combinatie van verticale en horizontale schaalbaarheid Overweging. Verticaal schaal ik door meer CPU-kernen, RAM, snelle SSD’s en een geoptimaliseerde netwerkconfiguratie, zodat elke worker soepel werkt. Horizontaal schaal ik uit met stateless NGINX-knooppunten, centraal beheerde configuratie en gedistribueerde logboekregistratie, zodat de totale capaciteit lineair groeit. Lokale caches en duidelijk omschreven beleidsregels via Maps of de API zorgen ervoor dat wijzigingen snel kunnen worden doorgevoerd. Deze scheiding beperkt neveneffecten en helpt om nieuwe verkeerspatronen te verwerken zonder dat er aanpassingen nodig zijn op elk knooppunt bedienen.

Hostingperspectief: latentie, foutpercentages en gebruikerservaring

Te weinig worker_connections leiden tot afgewezen verbindingen, time-outs en slechte Gebruikerservaring. Dynamische toepassingen zoals CMS-systemen of webwinkels merken dit direct, omdat het laden van een pagina meerdere backend-verzoeken genereert en slots sneller korte worden. Daarom begin ik met gematigde waarden zoals 1024 of 2048 per worker en verhoog ik deze stapsgewijs op basis van daadwerkelijke meetwaarden. Tegelijkertijd zorg ik ervoor dat de upstream-diensten goed blijven presteren en dat er voldoende bestandsdescriptoren zijn, zodat er geen kunstmatige Grenzen werken. Uit benchmarks blijkt dat zorgvuldig afgestemde platforms hier echte voordelen bieden en piekverkeer betrouwbaar onderschep.

Geheugen, buffering en I/O-paden

Elke verbinding neemt werkgeheugen in beslag voor metadata en buffers. Ik stel de waarden van `proxy_buffers`, `client_body_buffer_size` en `large_client_header_buffers` zo in dat typische verzoeken erin passen, zonder dat er bij uitschieters automatisch te veel RAM wordt binden. Voor statische inhoud versnellen `sendfile` en `tcp_nopush` de levering, terwijl `tcp_nodelay` bedoeld is voor kleine antwoorden waarbij de latentie van cruciaal belang is Belangrijk blijft. Als assets op tragere opslag staan, helpen `aio threads` en `thread_pool` om blokkerende effecten op te vangen. Met `open_file_cache` verminder ik het aantal bestandstoegangen en `stat()`-aanroepen, maar houd rekening met de extra FD-behoefte. Logs schrijf ik gebufferd (access_log … buffer=… flush=…), zodat I/O-pieken de responstijden niet beïnvloeden.

Een evenwicht tussen beveiliging en TLS-prestaties

TLS-handshakes zijn CPU-intensief. Ik combineer het hergebruik van sessies met gematigde sleutelparameters en schakel stapelbare optimalisaties zoals sessiecaches en tickets in, voor zover dit operationeel fit. De optimale balans tussen veiligheid en prestaties houdt de latentie stabiel, zonder in te boeten aan de kwaliteit van de versleuteling. Bij een hogere belasting houd ik de 95e en 99e percentiel afzonderlijk in de gaten, omdat TLS-pieken anders achter de gemiddelde waarden verbergen. HTTP/2 vermindert het aantal verbindingen, maar vereist zorgvuldigheid bij de stroomcontrole en headercompressie om de CPU- en geheugenprofielen onder controle te houden behouden.

Veerkracht onder overbelasting: grenzen en geleidelijk afbouwen

Om de latentie te behouden, is gerichte Vormgeven onmisbaar bij piekbelasting. Met `limit_conn` beperk ik het aantal gelijktijdige verbindingen per sleutel (bijv. IP of sessie), terwijl `limit_req` piekbelasting afremt en backends beschermt tegen synchrone Stormen. Kritieke eindpunten isoleer ik met strengere regels dan statische assets. Als er op korte termijn een piek in de belasting optreedt, lever ik duidelijk gedefinieerde 429/503-foutcodes met Retry-After, in plaats van alle verzoeken gelijkmatig te verwerken verhongeren laten staan. Ik houd langdurige verbindingen (lingering_close) vast om bronnen op een gecontroleerde manier vrij te geven en Slowloris-patronen te ontkrachten. Door dit actieve shedding blijft de p95/p99-latentie binnen de veilige marges, zelfs als de totale vraag tijdelijk boven de nominale capaciteit ligt ligt.

Container- en systeemintegratie: beperkingen wegnemen waar ze ontstaan

In containers gelden vaak strengere beperkingen. Ik controleer de cgroup-limieten (CPU, RAM), stel ulimit -n binnen de container op de juiste waarde in en veranker LimitNOFILE in de servicedefinitie. sysctl-parameters zoals somaxconn en tcp_max_syn_backlog moeten op de Gastheer van kracht worden; naamruimten isoleren deze instellingen niet altijd op transparante wijze. Op georkestreerde platforms plan ik de capaciteit per pod/node, koppel ik workers aan toegewezen kernen en let ik op stabiele netwerkpaden (bijv. geen onnodige NAT-hops), zodat de latentiekromme rustig blijft. Ik gebruik worker_shutdown_timeout bij rolling updates, zodat bestaande verbindingen netjes uitlopen.

Monitoring en iteratieve optimalisatie

Zonder zichtbaarheid blijven tuningstappen een Risico. Ik schakel stub_status of alternatieve oplossingen in om actieve verbindingen, acceptatiepercentages en afwijzingen continu te monitoren. In belastingstests simuleer ik realistische toegangsmodellen en breng ik knelpunten in kaart bij acceptatiewachtrijen, upstream-latenties of CPU-Verzadiging. Daarna pas ik worker_connections, processen, bestandslimieten en TCP-parameters voorzichtig aan en controleer ik opnieuw het effect. Deze cyclus zorgt ervoor dat het platform betrouwbaar blijft en voorkomt verrassingen op ongelegen momenten Times.

Voorbeeldconfiguratie en berekeningswijze

Stel dat ik tijdens piekuren 2000 gelijktijdige in-flight-verzoeken verwacht en een reverse proxy gebruik, dan schat ik grofweg 4000 verbindingsslots plus Buffer. Als NGINX op vier CPU-kernen draait, begin ik bijvoorbeeld met `worker_processes auto` en `worker_connections` tussen 1000 en 2000 per worker. De limiet voor het aantal file descriptors stel ik per worker voldoende hoog in, zodat verbindingen, logbestanden en interne sockets voldoende Plaats heb. Ik stel het Events-blok in op epoll, activeer multi_accept en verhoog de kernel-backlogs in overeenstemming met mijn piekverkeer. Een minimalistisch fragment kan er zo uitzien, dat ik vervolgens met benchmarks verfijn Stem:

worker_processes  auto;
worker_rlimit_nofile  65535;

events {
    use epoll;
    worker_connections  2048;
    multi_accept on;
}

http {
    keepalive_timeout   65;
    sendfile on;
    # overige proxy-/cache-opties ...
}

Daarnaast voeg ik lijst- en upstream-optimalisaties toe om de acceptatie- en backend-trajecten onder belasting te verfijnen:

events {
    use epoll;
    worker_connections 4096;
    # worker_cpu_affinity auto;  # indien nodig kernen vast toewijzen
}

http {
    # TLS-/sessie-optimalisaties als voorbeeld
    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 samengevat: concrete richtwaarden

Ik stem het aantal `worker_processes` af op het aantal CPU-kernen en stel het aantal `worker_connections` doorgaans in op een waarde tussen 1024 en 4096. Bij een reverse proxy ga ik uit van twee verbindingen per verzoek en houd ik rekening met ten minste het dubbele aan speling ten opzichte van de gemeten piek-Belasting. Ik stel worker_rlimit_nofile en de systeembrede limieten hoog genoeg in, zodat de waarden uit het nginx.conf-bestand daadwerkelijk bruikbaar blijven. Het Events-blok beperk ik tot epoll en multi_accept, terwijl kernel-backlogs korte verkeerspieken dempen. Door middel van monitoring en stapsgewijze aanpassingen bouw ik hiermee een betrouwbare traffic-engine op, die de groeiende bezoekersaantallen netjes draagt.

Huidige artikelen