...

Korrekt brug af NGINX sendfile og tcp_nopush for at opnå maksimal ydeevne

Med nginx sendfile og tcp_nopush Jeg leverer statiske filer med »zero-copy« fra filsystemet til socket og reducerer dermed mærkbart både CPU-belastningen og antallet af pakker. Når de er indstillet korrekt, øger begge direktiver overførselseffektiviteten, mindsker overhead og danner grundlaget for en effektiv nginx-optimering af ressourcer og downloads.

Centrale punkter

  • Nul-kopi ved hjælp af sendfile: færre kopier, større gennemstrømning
  • tcp_nopush bufferer pakker: større rammer, mindre overhead
  • Kombination tæller: sendfile + tcp_nopush + tcp_nodelay
  • Brugsscenarier Prioritering: statiske ressourcer, store downloads
  • Test ved NFS/SMB: Mål effekten, og slå eventuelt sendfile fra

Hvorfor sendfile frigør så meget ydeevne for NGINX

Jeg aktiverer sendfile, fordi kernen kan sende filer direkte via netværksstakken uden at skulle tage en omvej via yderligere kopieringsoperationer i brugerrummet. Denne »zero-copy«-vej reducerer kontekstskift og sparer CPU-cyklusser, især når mange samtidige klienter henter statisk indhold. Store filer som billeder, CSS, JavaScript eller arkiver drager fordel af dette, fordi dataoverførslen foregår mere jævnt og med mindre overhead. Også systemcacherne fungerer mere effektivt, da der opstår færre hukommelsesbevægelser, og kernen styrer datastrømmen. Fordelen er mest tydelig på lokale filsystemer, og derfor måler jeg først der, før jeg overfører resultaterne til mere usædvanlige opsætninger.

Hvad tcp_nopush præcist gør, og hvornår det virkelig kommer til sin ret

Med tcp_nopush Jeg beder systemet om først at sende TCP-pakker, når de er fyldt på en fornuftig måde, i stedet for at sende små segmenter for tidligt. Under Linux svarer dette til TCP_CORK, under FreeBSD til TCP_NOPUSH, og i begge tilfælde falder antallet af pakker mærkbart. Direktivet reducerer ikke latenstiden til et minimum, men sigter mod et bedre forhold mellem nyttedata og overhead. Jeg bruger tcp_nopush målrettet til statiske filer, fordi sammenhængende datastrømme her giver de største effektivitetsgevinster. Uden sendfile har tcp_nopush ingen effekt, derfor integrerer jeg altid begge indstillinger sammen.

sendfile og tcp_nopush som par: Sådan lægger jeg grunden

Kombinationen af sendfile og tcp_nopush reducerer antallet af kopier og samler pakker, hvilket gør, at en server pr. CPU-kerne kan håndtere betydeligt flere parallelle overførsler. Jeg konfigurerer begge i http-kontekstniveauet og tilføjer ofte tcp_nodelay, så den sidste rest af en datastrøm kan løbe ud uden ventetid. Det er stadig vigtigt at teste med reel trafik, da pakkestørrelser, MTU og klienter varierer, og den bedste balance kan afvige lidt afhængigt af arbejdsbyrden. For statiske mapper er global aktivering som regel tilstrækkelig, mens jeg holder øje med virkningen ved dynamiske svarruter. Denne kombination giver et solidt fundament for yderligere nginx-optimeringstrin, som kommer senere.

direktiv Formål Typisk virkning Afhængighed
sendfile er aktiveret Zero-Copy fra fil til socket Mindre belastning af CPU’en, højere gennemstrømning Lokalt filsystem er ideelt
tcp_nopush aktiveret Fyld pakkerne, sænk omkostningerne Færre segmenter pr. fil Fungerer kun med sendfile
tcp_nodelay on Send de sidste bytes uden ventetid Hurtig afslutning af overførslen Tilføjet tcp_nopush

Sådan fungerer tcp_nodelay sammen med tcp_nopush

