...

NGINX-werkprocessen optimaal configureren voor maximale prestaties

I configureren NGINX-worker zodat worker_processes, worker_connections en worker_rlimit_nofile precies op elkaar zijn afgestemd en Epoll in de event-loop werkt. Daardoor gebruik ik CPU-kernen Zorg voor efficiëntie, maak het mogelijk om het aantal gelijktijdige verbindingen op een voorspelbare manier te schalen en houd de latentie laag tijdens piekbelastingen.

Centrale punten

De volgende kernpunten bieden je direct houvast voor een robuuste NGINX-worker-configuratie.

  • werker_processen koppelen aan het aantal logische kernen, bij voorkeur met „auto“.
  • werker_verbindingen zo instellen dat werkelijke pieken ruimschoots worden opgevangen.
  • rlimit_nofile en de OS-limieten aanpassen aan de verbindingscapaciteit.
  • epoll en multi_accept inschakelen om de event-loop efficiënt te benutten.
  • Belastingstesten doorgaan en in kleine stapjes nauwkeurig bijstellen.

NGINX-architectuur: inzicht in master en worker

Ik maak een onderscheid tussen de taken van Master en de workers: de master laadt configuraties, opent sockets en start processen, terwijl de workers in de event-loop verzoeken verwerken. Elke worker draait zelfstandig, reageert op gebeurtenissen en kan duizenden verbindingen beheren zonder blokkades te veroorzaken. Dit model komt goed tot zijn recht als ik CPU-kernen op de juiste manier inzet en de event-loop via epoll optimaal aanstuur. Ik houd er daarbij rekening mee dat elke extra proxy-hop verbindingsbronnen in beslag neemt, wat tot uiting komt in de limieten. Wie de rollen begrijpt, neemt bewuste beslissingen over Bronnen en voorkomt knelpunten in een vroeg stadium.

De drie belangrijkste richtlijnen op de juiste manier met elkaar verbinden

Ik beschouw werker_processen, worker_connections en worker_rlimit_nofile nooit afzonderlijk, maar als één geheel. Het totale aantal mogelijke verbindingen is het resultaat van het aantal workers vermenigvuldigd met het aantal verbindingen per worker; daaruit leid ik de limieten voor bestandsdescriptoren af. Als deze instellingen niet op elkaar zijn afgestemd, krijg ik te maken met „too many open files“ of harde time-outs. Voor hoge belasting heb ik een goed afgestemde keten nodig: voldoende processen, ruime verbindingen, netjes verhoogde rlimit_nofile en passende OS-parameters. Zo voorkom ik dat een te kleine Beperk de totale capaciteit is beperkt.

worker_processes: het aantal zorgvuldig kiezen

Ik stel werker_processen meestal op „auto“, zodat NGINX het aantal logische CPU-kernen herkent en elke kern kan benutten. Eén worker per kern voorkomt onnodige contextwisselingen en verdeelt de belasting gelijkmatig, waardoor de responstijd voorspelbaar blijft. Op machines met zeer veel kernen test ik bewust ook lagere aantallen workers om cache-hits en kernbezetting te vergelijken. Als uit de statistieken blijkt dat kernen overbelast raken of dat het aantal TLB-misses toeneemt, pas ik het aantal workers stapsgewijs aan. Eerst meten, dan aanpassen – zo zorg ik voor betrouwbare Resultaten.

worker_connections: het aantal verbindingen op een planbare manier verhogen

Ik kies voor de werker_verbindingen afhankelijk van het doelverkeer en de protocolmix, vaak beginnend bij 2048 of 4096. Voor drukbezochte API’s overweeg ik 8192, mits de limieten van het besturingssysteem en het RAM-geheugen dit toelaten. Elke verhoging toets ik met belastingstests, omdat open verbindingen geheugen bezetten en het upstream-gedrag beïnvloeden. Als SSL-handshakes of grote uploads de boventoon voeren, richt ik me eerder op CPU- en I/O-profielen, en niet alleen op de kale verbindingsaantallen. Zo zorg ik ervoor dat het per worker gedefinieerde Capaciteit ook in de praktijk bruikbaar blijft.

