Mit nginx sendfile und tcp_nopush liefere ich statische Dateien Zero-Copy vom Dateisystem zum Socket aus und drücke so CPU-Last wie Paketanzahl spürbar nach unten. Richtig eingestellt heben beide Direktiven die Effizienz der Übertragung an, senken Overhead und legen die Basis für eine saubere nginx optimization bei Assets und Downloads.
Zentrale Punkte
- Zero-Copy durch sendfile: weniger Kopien, mehr Durchsatz
- tcp_nopush puffert Pakete: größere Frames, weniger Overhead
- Kombination zählt: sendfile + tcp_nopush + tcp_nodelay
- Use-Cases priorisieren: statische Assets, große Downloads
- Tests bei NFS/SMB: Wirkung messen, notfalls sendfile off
Warum sendfile für NGINX so viel Leistung freilegt
Ich aktiviere sendfile, weil der Kernel Dateien direkt über den Netzwerk-Stack senden kann, ohne den Umweg über zusätzliche Kopieroperationen im Userspace zu gehen. Dieser Zero-Copy-Pfad reduziert Kontextwechsel und spart CPU‑Zyklen, besonders wenn viele gleichzeitige Clients statische Inhalte abrufen. Große Dateien wie Images, CSS, JavaScript oder Archive profitieren, weil der Datentransfer gleichmäßiger und mit weniger Overhead läuft. Auch die Systemcaches wirken effizienter, da weniger Speicherbewegungen entstehen und der Kernel den Weg der Daten steuert. Auf lokalen Dateisystemen zeigt sich der Gewinn am deutlichsten, weshalb ich zuerst dort messe, bevor ich auf exotische Setups übertrage.
Was tcp_nopush genau macht und wann es glänzt
Mit tcp_nopush bitte ich das System, TCP‑Pakete erst zu senden, wenn sie sinnvoll gefüllt sind, anstatt zu früh kleine Segmente zu verschicken. Unter Linux entspricht das TCP_CORK, unter FreeBSD TCP_NOPUSH, und in beiden Fällen sinkt die Paketanzahl messbar. Die Direktive hebt nicht die Latenz auf ein Minimum, sie zielt auf ein besseres Verhältnis zwischen Nutzdaten und Overhead. Ich setze tcp_nopush gezielt bei statischen Dateien ein, weil dort zusammenhängende Datenströme am meisten Effizienzgewinne liefern. Ohne sendfile bleibt tcp_nopush wirkungslos, daher binde ich beide Einstellungen immer gemeinsam ein.
sendfile und tcp_nopush als Doppel: so setze ich die Basis
Die Kombination aus sendfile und tcp_nopush reduziert Kopien und bündelt Pakete, wodurch ein Server pro CPU‑Kern deutlich mehr parallele Transfers stemmen kann. Ich konfiguriere beide in der http‑Kontextstufe und ergänze oft tcp_nodelay, damit der letzte Rest eines Flows ohne Wartezeit abfließt. Wichtig bleibt das Testen mit Real‑Traffic, da Paketgrößen, MTU und Clients variieren und die beste Balance je nach Workload leicht abweichen kann. Für statische Verzeichnisse genügt meist die globale Aktivierung, während ich bei dynamischen Antwortrouten auf die Auswirkung achte. Der Mix liefert ein solides Fundament für weitere nginx optimization Schritte, die später obenauf kommen.
| Direktive | Zweck | Typische Wirkung | Abhängigkeit |
|---|---|---|---|
| sendfile on | Zero-Copy von Datei zum Socket | Weniger CPU-Last, höherer Durchsatz | Lokales Dateisystem ideal |
| tcp_nopush on | Pakete füllen, Overhead senken | Weniger Segmente pro Datei | Wirkt nur mit sendfile |
| tcp_nodelay on | Letzte Bytes ohne Warten senden | Schneller Abschluss der Übertragung | Ergänzt tcp_nopush |
So spielt tcp_nodelay mit tcp_nopush zusammen
Ich aktiviere tcp_nopush, um den Anfang eines Transfers in größeren Paketen zu senden, und lasse tcp_nodelay gleichzeitig zu, damit der Abschluss nicht hängen bleibt. Beide Einstellungen wirken auf unterschiedliche Phasen des Flows und behindern sich nicht, wenn NGINX Dateien via sendfile liefert. Gerade bei vielen kleinen Dateien verhindert tcp_nodelay, dass der Client wegen kleiner Restdaten unnötig wartet. Ich teste die Kombination zuerst in Staging, beobachte RTTs und Segmentgrößen, und gleiche sie mit Live‑Metriken ab. So sichere ich mir Effizienz am Anfang und Schnelligkeit am Ende der Übertragung.
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
}
Typische Einsatzszenarien: wo die Direktiven stark wirken
Bei großen Downloads wie Videos, Archiven oder ISO‑Images reduziert der Zero‑Copy‑Pfad des Kernels die CPU‑Zeit pro Transfer deutlich. In CDN‑ähnlichen Setups mit vielen CSS‑, JS‑ und Font‑Dateien spart tcp_nopush Segmente ein und steigert so die nutzbare Bandbreite pro Socket. Auf gut gecachten WordPress‑Seiten fallen die meisten Requests auf statische Assets, weshalb ich den Effekt dort sehr schnell sehe. Auch Build‑Artefakte, Container‑Images oder Installer profitieren, sofern sie lokal liegen und nicht über ein wackliges Netzwerk‑FS kommen. Wer Lastspitzen erwartet, holt mit diesem Duo viel Stabilität aus der vorhandenen Hardware heraus.
Praxisbeispiel: NGINX für WordPress mit Caching und Assets
In WordPress‑Setups setze ich sendfile, tcp_nopush und tcp_nodelay global, liefere statische Ressourcen direkt aus und halte PHP‑FPM für dynamische Pfade sauber getrennt. Ich ergänze sinnvolle Cache‑Header für Bilder, CSS und JavaScript, damit Browser weniger Roundtrips verursachen. Wenn ich streaming‑artige Antworten liefere, beachte ich die Interaktion mit Pufferung und teste, wie sich Chunk‑Größen auf Latenz und Durchsatz auswirken; dazu passt der Überblick zu Response-Streaming in Chunks. Für textbasierte Inhalte ziehe ich Kompression hinzu, ohne Binärdateien unnötig zu packen. So bleibt der Request‑Flow stabil, die CPU entspannt und die Time‑to‑First‑Byte kurz.
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";
}
}
}
Wann ich sendfile bewusst deaktiviere
Ich schalte sendfile aus, wenn Dateien über NFS, SMB oder verteilte Dateisysteme liegen, die in meinem Test schlechtere Durchsätze liefern. Manche Treiber oder Latenzen im Storage‑Pfad machen den Zero‑Copy‑Vorteil zunichte, weshalb Messungen den Ton angeben. Bei sporadischen Netzwerk‑Eigenheiten drehe ich zuerst tcp_nopush ab, um Effekte einzugrenzen, bevor ich sendfile selbst hinterfrage. Auch ungewöhnliche Kernel‑Bugs oder ältere Stacks können Gründe sein, temporär auf den klassischen Lese‑Schreib‑Pfad zu wechseln. Wichtig bleibt, Änderungen schrittweise einzuspielen und mit Metriken zu belegen.
Fehlerquellen, die ich im Blick behalte
Ich prüfe zuerst, ob tcp_nopush versehentlich aktiv ist, während sendfile aus bleibt, denn dann zeigt die Einstellung keine Wirkung. Für dynamische Pfade beobachte ich, ob zusätzliche Pufferungen die Latenz hochtreiben und wäge den Nutzen gegen die Reaktionszeit ab. Bei High‑Latency‑Netzen messe ich, ob größere Pakete wirklich helfen oder ob ich an Segmentgrößen und Keep‑Alive feilen muss. Auch die MTU‑Konfiguration und Offloading‑Features der Netzwerkkarte können das Ergebnis sichtbar verschieben. Saubere Logs, pcap‑Samples und korrelierte Systemmetriken zeigen mir schnell, wo ich nachjustiere.
NGINX-Performance ganzheitlich denken: weitere Stellschrauben
Neben sendfile zahlt sich die korrekte Zahl an worker_processes und worker_connections aus, damit ich Sockets nicht künstlich limitiere. Unter Linux nutze ich epoll und sorge für ausreichend File‑Deskriptoren, damit Lastspitzen nicht zu Engpässen führen. Für Textinhalte aktiviere ich gzip oder Brotli und teste, ob die Kompressionsstufe die CPU sinnvoll belastet. Auf der Transportebene halte ich Verbindungen länger offen und optimiere Keep‑Alive, wozu der Leitfaden Keep-Alive-Tuning praktische Anhaltspunkte liefert. TLS, Session‑Wiederverwendung und HTTP/2 oder HTTP/3 runden das Setup ab und unterstützen hohe Parallelität mit moderater Latenz.
Grenzen und Sonderfälle: TLS, HTTP/2/3 und Proxying
Ich berücksichtige, dass sendfile technisch nur für unverschlüsselte Dateipfade oder spezielle Kernel‑Funktionen greift. Bei klassischem TLS verschlüsselt NGINX die Bytes im Userspace, weshalb der Zero‑Copy‑Vorteil entfällt; moderne Kernel können Verschlüsselung teilweise in den Kernel verlagern, was den Effekt zurückbringt, aber nicht in jedem Setup verfügbar ist. Bei HTTP/2 liegen Daten in Frames, mehrere Antworten teilen sich eine TCP‑Verbindung, und NGINX packt die Bytes aktiv um – hier ist sendfile weniger relevant. HTTP/3 basiert auf UDP/QUIC und folgt wieder anderen Regeln, sodass ich Effizienzgewinne eher über Puffer, Congestion-Control und korrekt gewählte Chunk‑Größen erziele. Als Reverse Proxy greift sendfile nur, wenn ich tatsächlich Dateien vom lokalen Dateisystem serviere; Antworten aus proxy_pass oder fastcgi_pass durchlaufen ohnehin den Userspace. Ich trenne deshalb Assets strikt vom dynamischen Pfad, damit der Zero‑Copy‑Weg maximal genutzt wird.
Kompression richtig einordnen: gzip/Brotli versus gzip_static
Sobald NGINX Inhalte on‑the‑fly komprimiert, muss es die Datei lesen, verarbeiten und das Ergebnis schreiben – dabei verliert sendfile seinen Vorteil. Für statische Assets nutze ich daher, wo möglich, vorab komprimierte Dateien (z. B. .gz oder .br) und lasse sie direkt ausliefern. So bleibt der Zero‑Copy‑Pfad erhalten, weil NGINX die vorkomprimierte Datei wie jedes andere Asset übergeben kann. Für textlastige, selten geänderte Inhalte erreiche ich so CPU‑Ersparnis und stabilen Durchsatz, ohne an Übertragungszeit einzubüßen. Bei Binärdateien und bereits komprimierten Formaten spare ich mir jede Laufzeitkompression – hier zählt reiner I/O‑Durchsatz, und sendfile plus tcp_nopush spielen ihre Stärken aus.
AIO, directio und Page Cache: Muster für kleine und große Dateien
Ich kombiniere sendfile mit asynchronem I/O und direktem Plattenzugriff, um je nach Dateigröße das Optimum zu erreichen. Kleine bis mittlere Dateien profitieren vom Page Cache des Kernels und bleiben auf dem sendfile‑Pfad. Sehr große Dateien können den Cache hingegen verdrängen; dann lese ich sie gezielt mit directio außerhalb des Caches und arbeite mit AIO‑Threads. Dadurch entlaste ich den Speicher und halte die Latenz für andere Requests niedrig. Ein typisches Muster sieht so aus:
http {
# Standardpfad: Zero-Copy aus dem Page Cache
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# Große Dateien: am Cache vorbei und asynchron lesen
aio threads;
directio 4m; # greift nur für Dateien >= 4 MiB
output_buffers 1 512k; # Puffer für directio-Pfade
sendfile_max_chunk 1m; # Fairness unter hoher Last
}
Mit dieser Staffelung bleiben kleine Assets extrem effizient, während sehr große Transfers den Arbeitsspeicher nicht fluten. Wichtig: directio schaltet für betroffene Dateien den sendfile‑Pfad ab – genau so beabsichtige ich es für den Großdatei‑Use‑Case.
Fairness und Flusskontrolle unter Last
In Hochlastphasen möchte ich vermeiden, dass ein einziger Stream die CPU oder den Socket monopolisiert. Ich setze sendfile_max_chunk, damit NGINX den Kernel nach einer definierten Byte‑Menge zurückgibt und anderen Verbindungen Luft lässt. Für Bandbreitenlenkung helfen limit_rate und limit_rate_after, etwa um Bulk‑Downloads zu drosseln, während UI‑Assets flott bleiben. Mit postpone_output steuere ich, ab welcher Antwortgröße NGINX das Senden beginnt – in Kombination mit tcp_nopush sorge ich so für saubere Paketzuschnitte. Zusätzlich achte ich auf lingering_close, damit verbleibende Pakete sauber abfließen und der Socket nicht abrupt terminiert wird.
Dateisysteme, Readahead und Storage-Pfade
Weil sendfile die Seitencaches nutzt, spielt das zugrunde liegende Dateisystem eine große Rolle. Ich prüfe Readahead‑Werte und halte sie so, dass sequentielle Lesezüge von großen Dateien nicht ins Stocken geraten, ohne kleinere Assets zu verdrängen. Auf ext4 oder xfs beobachte ich, wie gut Prefetching und I/O‑Scheduler mit meinem Durchsatzmuster harmonieren. Auf Netzwerk‑FS (NFS/SMB) teste ich rsize/wsize, Caching und Latenzen streng, weil schon kleine Abweichungen den Zero‑Copy‑Vorteil neutralisieren. Meine Regel bleibt: erst lokale Pfade maximal ausreizen, dann externe Stacks vorsichtig justieren – und Messwerte immer vor Bauchgefühl stellen.
Netzwerk-Stack und NIC-Offloading pragmatisch abstimmen
Für hohe Verbindungszahlen verlasse ich mich auf die automatische Pufferanpassung moderner Stacks, passe aber bei Bedarf Sende‑ und Empfangspuffer an. NIC‑Offloads wie TSO, GSO und GRO senken CPU‑Last spürbar; in Messungen prüfe ich allerdings mit Bedacht, weil Packet‑Captures durch Offloading verfälscht wirken können (scheinbar wenige, sehr große Segmente). Ich korreliere deshalb pcap‑Traces mit Metriken aus NGINX und dem Kernel, um echte Drahtgrößen von Offload‑Artefakten zu trennen. Für Latenzspitzen unterbreche ich Tests kurz mit deaktivierten Offloads, dokumentiere den Unterschied und entscheide dann, was im Dauerbetrieb mehr Nutzen bringt.
Konfigurationsmuster pro Location: gezielt an- und abschalten
Ich halte mir die Option offen, sendfile je nach Pfad oder Dateityp zu überschreiben. Für statische Verzeichnisse bleibt es an, für Streaming‑ oder dynamische Pfade schalte ich es selektiv aus, wenn Puffer oder Filter (z. B. Kompression) Vorrang haben. Ein kurzes Muster:
server {
listen 80;
server_name static.example.com;
root /var/www/static;
# Statische Assets: Zero-Copy
location /assets/ {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
expires 7d;
}
# Dynamik oder Streaming: Flexibilität vor Zero-Copy
location /api/ {
sendfile off;
proxy_pass http://app_upstream;
}
}
Diese Trennung verhindert, dass ich Vorteile auf der einen Seite verliere, nur weil ein anderer Pfad spezielle Anforderungen stellt.
Range, Slices und große Kataloge
Bei großen Objekten spielen Range-Requests ihre Stärken aus: Der Client lädt nur benötigte Teile, und Verbindungen bleiben stabil. In Content‑Katalogen mit sehr großen Dateien segmentiere ich Transfers gerne logisch – die Serverlast verteilt sich gleichmäßiger, und Fehlerfälle wie Abbrüche kosten weniger Zeit. In Caching‑Szenarien beuge ich „Thundering Herds“ vor, indem ich Antworten sinnvoll puffer, aber kleine Chunks und Restdaten nicht künstlich festhalte. Das Zusammenspiel mit tcp_nopush bleibt dabei zentral: Ich halte Anfangssegmente groß, lasse das Ende aber nicht warten.
Mess- und Teststrategie: Effekte belastbar nachweisen
Ich belege Optimierungen mit reproduzierbaren Tests. Auf Serverseite beobachte ich CPU‑Profile, $request_time, $bytes_sent, aktive Verbindungen und Kontextwechsel. Im Netz messe ich Segmentgrößen, Retransmits und RTT‑Verteilung; Packet‑Captures korreliere ich mit Socket‑Statistiken, um Offload‑Effekte zu berücksichtigen. Auf Clientseite vergleiche ich TTFB, First Contentful Paint und Downloadzeiten unter realistischen RTTs und Bandbreiten. Ich variiere MTU, Keep‑Alive‑Einstellungen und Dateigrößen, damit ich nicht nur Best‑Case‑Kurven sehe. Am Ende entscheide ich anhand harter Zahlen, ob sendfile/tcp_nopush im jeweiligen Workload die gewünschte Stabilität und Effizienz liefern – und passe fein an, bis sie es tun.
HTTP-Details, die den Unterschied machen: Range und Streaming
Ich nutze Range-Requests bei großen Dateien, damit Clients nur benötigte Teile nachladen und Verbindungen stabil bleiben. Gerade bei Video‑Vorsprüngen und Update‑Resumes hilft ein sauberer Support der Byteranges, den Durchsatz sinnvoll zu verteilen; Hintergrundinfos liefert die Seite zu HTTP-Range-Requests. Für fortlaufende Antworten mit wachsendem Body teste ich Streaming‑Strategien und sorge dafür, dass Puffer nicht unabsichtlich zu lange festhalten. Dabei respektiere ich Caches und setze sinnvolle Header, damit Proxies und Browser korrekt handeln. Die Wechselwirkung mit tcp_nopush beachte ich, weil Paketgrößen und das Timing des Flushs direkten Einfluss auf wahrgenommene Schnelligkeit haben.
Kurz zusammengefasst
Mit sendfile leite ich Dateien effizient direkt an den Kernel weiter, und mit tcp_nopush lasse ich die Pakete sinnvoll füllen, bevor sie die Leitung belasten. Beide Direktiven ergänzen sich, während tcp_nodelay den letzten Byte‑Rest ohne Verzögerung ausliefert. Ich prüfe die Wirkung unter Real‑Traffic, achte auf Storage‑Pfad, MTU, Keep‑Alive und Kompression und messe konsequent. Für WordPress‑ und CDN‑artige Workloads zeigt sich der Nutzen besonders schnell, weil viele Requests auf statische Assets fallen. Wer die Einstellungen gezielt einsetzt, holt mehr Durchsatz pro Kern, senkt Overhead und schafft Reserven für echte Wachstumsspitzen.