Jeg aktiverer tcp_nopush, for at sende starten af en overførsel i større pakker, og tillad samtidig tcp_nodelay, så afslutningen ikke går i stå. Begge indstillinger påvirker forskellige faser af datastrømmen og forstyrrer ikke hinanden, når NGINX leverer filer via sendfile. Især ved mange små filer forhindrer tcp_nodelay, at klienten venter unødigt på grund af små resterende datamængder. Jeg tester først kombinationen i staging, overvåger RTT’er og segmentstørrelser og sammenligner dem med live-metrikker. På den måde sikrer jeg effektivitet i starten og hurtighed i slutningen af overførslen.

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
}

Typiske anvendelsesscenarier: hvor direktiverne har stor indflydelse

Ved store Downloads Ligesom videoer, arkiver eller ISO-billeder reducerer kernels »zero-copy-path« CPU-tiden pr. overførsel markant. I CDN-lignende opsætninger med mange CSS-, JS- og fontfiler sparer tcp_nopush segmenter og øger dermed den anvendelige båndbredde pr. socket. På WordPress-sider med god caching vedrører de fleste anmodninger statiske ressourcer, hvorfor jeg meget hurtigt kan se effekten der. Også build-artefakter, container-images eller installationsprogrammer drager fordel heraf, forudsat at de ligger lokalt og ikke kommer via et ustabilt netværksfilsystem. Hvis man forventer belastningsspidser, kan man med denne kombination få meget stabilitet ud af den eksisterende hardware.

Praktisk eksempel: NGINX til WordPress med caching og ressourcer

I WordPress-opsætninger indsætter jeg sendfile, tcp_nopush og tcp_nodelay globalt, leverer statiske ressourcer direkte og holder PHP-FPM adskilt fra dynamiske stier. Jeg tilføjer relevante cache-headere til billeder, CSS og JavaScript, så browsere foretager færre roundtrips. Når jeg leverer streaming-lignende svar, tager jeg højde for interaktionen med buffering og tester, hvordan chunk-størrelser påvirker latenstid og gennemstrømning; dette passer godt sammen med oversigten over Streaming af svar i bidder. Til tekstbaseret indhold anvender jeg komprimering uden at pakke binære filer unødigt. På den måde forbliver anmodningsstrømmen stabil, CPU’en aflastet og tiden til første byte kort.

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

 keepalive_timeout 65;
    gzip on;
    gzip_types text/css application/javascript image/svg+xml;

    server {
 listen 80;
 server_name blog.example.com;
 root /var/www/blog;

 location / {
 try_files $uri $uri/ /index.php?$args;
 }

        location ~ \.php$ {
 include fastcgi_params;
 fastcgi_pass unix:/run/php/php-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 }

 location ~* \.(jpg|jpeg|png|gif|css|js|ico|svg|woff2?)$ {
 expires 30d;
 add_header Cache-Control "public, max-age=2592000";
 }
    }
}

Når jeg bevidst deaktiverer sendfile

Jeg skifter sendfile hvis filerne ligger på NFS, SMB eller distribuerede filsystemer, som i min test giver dårligere gennemstrømning. Visse drivere eller forsinkelser i lagringsstien kan ophæve fordelen ved zero-copy, hvorfor målinger er afgørende. Ved sporadiske netværksproblemer deaktiverer jeg først tcp_nopush for at indkredse årsagerne, før jeg selv undersøger sendfile. Også usædvanlige kernel-bugs eller ældre stakke kan være grunde til midlertidigt at skifte til den klassiske læse-skrive-sti. Det er vigtigt at implementere ændringer trinvist og underbygge dem med målinger.

Fejlkilder, som jeg holder øje med