worker_rlimit_nofile en OS-limieten synchroniseren

Ik zorg ervoor dat rlimit_nofile ten minste de theoretische totale capaciteit dekt en vaak met een reserve wordt geconfigureerd. Voor reverse-proxy-scenario’s houd ik per clientverbinding rekening met een tweede descriptor voor de upstream. Daarom stel ik rlimit_nofile graag in op het dubbele van het verwachte aantal gelijktijdige verbindingen. De kernel- en gebruikerslimieten (ulimit -n, fs.file-max) verhoog ik zodanig dat NGINX de waarden daadwerkelijk kan benutten. Als er in het foutenlogboek meldingen over open bestanden verschijnen, verhoog ik de limieten onmiddellijk en houd ik de Latency onder belasting opnieuw.

Evenementenblok: epoll en multi_accept effectief inzetten

Ik activeer in het evenementenblok epoll en stel multi_accept in op „on“, zodat workers wachtende verbindingen in één keer accepteren. Epoll vermindert de overhead bij veel gelijktijdige sockets en sluit goed aan bij het niet-blokkerende ontwerp van NGINX. Deze instellingen lonen zich bij pieken in het verkeer, omdat ik de acceptatiefase versnel en sneller bij de daadwerkelijke verwerking kom. Voor Linux is dit mijn standaardinstelling, die ik alleen in zeldzame, speciale gevallen aanpas. Wie zich hier verder in wil verdiepen, vergelijkt het event-loop-model met Threadpool versus event-loop en trekt daaruit de conclusie dat conclusies voor de eigen omgeving.

CPU-affiniteit: workers aan cores koppelen

Ik stel worker_cpu_affinity Ik pas dit doelgericht toe wanneer workloads constant en CPU-gebonden zijn. Ik verdeel het toewijzingsschema via bitmaskers om contextwisselingen te vermijden en cache-localiteit te bevorderen. Bij vier kernen wijs ik de maskers zo toe dat elke worker een eigen kern krijgt. Vervolgens controleer ik de cache-miss-percentages, mediane latenties en 99e percentielen om het effect duidelijk te zien. Meer uitleg over affiniteit en NUMA vind je beknopt op CPU-affiniteit in de praktijk, wat bij het verfijnen van Werknemer-Lay-outs helpt.

Capaciteit plannen: headroom en belastingstests

Bij verbindingen plan ik een Buffer die duidelijk boven de waargenomen pieken ligt, zodat kortstondige pieken niet direct de limieten overschrijden. Als ik de piekbelasting als uitgangspunt verdubbel, heb ik in veel scenario’s een ruime marge. Bij sterk fluctuerend verkeer vergroot ik de buffer verder totdat de 99e percentielen soepel verlopen. Vervolgens controleer ik knelpunten met tools zoals wrk of k6, houd ik foutpercentages in de gaten en bekijk ik de status van open verbindingen. Pas als de statistieken consistent zijn, verhoog of verlaag ik gericht afzonderlijke Waarden.

Configuratie en rekenvoorbeelden

Ik bereken de verbindingscapaciteit door het aantal workers te vermenigvuldigen met het aantal verbindingen per worker en stel op basis daarvan de limieten iets hoger in. Bij vier CPU-kernen met de instelling ‘auto’ en 4096 verbindingen per worker kom ik uit op 16384 gelijktijdige verbindingen. In proxyscenario’s stel ik rlimit_nofile liever in op 32.768 of hoger, zodat upstream-sockets hierin worden meegenomen. Voor kleine machines met twee kernen volstaan vaak 2048 verbindingen per worker, mits het aandeel van uploads en TLS gematigd blijft. De volgende tabel helpt bij het indelen van de Startwaarden:

CPU-kernen werker_processen worker_connections (Start) Min. rlimit_nofile (richtwaarde) Tip
2 auto (≈2) 2048 ≥ 4096 Reserve inplannen voor TLS/proxy
4 auto (≈4) 4096 ≥ 16384 Bij proxy's is de factor vaak 2 bij FD's
8 auto (≈8) 4096-8192 ≥ 32768 Belastingstest besluit over verhoging
16+ auto, eventueel minder 8192+ ≥ 65535 Met gevoel en terughoudendheid testen

