Con nginx sendfile e tcp_nopush Trasmetto i file statici in modalità zero-copy dal file system al socket, riducendo così in modo tangibile sia il carico della CPU che il numero di pacchetti. Se configurate correttamente, entrambe le direttive aumentano l'efficienza della trasmissione, riducono l'overhead e gettano le basi per un'ottimizzazione efficace di nginx per quanto riguarda le risorse e i download.
Punti centrali
- Copia zero tramite sendfile: meno copie, maggiore velocità di trasmissione
- tcp_nopush memorizza i pacchetti: frame più grandi, meno overhead
- Combinazione conta: sendfile + tcp_nopush + tcp_nodelay
- Casi d'uso dare priorità a: risorse statiche, download di grandi dimensioni
- Test per NFS/SMB: misurare l'effetto, se necessario disattivare sendfile
Perché sendfile migliora così tanto le prestazioni di NGINX
Attivo sendfile, poiché il kernel è in grado di inviare i file direttamente tramite lo stack di rete, senza dover ricorrere a ulteriori operazioni di copia nello spazio utente. Questo percorso “zero-copy” riduce i cambi di contesto e risparmia cicli di CPU, soprattutto quando molti client contemporanei recuperano contenuti statici. I file di grandi dimensioni come immagini, CSS, JavaScript o archivi ne traggono vantaggio, poiché il trasferimento dei dati avviene in modo più uniforme e con un overhead minore. Anche le cache di sistema risultano più efficienti, poiché si verificano meno movimenti di memoria e il kernel controlla il percorso dei dati. Il vantaggio è più evidente sui file system locali, motivo per cui effettuo le misurazioni innanzitutto lì, prima di estenderle a configurazioni più particolari.
Cosa fa esattamente tcp_nopush e in quali casi dà il meglio di sé
Con tcp_nopush Chiedo al sistema di inviare i pacchetti TCP solo quando sono riempiti in modo sensato, invece di inviare segmenti piccoli troppo presto. Su Linux ciò corrisponde a TCP_CORK, su FreeBSD a TCP_NOPUSH, e in entrambi i casi il numero di pacchetti diminuisce in modo misurabile. La direttiva non riduce la latenza al minimo, ma mira a ottenere un miglior rapporto tra dati utili e overhead. Utilizzo tcp_nopush in modo mirato per i file statici, poiché è proprio in questo contesto che i flussi di dati contigui garantiscono i maggiori guadagni in termini di efficienza. Senza sendfile, tcp_nopush rimane inefficace, pertanto integro sempre entrambe le impostazioni insieme.
sendfile e tcp_nopush in coppia: ecco come imposto le basi
La combinazione di sendfile e tcp_nopush riduce le copie e raggruppa i pacchetti, consentendo così a un server per ogni core della CPU di gestire un numero significativamente maggiore di trasferimenti paralleli. Configuro entrambi a livello di contesto http e spesso aggiungo tcp_nodelay, affinché l’ultima parte di un flusso venga inviata senza tempi di attesa. Rimane importante effettuare test con traffico reale, poiché le dimensioni dei pacchetti, l’MTU e i client variano e l’equilibrio ottimale può differire leggermente a seconda del carico di lavoro. Per le directory statiche è solitamente sufficiente l’attivazione globale, mentre nel caso di percorsi di risposta dinamici prendo in considerazione l’effetto che ne deriva. Questa combinazione fornisce una solida base per ulteriori passaggi di ottimizzazione di nginx, che verranno aggiunti in seguito.
| direttiva | Scopo | Effetto tipico | Dipendenza |
|---|---|---|---|
| sendfile on | Zero-Copy da file a socket | Minore carico della CPU, maggiore produttività | Sistema di file locale ideale |
| tcp_nopush on | Riempire i pacchi, ridurre i costi generali | Meno segmenti per file | Funziona solo con sendfile |
| tcp_nodelay on | Invia gli ultimi byte senza attendere | Rapida conclusione del trasferimento | Aggiunto tcp_nopush |
Ecco come tcp_nodelay interagisce con tcp_nopush
Attivo tcp_nopush, per inviare l'inizio di un trasferimento in pacchetti più grandi, e abilito contemporaneamente tcp_nodelay affinché la conclusione non rimanga bloccata. Entrambe le impostazioni agiscono su fasi diverse del flusso e non si ostacolano a vicenda quando NGINX distribuisce i file tramite sendfile. Soprattutto in presenza di molti file di piccole dimensioni, tcp_nodelay impedisce che il client attenda inutilmente a causa di piccoli dati residui. Testo prima la combinazione in ambiente di staging, osservo gli RTT e le dimensioni dei segmenti e li confronto con le metriche live. In questo modo garantisco l’efficienza all’inizio e la velocità alla fine del trasferimento.
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
}
Scenari di applicazione tipici: dove le direttive hanno un forte impatto
Per i grandi Scaricamento Come nel caso di video, archivi o immagini ISO, il percorso zero-copy del kernel riduce notevolmente il tempo di CPU per ogni trasferimento. In configurazioni simili a CDN con numerosi file CSS, JS e di font, tcp_nopush riduce il numero di segmenti, aumentando così la larghezza di banda utilizzabile per ogni socket. Sui siti WordPress con una buona cache, la maggior parte delle richieste riguarda risorse statiche, motivo per cui ne vedo l’effetto molto rapidamente. Anche gli artefatti di build, le immagini dei container o i programmi di installazione ne traggono vantaggio, a condizione che si trovino in locale e non passino attraverso un file system di rete instabile. Chi si aspetta picchi di carico, con questa coppia di strumenti otterrà la massima stabilità dall’hardware a disposizione.
Esempio pratico: NGINX per WordPress con caching e risorse
Nelle configurazioni di WordPress imposto sendfile, imposta tcp_nopush e tcp_nodelay a livello globale, servo le risorse statiche direttamente e mantengo una netta separazione tra PHP-FPM e i percorsi dinamici. Aggiungo header di cache appropriati per immagini, CSS e JavaScript, in modo che i browser generino un minor numero di roundtrip. Quando fornisco risposte di tipo streaming, prendo in considerazione l’interazione con il buffering e verifico come le dimensioni dei chunk influiscano sulla latenza e sulla velocità di trasmissione; a questo proposito è utile la panoramica su Streaming della risposta in pezzi. Per i contenuti testuali ricorro alla compressione, senza comprimere inutilmente i file binari. In questo modo il flusso delle richieste rimane stabile, la CPU non viene sovraccaricata e il tempo di risposta (Time-to-First-Byte) è breve.
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";
}
}
}
Quando disattivo intenzionalmente la funzione sendfile
Accendo sendfile quando i file si trovano su NFS, SMB o sistemi di file distribuiti, che nel mio test hanno registrato velocità di trasferimento inferiori. Alcuni driver o latenze nel percorso di archiviazione annullano il vantaggio dello Zero Copy, motivo per cui le misurazioni sono determinanti. In caso di anomalie sporadiche della rete, disattivo innanzitutto tcp_nopush per circoscrivere gli effetti, prima di mettere in discussione sendfile stesso. Anche bug insoliti del kernel o stack obsoleti possono essere motivi per passare temporaneamente al classico percorso di lettura-scrittura. È importante apportare le modifiche in modo graduale e documentarle con metriche.
Fonti di errore che tengo d’occhio
Per prima cosa verifico se tcp_nopush è attivata per errore, mentre sendfile rimane disattivato, poiché in tal caso l’impostazione non ha alcun effetto. Per i percorsi dinamici, osservo se un buffering aggiuntivo aumenta la latenza e valuto i vantaggi rispetto al tempo di risposta. Nelle reti ad alta latenza, valuto se pacchetti più grandi siano davvero d’aiuto o se sia necessario ottimizzare le dimensioni dei segmenti e il keep-alive. Anche la configurazione dell’MTU e le funzionalità di offloading della scheda di rete possono influire visibilmente sul risultato. Log chiari, campioni pcap e metriche di sistema correlate mi indicano rapidamente dove intervenire.
Un approccio olistico alle prestazioni di NGINX: ulteriori parametri di regolazione
Inoltre sendfile È importante impostare il numero corretto di `worker_processes` e `worker_connections`, in modo da non limitare artificialmente i socket. Su Linux utilizzo epoll e mi assicuro che ci siano abbastanza descrittori di file, affinché i picchi di carico non causino colli di bottiglia. Per i contenuti testuali attivo gzip o Brotli e verifico se il livello di compressione grava in modo ragionevole sulla CPU. A livello di trasporto mantengo aperte le connessioni più a lungo e ottimizzo il Keep-Alive, come indicato nella guida Ottimizzazione Keep-Alive fornisce indicazioni pratiche. TLS, il riutilizzo delle sessioni e HTTP/2 o HTTP/3 completano la configurazione e garantiscono un elevato livello di parallelismo con una latenza moderata.
Limiti e casi particolari: TLS, HTTP/2/3 e proxy
Tengo conto del fatto che sendfile tecnicamente si applica solo ai percorsi dei file non crittografati o a specifiche funzioni del kernel. Nel TLS classico, NGINX crittografa i byte nello spazio utente, il che elimina il vantaggio dello zero-copy; i kernel moderni possono in parte spostare la crittografia nel kernel, ripristinando così tale vantaggio, ma questa funzionalità non è disponibile in tutte le configurazioni. In HTTP/2 i dati sono contenuti in frame, più risposte condividono una connessione TCP e NGINX ricompone attivamente i byte: in questo caso, sendfile è meno rilevante. HTTP/3 si basa su UDP/QUIC e segue regole ancora diverse, per cui ottengo miglioramenti in termini di efficienza soprattutto grazie ai buffer, al controllo della congestione e a dimensioni dei chunk scelte correttamente. Come Proxy inverso sendfile viene utilizzato solo quando servo effettivamente file dal file system locale; le risposte da proxy_pass oppure fastcgi_pass passano comunque attraverso lo spazio utente. Per questo motivo separo rigorosamente le risorse dal percorso dinamico, in modo da sfruttare al massimo l’approccio zero-copy.
Comprendere correttamente la compressione: gzip/Brotli contro gzip_static
Quando NGINX comprime i contenuti al volo, deve leggere il file, elaborarlo e scrivere il risultato; in questo processo si verifica una perdita di sendfile il suo vantaggio. Per le risorse statiche, quindi, utilizzo, ove possibile, precompressi File (ad es. .gz o .br) e li faccio consegnare direttamente. In questo modo si mantiene il percorso zero-copy, poiché NGINX può trasmettere il file precompresso come qualsiasi altra risorsa. Per i contenuti prevalentemente testuali e modificati raramente, in questo modo ottengo un risparmio di CPU e un throughput stabile, senza compromettere i tempi di trasmissione. Nel caso di file binari e formati già compressi, evito qualsiasi compressione in fase di esecuzione: in questo caso conta esclusivamente la velocità di trasmissione I/O, ed è qui che sendfile e tcp_nopush danno il meglio di sé.
AIO, directio e Page Cache: modelli per file di piccole e grandi dimensioni
Combino sendfile con I/O asincrono e accesso diretto al disco, per ottenere le prestazioni ottimali a seconda delle dimensioni del file. I file di piccole e medie dimensioni traggono vantaggio dalla cache di pagina del kernel e rimangono sul percorso sendfile. I file molto grandi, invece, possono sovrascrivere la cache; in tal caso, li leggo in modo mirato con direzione al di fuori della cache e utilizzo thread AIO. In questo modo alleggerisco il carico sulla memoria e mantengo bassa la latenza per le altre richieste. Un modello tipico si presenta così:
http {
# Percorso predefinito: zero-copy dalla cache di pagina
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# File di grandi dimensioni: lettura asincrona senza passare dalla cache
aio threads;
directio 4m; # si applica solo per file >= 4 MiB
output_buffers 1 512k; # buffer per percorsi directio
sendfile_max_chunk 1m; # equità sotto carico elevato
}
Grazie a questa scalabilità, gli asset di piccole dimensioni rimangono estremamente efficienti, mentre i trasferimenti di grandi dimensioni non sovraccaricano la memoria di lavoro. Importante: directio disattiva il percorso sendfile per i file interessati – ed è proprio quello che intendo per il caso d'uso dei file di grandi dimensioni.
Equità e controllo del flusso sotto carico
Nei periodi di carico elevato, vorrei evitare che un singolo flusso monopolizzi la CPU o il socket. Impostare sendfile_max_chunk, in modo che NGINX restituisca il kernel dopo un numero definito di byte e lasci spazio ad altre connessioni. Per la gestione della larghezza di banda sono utili limit_rate e tasso_limite_dopo, ad esempio per limitare i download in blocco, mentre le risorse dell’interfaccia utente rimangono veloci. Con postpone_output impostando la dimensione minima della risposta a partire dalla quale NGINX inizia l'invio; in combinazione con tcp_nopush, garantisco così un frazionamento corretto dei pacchetti. Inoltre, mi assicuro che lingering_close, in modo che i pacchetti rimanenti possano essere trasmessi correttamente e il socket non venga chiuso bruscamente.
Sistemi di file, readahead e percorsi di archiviazione
Perché sendfile Quando si utilizzano le cache di pagina, il file system sottostante riveste un ruolo fondamentale. Controllo i valori di readahead e li mantengo in modo tale che le operazioni di lettura sequenziale di file di grandi dimensioni non subiscano rallentamenti, senza però sacrificare le risorse più piccole. Su ext4 oppure xfs Osservo quanto il prefetching e lo scheduler I/O si adattino bene al mio modello di throughput. Sui file system di rete (NFS/SMB) sottopongo a test rigorosi rsize/wsize, la cache e le latenze, poiché anche piccole variazioni neutralizzano il vantaggio dello zero-copy. La mia regola rimane: sfruttare al massimo i percorsi locali, poi regolare con cautela gli stack esterni – e dare sempre la precedenza ai valori misurati rispetto all’intuizione.
Ottimizzare in modo pragmatico lo stack di rete e l'offloading della scheda di rete
Per un numero elevato di connessioni mi affido alla regolazione automatica dei buffer degli stack moderni, ma se necessario regolo i buffer di trasmissione e ricezione. Le operazioni di offload della scheda di rete (NIC), come TSO, GSO e GRO, riducono sensibilmente il carico della CPU; tuttavia, durante le misurazioni procedo con cautela, poiché le acquisizioni dei pacchetti possono risultare distorte dall’offload (apparentemente pochi segmenti di dimensioni molto grandi). Pertanto, metto in correlazione pcap‑Traces con metriche provenienti da NGINX e dal kernel, per distinguere le dimensioni effettive del traffico dagli artefatti dell’offload. In caso di picchi di latenza, interrompo brevemente i test disattivando gli offload, documento la differenza e poi decido quale soluzione sia più vantaggiosa nel funzionamento continuo.
Modelli di configurazione per ogni sede: attivazione e disattivazione mirate
Mi riservo la possibilità di, sendfile da sovrascrivere a seconda del percorso o del tipo di file. Per le directory statiche rimane attivo, mentre per i percorsi in streaming o dinamici lo disattivo in modo selettivo quando i buffer o i filtri (ad es. la compressione) hanno la priorità. Ecco un breve esempio:
server {
listen 80;
server_name static.example.com;
root /var/www/static;
# Risorse statiche: Zero-Copy
location /assets/ {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
expires 7d;
}
# Contenuti dinamici o streaming: flessibilità prima di Zero-Copy
location /api/ {
sendfile off;
proxy_pass http://app_upstream;
}
}
Questa separazione mi impedisce di perdere i vantaggi da un lato, solo perché un altro percorso prevede requisiti specifici.
Intervalli, sezioni e cataloghi di grandi dimensioni
Nel caso di immobili di grandi dimensioni, si applica Gamma-Le richieste ne sfruttano i punti di forza: il client carica solo le parti necessarie e le connessioni rimangono stabili. Nei cataloghi di contenuti con file di grandi dimensioni, preferisco segmentare logicamente i trasferimenti: il carico sul server si distribuisce in modo più uniforme e gli errori, come le interruzioni, comportano una perdita di tempo minore. Negli scenari di caching prevengo i „thundering herds“ bufferizzando le risposte in modo ragionevole, senza però trattenere artificialmente piccoli blocchi e dati residui. L’interazione con tcp_nopush rimane fondamentale in questo contesto: mantengo grandi i segmenti iniziali, ma non faccio attendere quelli finali.
Strategia di misurazione e collaudo: dimostrare gli effetti in modo attendibile
Corropo le ottimizzazioni con test riproducibili. A livello di server, monitoro i profili della CPU, $request_time, 1 TP 4 TB inviati, connessioni attive e cambi di contesto. In rete misuro le dimensioni dei segmenti, le ritrasmissioni e la distribuzione degli RTT; metto in correlazione le acquisizioni dei pacchetti con le statistiche dei socket per tenere conto degli effetti dell’offload. Sul lato client confronto TTFB, First Contentful Paint e tempi di download in condizioni realistiche di RTT e larghezza di banda. Vario MTU, impostazioni Keep-Alive e dimensioni dei file, in modo da non vedere solo curve di scenario ottimale. Infine, sulla base di dati concreti, valuto se sendfile/tcp_nopush garantiscono la stabilità e l’efficienza desiderate nel carico di lavoro in questione e procedo a una regolazione fine fino a quando non raggiungono tali risultati.
Dettagli HTTP che fanno la differenza: Range e streaming
Uso Gamma-Richieste per file di grandi dimensioni, in modo che i client scarichino solo le parti necessarie e le connessioni rimangano stabili. Soprattutto in caso di riproduzione video in anticipo e ripresa degli aggiornamenti, un supporto efficiente degli intervalli di byte aiuta a distribuire in modo ottimale la larghezza di banda; ulteriori informazioni sono disponibili alla pagina dedicata a Richieste HTTP Range. Per le risposte continue con un corpo sempre più lungo, sto testando strategie di streaming e mi assicuro che i buffer non trattengano i dati involontariamente per troppo tempo. Nel farlo, rispetto le cache e imposto header appropriate affinché i proxy e i browser agiscano correttamente. Prendo in considerazione l’interazione con tcp_nopush, poiché le dimensioni dei pacchetti e la tempistica del flush influenzano direttamente la velocità percepita.
Riassumendo brevemente
Con sendfile Inoltro i file in modo efficiente direttamente al kernel e, con tcp_nopush, faccio in modo che i pacchetti vengano riempiti in modo ottimale prima che appesantiscano la linea. Entrambe le direttive si completano a vicenda, mentre tcp_nodelay invia l’ultimo byte rimanente senza ritardi. Verifico l’effetto con traffico reale, prestando attenzione al percorso di archiviazione, all’MTU, al keep-alive e alla compressione, ed effettuo misurazioni sistematiche. Per i carichi di lavoro di tipo WordPress e CDN, i benefici si manifestano particolarmente in fretta, poiché molte richieste riguardano risorse statiche. Chi utilizza queste impostazioni in modo mirato ottiene una maggiore larghezza di banda per core, riduce l’overhead e crea riserve per i veri picchi di crescita.