Jeg tjekker først, om tcp_nopush er aktiveret ved en fejl, mens sendfile forbliver deaktiveret, da indstillingen i så fald ikke har nogen effekt. Ved dynamiske stier holder jeg øje med, om yderligere buffering øger latenstiden, og afvejer fordelene i forhold til responstiden. På netværk med høj latenstid måler jeg, om større pakker virkelig hjælper, eller om jeg skal finjustere segmentstørrelser og keep-alive. Også MTU-konfigurationen og netværkskortets offloading-funktioner kan synligt påvirke resultatet. Overskuelige logfiler, pcap-prøver og korrelerede systemmetrikker viser mig hurtigt, hvor jeg skal foretage justeringer.

En helhedsorienteret tilgang til NGINX-ydeevne: yderligere justeringsmuligheder

Ud over sendfile Det lønner sig at indstille det korrekte antal worker_processes og worker_connections, så jeg ikke kunstigt begrænser antallet af sockets. Under Linux bruger jeg epoll og sørger for tilstrækkelige filbeskrivere, så belastningsspidser ikke fører til flaskehalse. For tekstindhold aktiverer jeg gzip eller Brotli og tester, om komprimeringsniveauet belaster CPU’en på en fornuftig måde. På transportniveau holder jeg forbindelserne åbne længere og optimerer Keep-Alive, hvilket vejledningen Keep-Alive-tuning giver praktiske retningslinjer. TLS, genbrug af sessioner samt HTTP/2 eller HTTP/3 fuldender opsætningen og understøtter høj parallelitet med moderat latenstid.

Begrænsninger og særlige tilfælde: TLS, HTTP/2/3 og proxying

Jeg tager højde for, at sendfile gælder teknisk set kun for ukrypterede filstier eller specifikke kernefunktioner. Ved klassisk TLS krypterer NGINX bytes i brugerrummet, hvorfor fordelen ved zero-copy bortfalder; moderne kerneler kan delvist flytte krypteringen ind i kernelen, hvilket gendanner effekten, men dette er ikke tilgængeligt i alle opsætninger. Ved HTTP/2 Dataene ligger i frames, flere svar deler en TCP-forbindelse, og NGINX ompakker aktivt bytes – her er sendfile mindre relevant. HTTP/3 er baseret på UDP/QUIC og følger igen andre regler, så jeg snarere opnår effektivitetsgevinster gennem buffere, overbelastningskontrol og korrekt valgte chunk-størrelser. Som Omvendt proxy sendfile fungerer kun, hvis jeg rent faktisk serverer filer fra det lokale filsystem; svar fra proxy_pass eller fastcgi_pass De passerer alligevel gennem brugerrummet. Derfor adskiller jeg assets strengt fra den dynamiske sti, så zero-copy-metoden udnyttes maksimalt.

Sådan vælger du den rigtige komprimering: gzip/Brotli kontra gzip_static

Når NGINX komprimerer indhold i realtid, skal det læse filen, behandle den og skrive resultatet – og i den forbindelse går sendfile sin fordel. Til statiske ressourcer bruger jeg derfor, hvor det er muligt, forhåndskomprimeret Filer (f.eks. .gz eller .br) og lader dem leveres direkte. På den måde bevares Zero-Copy-stien, fordi NGINX kan videregive den forkomprimerede fil på samme måde som ethvert andet medie. For teksttunge indholdselementer, der sjældent ændres, opnår jeg på denne måde CPU-besparelser og stabil gennemstrømning uden at gå på kompromis med overførselstiden. Ved binære filer og allerede komprimerede formater undgår jeg enhver komprimering under kørsel – her tæller ren I/O-gennemstrømning, og sendfile samt tcp_nopush udnytter deres styrker fuldt ud.

AIO, directio og Page Cache: Mønstre for små og store filer

Jeg kombinerer sendfile med asynkron I/O og direkte diskadgang for at opnå det optimale resultat afhængigt af filstørrelsen. Små til mellemstore filer drager fordel af kernels sidecache og forbliver på sendfile-stien. Meget store filer kan derimod fortrænge cachen; i så fald læser jeg dem målrettet med Direktion uden for cachen og arbejder med AIO-tråde. På den måde aflaster jeg hukommelsen og holder ventetiden lav for andre anmodninger. Et typisk mønster ser sådan ud:

http {
    # Standardsti: Zero-Copy fra sidecachen
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

 # Store filer: uden om cachen og asynkron læsning
    aio threads;
    directio 4m; # gælder kun for filer >= 4 MiB
    output_buffers 1 512k;    # Buffer til directio-stier
    sendfile_max_chunk 1m;    # Retfærdighed under høj belastning
}

Med denne differentiering forbliver små filer ekstremt effektive, mens meget store overførsler ikke overbelaster arbejdshukommelsen. Vigtigt: directio deaktiverer sendfile-stien for de berørte filer – og det er præcis, hvad jeg har til hensigt i forbindelse med anvendelsen af store filer.

Retfærdighed og strømningskontrol under belastning

I perioder med høj belastning vil jeg gerne undgå, at en enkelt stream monopoliserer CPU’en eller soklen. Jeg indstiller sendfile_max_chunk, så NGINX returnerer kontrollen til kernen efter en bestemt mængde bytes og giver plads til andre forbindelser. Til båndbreddestyring hjælper limit_rate og limit_rate_after, f.eks. for at begrænse bulk-downloads, mens UI-elementer forbliver hurtige. Med udsæt_output Jeg styrer, fra hvilken svarstørrelse NGINX begynder at sende – i kombination med tcp_nopush sikrer jeg dermed pæne pakkeopdelinger. Derudover er jeg opmærksom på lingering_close, så de resterende pakker kan afvikles korrekt, og soklen ikke afbrydes brat.

Filsystemer, readahead og lagringsstier

Fordi sendfile Når man bruger sidecaches, spiller det underliggende filsystem en stor rolle. Jeg tjekker readahead-værdierne og indstiller dem således, at sekventielle læseoperationer på store filer ikke går i stå, uden at det går ud over de mindre filer. På ext4 eller xfs Jeg observerer, hvor godt prefetching og I/O-scheduler passer til mit gennemstrømningsmønster. På netværksfiler (NFS/SMB) tester jeg rsize/wsize, caching og latenstider grundigt, fordi selv små afvigelser neutraliserer Zero-Copy-fordelen. Min regel er stadig: Først skal de lokale stier udnyttes maksimalt, derefter skal eksterne stakke justeres forsigtigt – og måleværdier skal altid veje tungere end mavefornemmelsen.

Pragmatisk tilpasning af netværksstakken og NIC-offloading

Ved et stort antal forbindelser stoler jeg på den automatiske buffertilpasning i moderne stakke, men justerer sende- og modtagelsesbufferne efter behov. NIC-offloads som TSO, GSO og GRO reducerer CPU-belastningen mærkbart; i målinger er jeg dog forsigtig, da pakkeoptagelser kan virke forvrængede på grund af offloading (tilsyneladende få, meget store segmenter). Derfor korrelerer jeg pcap‑Traces med målinger fra NGINX og kernen for at skelne mellem reelle netværksstørrelser og offload-artefakter. Ved latenstops afbryder jeg kortvarigt testene med deaktiverede offloads, dokumenterer forskellen og beslutter derefter, hvad der giver størst fordel i kontinuerlig drift.

Konfigurationsskabeloner pr. lokation: målrettet aktivering og deaktivering

Jeg holder muligheden åben for, sendfile afhængigt af stien eller filtypen. For statiske mapper forbliver den aktiveret, mens jeg for streaming- eller dynamiske stier slår den selektivt fra, når buffere eller filtre (f.eks. komprimering) har forrang. Et kort eksempel:

server {
    listen 80;
    server_name static.example.com;
    root /var/www/static;

 # Statiske ressourcer: Zero-Copy
    location /assets/ {
 sendfile on;
 tcp_nopush on;
        tcp_nodelay on;
 expires 7d;
    }

 # Dynamik eller streaming: Fleksibilitet frem for Zero-Copy
    location /api/ {
 sendfile off;
 proxy_pass http://app_upstream;
    }
}