NGINX-workers en upstreams: scenario’s op de juiste manier wegen

Ik maak onderscheid tussen statische levering, reverse-proxy-werking en API-gateway-belasting, omdat ze de Werknemer-configuratie stellen verschillende eisen. Statische inhoud verbruikt minder bronnen, terwijl TLS, compressie en upstream-verbindingen meer druk uitoefenen op de CPU en FD’s. Hoe groter de SSL-sleutels en hoe meer handshakes, hoe meer voordeel er te behalen valt met de instelling „één worker per kern“. Grote uploads verschuiven het profiel naar I/O, waardoor ik meer aandacht besteed aan rlimit_nofile en netwerkbuffers. Bij merkbare wachttijden bij het accepteren of bij backend-antwoorden helpt het overzicht mij om Wachtrijen en latentie, om knelpunten gericht op te lossen.

Workflow in de praktijk: stap voor stap naar een snellere server

Ik begin met een inventarisatie van alle relevante Waarden In het bestand nginx.conf controleer ik het aantal CPU-kernen, ulimit en de kernelparameters. Vervolgens stel ik worker_processes in op auto, stel ik worker_connections bijvoorbeeld in op 4096 en verhoog ik rlimit_nofile ruimschoots. In het Events-blok activeer ik epoll en multi_accept en controleer ik de logbestanden met een reload. Vervolgens voer ik belastingstests uit onder reproduceerbare omstandigheden, waarbij ik responstijden, foutpercentages en open verbindingen observeer. Bij de fijnafstemming wijzig ik altijd slechts één variabele, documenteer ik elke stap en controleer ik de effecten in de Metriek.

Hostingomgeving: bronnen, kernel, netwerk

Ik zorg ervoor dat er voldoende is CPU-Kernen, voldoende RAM, snelle SSD’s of NVMe en een recente Linux-kernel. Alleen zo werken epoll, moderne TCP-stacks en zinvolle offload-functies betrouwbaar. Netwerkparameters zoals somaxconn en tcp_max_syn_backlog pas ik aan het beoogde aantal verbindingen aan, om de wachtrijen voor inkomend verkeer kort te houden. Een provider met robuuste I/O-prestaties en vrij toegankelijke systeemconfiguratie loont zich hiervoor duidelijk. Uit vergelijkingen blijkt dat diensten met constante Bronnen De mogelijkheden van NGINX aanzienlijk vergroten.

Keepalive-strategie: client- en upstream-verbindingen

Ik gebruik Keepalive bewust als middel om de capaciteit en latentie te beïnvloeden. Aan de clientzijde gebruik ik keepalive_timeout niet te hoog, zodat inactieve sockets niet onnodig werker_verbindingen blokkeren. Waarden tussen 10 en 30 s bieden mij vaak een goed compromis tussen hergebruik en het vastleggen van middelen. Met keepalive_requests Ik beperk het aantal verzoeken per verbinding om langlopende verbindingen af te kappen en geheugendruk te voorkomen. Aan de upstream-zijde (reverse-proxy) onderhoud ik permanente verbindingen met keepalive in het upstream-blok, zodat handshakes en TCP-configuratie overbodig worden. Daarbij schaal ik het aantal per backend conservatief op basis van de backend-capaciteit (max_conns), anders maak ik zelf wachtrijen aan bij de upstream. Belangrijk: elke keepalive-socket telt als een open verbinding en heeft FD’s nodig; daar houd ik rekening mee in rlimit_nofile en mijn planning voor de headroom.

Lijstoptimalisatie: reuseport, backlog en acceptatiestrategie

Ik verdeel de opnamebelasting gelijkmatig door SO_REUSEPORT activeer (listen … reuseport). Elke worker beschikt daarmee over een eigen accept-queue, wat „thundering herds“ vermindert en hotspots voorkomt. In combinatie met multi_accept versnel ik de acceptatiefase merkbaar. De lijsten-achterstand (listen … backlog=) en de bijbehorende kernelinstellingen (somaxconn, tcp_max_syn_backlog) stel ik ruim in, zodat pieken niet verloren gaan bij de socket-ingang. De optie uitgesteld stelt Accept uit totdat de gegevens beschikbaar zijn – bij veel kortstondige verzoeken kan dat helpen; anders vergelijk ik het in tests. Of ik accept_mutex Wat ik nodig heb, bepaal ik aan de hand van de benchmark: met reuseport is het meestal overbodig; zonder reuseport kan het de eerlijkheid verbeteren, maar het vergt wel coördinatie. Hier neem ik een besluit op basis van gegevens, nooit op gevoel.

Time-outs en wachtrijen stabiel instellen

Ik stel Time-outs zodat trage clients de workers niet verstoppen: client_header_timeout en cliënt_lichaam_timeout Ik houd het kort genoeg om vertragingen te voorkomen, maar ruim genoeg voor echte gebruikers. send_timeout voorkomt dat antwoorden naar de client worden geblokkeerd. In de proxy-context definieer ik proxy_connect_timeout, proxy_read_timeout en proxy_send_timeout strikt, zodat de backends die daarmee samenhangen de frontend niet vertragen. Bij backends met beperkte parallelliteit gebruik ik wachtrij in het upstream-blok met een time-out, om pieken op te vangen en op een gecontroleerde manier een 503-fout te signaleren, in plaats van alle workers aan wachtende upstream-sockets te koppelen. Daarnaast zorg ik voor stabiliteit door limit_req (Burst/Delay) en limit_conn gevoelige paden, zodat individuele clients of bots niet onevenredig veel bronnen verbruiken.

Buffering, sendfile en AIO: bewust kiezen voor I/O-methoden

Ik stel sendfile voor statische bestanden en combineer dit met tcp_nopush/tcp_nodelay afhankelijk van de werklast, om pakketten efficiënt te bundelen of interactieve vertragingen te verminderen. Voor grote bestanden gebruik ik directio vanaf een bepaalde drempelwaarde, zodat cache-pollution wordt voorkomen en de paginacache niet wordt verdrongen. In de proxy-modus bepaal ik of proxy_buffering helpt (snelle overdracht naar de client, ontkoppeld lezen van de upstream) of dat ik bij streamingbelastingen liever proxy_request_buffering verklein, om uploads vroegtijdig te starten. De grootte van proxy_buffers, proxy_buffer_size en large_client_header_buffers Ik stuur dit bewust aan, zodat het geheugengebruik per verbinding niet explosief stijgt. Om de CPU te ontzien bij het openen van bestanden, overweeg ik aio (native of threads), maar test dit grondig, omdat de kenmerken van de event-loop en de I/O elkaar beïnvloeden.

HTTP/2/HTTP/3 en TLS: gevolgen voor de capaciteit van workers

Ik houd er rekening mee dat HTTP/2 en HTTP/3 De verbindingsdynamiek wijzigen: veel verzoeken worden uitgevoerd als Streams via een klein aantal TCP- of QUIC-verbindingen. Dit vermindert het aantal verbindingen, maar verhoogt het CPU- en geheugenverbruik per verbinding (multiplexing, headercompressie, TLS/QUIC). Mijn werker_verbindingen Ik interpreteer dit daarom niet zomaar als „evenveel verzoeken“. Ik merk op dat gelijktijdige streams per verbinding en pas keepalive_timeout en indien van toepassing. http2_max_concurrent_streams . Aan de TLS-kant profiteer ik van sessieherstel (tickets/cache) en OCSP-stapling; zo bespaar ik dure handshakes en houd ik de latentie laag. De keerzijde: langere keepalives leggen beslag op FD’s en RAM – dus plan ik rlimit_nofile en geheugencontingenten met realistische reserves. Voor CPU-intensieve versleutelingsalgoritmen loont het de moeite om affiniteit en moderne cryptografische versnelling te testen.

Monitoring: status, logbestanden en statistieken