Denne adskillelse forhindrer, at jeg mister fordele på den ene side, blot fordi en anden vej stiller særlige krav.

Range, Slices og store kataloger

Når det drejer sig om store objekter, spiller Rækkevidde-anmodninger udnytter deres styrker: Klienten indlæser kun de nødvendige dele, og forbindelserne forbliver stabile. I indholdskataloger med meget store filer foretrækker jeg at opdele overførslerne logisk – serverbelastningen fordeles mere jævnt, og fejl som afbrud koster mindre tid. I caching-scenarier forebygger jeg „Thundering Herds“ ved at buffe svarene på en fornuftig måde, men uden kunstigt at tilbageholde små chunks og restdata. Samspillet med tcp_nopush er her afgørende: Jeg holder de indledende segmenter store, men lader ikke slutningen vente.

Måle- og teststrategi: Pålidelig påvisning af effekter

Jeg underbygger optimeringer med reproducerbare tests. På serversiden overvåger jeg CPU-profiler, $request_time, 1 TP 4 Tbyte sendt, aktive forbindelser og kontekstskift. På netværket måler jeg segmentstørrelser, retransmissioner og RTT-fordeling; jeg korrelerer pakkefangster med socket-statistikker for at tage højde for offload-effekter. På klientsiden sammenligner jeg TTFB, First Contentful Paint og downloadtider under realistiske RTT-værdier og båndbredder. Jeg varierer MTU, Keep-Alive-indstillinger og filstørrelser, så jeg ikke kun ser »best-case«-kurver. Til sidst beslutter jeg på baggrund af konkrete tal, om sendfile/tcp_nopush leverer den ønskede stabilitet og effektivitet i den pågældende arbejdsbelastning – og finjusterer, indtil det er tilfældet.

HTTP-detaljer, der gør en forskel: Range og streaming

Jeg bruger Rækkevidde-Anmodninger ved store filer, så klienterne kun henter de nødvendige dele, og forbindelserne forbliver stabile. Især ved video-spoling og genoptagelse af opdateringer hjælper en velfungerende understøttelse af byterange med at fordele båndbredden hensigtsmæssigt; yderligere oplysninger findes på siden om HTTP-Range-anmodninger. For løbende svar med en voksende brødtekst tester jeg streaming-strategier og sørger for, at buffere ikke utilsigtet holder fast i dataene for længe. I den forbindelse respekterer jeg cacher og indsætter relevante headere, så proxyservere og browsere fungerer korrekt. Jeg tager højde for samspillet med tcp_nopush, da pakkestørrelser og timingen af flush har direkte indflydelse på den oplevede hastighed.

Kort opsummeret

Med sendfile Jeg videresender filer effektivt direkte til kernen, og med tcp_nopush sørger jeg for, at pakkerne udfyldes optimalt, inden de belaster forbindelsen. Begge direktiver supplerer hinanden, mens tcp_nodelay leverer den sidste restbyte uden forsinkelse. Jeg tester effekten under reel trafik, holder øje med lagringssti, MTU, Keep-Alive og komprimering og foretager konsekvente målinger. For WordPress- og CDN-lignende arbejdsbelastninger viser fordelene sig særligt hurtigt, fordi mange anmodninger vedrører statiske ressourcer. Den, der anvender indstillingerne målrettet, opnår større gennemstrømning pr. kerne, reducerer overhead og skaber reserver til reelle vækstspidser.

Aktuelle artikler

Linux-webserver med flere netværksforbindelser i et datacenter
Plesk webserver

SO_REUSEPORT under Linux: Bedre ydeevne til webservere

Find ud af, hvordan SO_REUSEPORT forbedrer din webservers ydeevne i Linux. Lær, hvordan denne socket-indstilling fungerer, og hvordan du bruger den i Nginx og andre tjenester.