Ik zorg voor transparantie met een gestroomlijnde Status-Endpoint (bijv. stub_status) om actieve verbindingen, Reading/Writing/Waiting en geaccepteerde verzoeken te bekijken. In de logbestanden houd ik de ruis beperkt: een compacte log_format met tijd, status, upstream-tijden en bytes is voldoende voor de meeste analyses. Bij een zeer hoge QPS schakel ik het toegangslogboek selectief uit (op basis van locatie) of sla ik logbestanden asynchroon op, zodat de I/O geen vertraging veroorzaakt. Het foutenlogboek stel ik in op waarschuw of fout en schakel alleen voor gerichte analyses tijdelijk over naar debug. Ik breng voortdurend de latenties (mediaan/95e/99e percentiel), open verbindingen, backend-foutpercentages en CPU-belasting per worker met elkaar in verband – op basis daarvan leid ik aanpassingen van de drie belangrijkste richtlijnen af en signaleer ik in een vroeg stadium verzadigingseffecten.

Containers en virtuele omgevingen: limieten netjes doorgeven

Ik controleer in containers de cgroup-Stel limieten in voor CPU, RAM en PID's en stem deze af op de NGINX-instellingen. ulimit -n moet binnen de container hoog genoeg zijn, anders hebben mijn aanpassingen aan rlimit_nofile geen zin. Bij CPU-quota’s (bijv. 2 vCPU’s) stel ik werker_processen Dienovereenkomstig, zodat de planning niet kunstmatig wordt versneld. Dicht bij het netwerk profiteer ik in „host“-netwerkmodi van een lagere overhead-latentie, terwijl overlays extra hops betekenen. Op Multi-NUMA-hosts let ik op affiniteit en geheugensockets, zodat workers niet over verschillende nodes heen werken. Hetzelfde geldt voor IRQ- en RPS/XPS-affiniteit: als de paden van de NIC via de IRQ naar de worker-kern kloppen, nemen de latentiepieken meetbaar af.

Verbindingslevenscyclus: tijdelijke poorten, TIME_WAIT en reserves

Ik plan voldoende tijdelijke poorten (ip_local_port_range), wanneer NGINX als actieve client naar upstreams fungeert. Bij een zeer hoge verbindingsdoorvoer voorkom ik overmatige poortfluctuatie met upstream-keepalive, waardoor TIME_WAIT-stacks kleiner worden. Ik maak slechts voorzichtig gebruik van kernel-toggles voor „Reuse“; moderne stacks optimaliseren veel zaken al intern. Het is stabieler om de levensduur van verbindingen te regelen via zinvolle keepalive- en timeout-waarden en hergebruik om te zorgen voor een eerlijke verdeling. Bij de capaciteitsberekening houd ik naast de clients altijd rekening met de upstream-kant – vaak zijn daar de FD’s de daadwerkelijke beperkende factor, niet de frontdoor.

Soepele herlaadbeurten en implementaties zonder onderbrekingen

Ik gebruik het master/worker-model voor soepele herlaadbeurten: De master laadt nieuwe configuraties; oude workers worden afgebroken, terwijl nieuwe het naadloos overnemen. Met worker_shutdown_timeout geef ik requests de tijd om netjes af te lopen, zonder resources te blokkeren. Zero-downtime-implementaties op de upstream koppel ik aan health checks en proxy_next_upstream-Regels om te voorkomen dat afzonderlijke defecte backends de algemene latentie doen stijgen. Bij configuratiewijzigingen pas ik altijd slechts één instelling aan en controleer ik de effecten in de logbestanden en statistieken – zo voorkom ik fouten door verwarring en zorg ik ervoor dat de prestaties reproduceerbaar blijven.

Beknopte samenvatting

Ik koppel werker_processen Stel het aantal kernen in (bij voorkeur automatisch), pas `worker_connections` aan op basis van de piekbelasting en verhoog `rlimit_nofile` en de OS-limieten ruimschoots. In het `events`-blok gebruik ik `epoll` en `multi_accept`, controleer ik alles met reproduceerbare belastingstests en pas ik vervolgens in kleine stapjes bij. Voor proxy-workloads houd ik rekening met extra descriptoren en test ik de CPU-affiniteit wanneer de workloads constant zijn. Een goed geconfigureerde stack met de juiste kernel, snelle I/O en zinvolle netwerkparameters maakt het verschil. Zo zorg ik ervoor dat NGINX betrouwbaar in het prestatiebereik dat veeleisende websites en API's nodig hebben.

Huidige artikelen