...

Utiliser correctement NGINX sendfile et tcp_nopush pour des performances optimales

Avec nginx sendfile et tcp_nopush Je transmets les fichiers statiques en « zero-copy » depuis le système de fichiers vers le socket, ce qui réduit sensiblement la charge du processeur et le nombre de paquets. Correctement configurées, ces deux directives améliorent l'efficacité du transfert, réduisent la surcharge et posent les bases d'une optimisation nginx efficace pour les ressources et les téléchargements.

Points centraux

  • Zero-Copy grâce à sendfile : moins de copies, un débit plus élevé
  • tcp_nopush met les paquets en mémoire tampon : trames plus volumineuses, moins de surcharge
  • Combinaison comprend : sendfile + tcp_nopush + tcp_nodelay
  • Cas d'utilisation hiérarchiser : ressources statiques, fichiers volumineux à télécharger
  • Tests pour NFS/SMB : mesurer l'impact, désactiver sendfile si nécessaire

Pourquoi la fonction `sendfile` améliore autant les performances de NGINX

J'active sendfile, car le noyau peut envoyer des fichiers directement via la pile réseau, sans passer par des opérations de copie supplémentaires dans l'espace utilisateur. Ce chemin « zéro copie » réduit les changements de contexte et économise des cycles CPU, en particulier lorsque de nombreux clients simultanés récupèrent du contenu statique. Les fichiers volumineux tels que les images, les fichiers CSS, JavaScript ou les archives en bénéficient, car le transfert de données s’effectue de manière plus fluide et avec moins de surcharge. Les caches système fonctionnent également plus efficacement, car il y a moins de mouvements de mémoire et c’est le noyau qui contrôle le cheminement des données. C’est sur les systèmes de fichiers locaux que le gain est le plus flagrant, c’est pourquoi je commence par y effectuer mes mesures avant de transposer les résultats à des configurations plus exotiques.

Ce que fait exactement tcp_nopush et dans quelles circonstances il se distingue

Avec tcp_nopush Je demande au système de n'envoyer les paquets TCP que lorsqu'ils sont suffisamment remplis, plutôt que d'envoyer trop tôt de petits segments. Sous Linux, cela correspond à TCP_CORK, sous FreeBSD à TCP_NOPUSH, et dans les deux cas, le nombre de paquets diminue de manière mesurable. Cette directive ne réduit pas la latence au minimum ; elle vise à améliorer le rapport entre les données utiles et la surcharge. J’utilise tcp_nopush de manière ciblée pour les fichiers statiques, car c’est là que les flux de données contigus offrent les gains d’efficacité les plus importants. Sans sendfile, tcp_nopush reste sans effet ; c’est pourquoi j’intègre toujours ces deux paramètres ensemble.

sendfile et tcp_nopush en tandem : voici comment je pose les bases

La combinaison de sendfile et tcp_nopush réduit les copies et regroupe les paquets, ce qui permet à un serveur par cœur de processeur de gérer nettement plus de transferts parallèles. Je configure ces deux paramètres au niveau du contexte http et j'ajoute souvent tcp_nodelay afin que les derniers restes d'un flux puissent s'écouler sans temps d'attente. Il reste important de procéder à des tests avec du trafic réel, car la taille des paquets, le MTU et les clients varient, et le meilleur équilibre peut légèrement différer en fonction de la charge de travail. Pour les répertoires statiques, l’activation globale suffit généralement, tandis que pour les routes de réponse dynamiques, je surveille l’impact. Cette combinaison offre une base solide pour d’autres étapes d’optimisation d’Nginx, qui viendront s’y ajouter par la suite.

directive Objectif Effet typique Dépendance
sendfile activé Copie sans transfert de fichier vers le socket Moins de charge sur le processeur, débit plus élevé Système de fichiers local : l'idéal
tcp_nopush activé Remplir les colis, réduire les frais généraux Moins de segments par fichier Ne fonctionne qu'avec sendfile
tcp_nodelay activé Envoyer les derniers octets sans délai Achèvement rapide du transfert Ajout de tcp_nopush

Voici comment tcp_nodelay interagit avec tcp_nopush

J'active tcp_nopush, afin d'envoyer le début d'un transfert par paquets plus volumineux, tout en activant tcp_nodelay pour éviter que la fin du transfert ne soit bloquée. Ces deux paramètres agissent sur des phases différentes du flux et ne se gênent pas mutuellement lorsque NGINX transfère des fichiers via sendfile. C’est notamment dans le cas de nombreux petits fichiers que tcp_nodelay évite au client d’attendre inutilement en raison de petites quantités de données restantes. Je teste d’abord cette combinaison en environnement de préproduction, j’observe les temps de transit (RTT) et la taille des segments, puis je les compare aux métriques en production. Je m’assure ainsi d’une efficacité au début et d’une rapidité à la fin du transfert.

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

Scénarios d'utilisation typiques : lorsque les directives ont un impact important

Pour les grandes Téléchargements Comme pour les vidéos, les archives ou les images ISO, le chemin « zero-copy » du noyau réduit considérablement le temps CPU par transfert. Dans les configurations de type CDN comportant de nombreux fichiers CSS, JS et de polices, tcp_nopush permet d’économiser des segments et augmente ainsi la bande passante utilisable par socket. Sur les sites WordPress bien mis en cache, la plupart des requêtes concernent des ressources statiques, c’est pourquoi j’y constate très rapidement un effet positif. Les artefacts de build, les images de conteneurs ou les programmes d’installation en bénéficient également, à condition qu’ils soient stockés localement et ne transitent pas par un système de fichiers réseau instable. Si vous vous attendez à des pics de charge, ce duo vous permettra de tirer le maximum de stabilité du matériel dont vous disposez.

Exemple pratique : NGINX pour WordPress avec mise en cache et ressources

Dans les installations WordPress, j'utilise sendfile, j'active les options `tcp_nopush` et `tcp_nodelay` au niveau global, je fournis directement les ressources statiques et je veille à bien séparer PHP-FPM des chemins dynamiques. J’ajoute des en-têtes de cache pertinents pour les images, les feuilles de style CSS et les scripts JavaScript, afin que les navigateurs effectuent moins d’allers-retours. Lorsque je fournis des réponses de type streaming, je tiens compte de l’interaction avec la mise en mémoire tampon et je teste l’impact de la taille des blocs sur la latence et le débit ; à ce sujet, l’aperçu sur Streaming de réponse en chunks. Pour les contenus textuels, j'utilise la compression sans compresser inutilement les fichiers binaires. Cela permet de maintenir un flux de requêtes stable, de ne pas surcharger le processeur et de réduire le temps de réponse (Time-to-First-Byte).

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

Quand je désactive délibérément la fonction sendfile

J'enclenche sendfile lorsque les fichiers se trouvent sur des systèmes de fichiers NFS, SMB ou distribués, qui, lors de mes tests, ont affiché des débits moins performants. Certains pilotes ou certaines latences dans le chemin de stockage annulent l’avantage du « zero-copy », c’est pourquoi les mesures font office de référence. En cas d’anomalies réseau sporadiques, je désactive d’abord tcp_nopush afin de circonscrire les effets avant de remettre en question sendfile lui-même. Des bogues inhabituels du noyau ou des piles plus anciennes peuvent également justifier le passage temporaire au chemin de lecture-écriture classique. Il reste important d’appliquer les modifications progressivement et de les étayer par des métriques.

Les sources d'erreurs que je surveille de près

Je vérifie d'abord si tcp_nopush est activée par inadvertance alors que sendfile reste désactivé, car dans ce cas, le paramètre n'a aucun effet. Pour les chemins d'accès dynamiques, je vérifie si une mise en mémoire tampon supplémentaire augmente la latence et je mets en balance les avantages et le temps de réponse. Sur les réseaux à forte latence, je vérifie si des paquets plus volumineux sont réellement utiles ou si je dois ajuster la taille des segments et les keep-alive. La configuration du MTU et les fonctionnalités de déchargement de la carte réseau peuvent également modifier sensiblement le résultat. Des journaux clairs, des échantillons pcap et des métriques système corrélées m’indiquent rapidement où effectuer des ajustements.

Une approche globale des performances de NGINX : d'autres leviers d'optimisation

En plus de sendfile Il est avantageux de définir correctement le nombre de `worker_processes` et de `worker_connections` afin de ne pas limiter artificiellement les sockets. Sous Linux, j’utilise epoll et je m’assure de disposer d’un nombre suffisant de descripteurs de fichiers pour éviter que les pics de charge n’entraînent des goulots d’étranglement. Pour les contenus textuels, j’active gzip ou Brotli et je vérifie si le niveau de compression sollicite le processeur de manière raisonnable. Au niveau de la couche de transport, je maintiens les connexions ouvertes plus longtemps et j’optimise le Keep-Alive, comme l’explique le guide Réglage Keep Alive fournit des indications pratiques. Le protocole TLS, la réutilisation des sessions et les protocoles HTTP/2 ou HTTP/3 complètent la configuration et permettent un haut niveau de parallélisme avec une latence modérée.

Limites et cas particuliers : TLS, HTTP/2/3 et utilisation d'un proxy

Je tiens compte du fait que sendfile ne s'applique techniquement qu'aux chemins d'accès aux fichiers non chiffrés ou à certaines fonctions spécifiques du noyau. Avec le protocole TLS classique, NGINX chiffre les octets dans l'espace utilisateur, ce qui annule l'avantage du « zero-copy » ; les noyaux modernes peuvent partiellement déporter le chiffrement vers le noyau, ce qui rétablit cet effet, mais cette fonctionnalité n'est pas disponible dans toutes les configurations. Dans le cas de HTTP/2 les données sont contenues dans des trames, plusieurs réponses partagent une connexion TCP et NGINX réorganise activement les octets : dans ce cas, sendfile est moins pertinent. HTTP/3 repose sur UDP/QUIC et suit à nouveau d'autres règles, de sorte que j'obtiens plutôt des gains d'efficacité grâce à des tampons, au contrôle de la congestion et à des tailles de chunks correctement choisies. En tant que Proxy inverse sendfile ne s'applique que lorsque je sers effectivement des fichiers provenant du système de fichiers local ; réponses tirées de proxy_pass ou fastcgi_pass passent de toute façon par l'espace utilisateur. C'est pourquoi je sépare strictement les ressources du chemin dynamique, afin de tirer pleinement parti du mode « zero-copy ».

Bien comprendre la compression : gzip/Brotli ou gzip_static

Dès que NGINX compresse du contenu à la volée, il doit lire le fichier, le traiter et écrire le résultat – ce qui entraîne une perte de sendfile son avantage. Pour les ressources statiques, j'utilise donc, dans la mesure du possible, pré-compressés fichiers (par exemple .gz ou .br) et les fais servir directement. Cela permet de conserver le chemin « zero-copy », car NGINX peut transmettre le fichier pré-compressé comme n’importe quelle autre ressource. Pour les contenus riches en texte et rarement modifiés, cela me permet de réaliser des économies de CPU et d’obtenir un débit stable, sans perte de temps de transfert. Pour les fichiers binaires et les formats déjà compressés, j’évite toute compression à l’exécution : ici, seul le débit d’E/S compte, et les fonctions `sendfile` et `tcp_nopush` montrent tout leur potentiel.

AIO, directio et Page Cache : modèles pour les petits et les grands fichiers

Je combine sendfile avec des E/S asynchrones et un accès direct au disque, afin d'obtenir les meilleures performances en fonction de la taille des fichiers. Les fichiers de petite à moyenne taille bénéficient du cache de pages du noyau et restent sur le chemin sendfile. En revanche, les très gros fichiers peuvent saturer le cache ; dans ce cas, je les lis de manière ciblée avec directio en dehors du cache et j'utilise des threads AIO. Cela permet de soulager la mémoire et de maintenir une faible latence pour les autres requêtes. Voici à quoi ressemble un modèle typique :

http {
    # Chemin standard : Zero-Copy à partir du cache de pages
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

 # Fichiers volumineux : contournement du cache et lecture asynchrone
    aio threads;
    directio 4m ; # ne s'applique qu'aux fichiers >= 4 MiB
    output_buffers 1 512k ;    # Tampons pour les chemins directio
    sendfile_max_chunk 1m ;    # Équité sous forte charge
}

Grâce à cette hiérarchisation, les petits fichiers restent extrêmement efficaces, tandis que les transferts de très grande taille ne saturent pas la mémoire vive. Important : directio désactive le chemin sendfile pour les fichiers concernés – c'est exactement ce que je souhaite pour le cas d'utilisation des fichiers volumineux.

Équité et contrôle du débit sous charge

Pendant les périodes de forte charge, je souhaite éviter qu'un seul flux ne monopolise le processeur ou le socket. J'utilise sendfile_max_chunk, afin que NGINX renvoie le noyau après un nombre défini d'octets et laisse de la place à d'autres connexions. Pour le contrôle de la bande passante, les éléments suivants sont utiles : limit_rate et limit_rate_after, par exemple pour limiter les téléchargements en masse tout en garantissant la fluidité des éléments de l'interface utilisateur. Avec postpone_output Je contrôle à partir de quelle taille de réponse NGINX commence l'envoi ; en combinaison avec tcp_nopush, je garantis ainsi un découpage propre des paquets. De plus, je veille à ce que lingering_close, afin que les paquets restants puissent être transmis correctement et que la connexion ne soit pas interrompue brusquement.

Systèmes de fichiers, lecture anticipée et chemins d'accès au stockage

Parce que sendfile Lorsqu'on utilise les caches de page, le système de fichiers sous-jacent joue un rôle important. Je vérifie les valeurs de prélecture et je les règle de manière à ce que les lectures séquentielles de fichiers volumineux ne soient pas ralenties, sans pour autant évincer les ressources plus petites. Sur ext4 ou xfs J'observe à quel point le préchargement et le planificateur d'E/S s'adaptent bien à mon profil de débit. Sur les systèmes de fichiers réseau (NFS/SMB), je teste rigoureusement les valeurs rsize/wsize, la mise en cache et les latences, car même de légers écarts suffisent à neutraliser l'avantage du « zero-copy ». Ma règle reste la même : exploiter au maximum les chemins locaux dans un premier temps, puis ajuster prudemment les piles externes – et toujours privilégier les mesures objectives plutôt que l'intuition.

Adapter de manière pragmatique la pile réseau et le déchargement de la carte réseau

Pour les nombres élevés de connexions, je m'en remets à l'ajustement automatique des tampons des piles modernes, mais j'ajuste les tampons d'émission et de réception si nécessaire. Les fonctions de déchargement des cartes réseau (NIC) telles que TSO, GSO et GRO réduisent sensiblement la charge du processeur ; je procède toutefois à des vérifications minutieuses lors des mesures, car les captures de paquets peuvent être faussées par le déchargement (apparence d'un nombre réduit de segments très volumineux). C'est pourquoi je corrèle pcap‑Traces avec des métriques issues de NGINX et du noyau, afin de distinguer les tailles réelles des paquets des artefacts liés à l'offload. En cas de pics de latence, j'interromps brièvement les tests en désactivant l'offload, je consigne la différence observée, puis je détermine ce qui est le plus avantageux en fonctionnement continu.

Modèles de configuration par site : activation et désactivation ciblées

Je me réserve la possibilité de, sendfile à remplacer en fonction du chemin ou du type de fichier. Pour les répertoires statiques, cette option reste activée ; pour les chemins de streaming ou dynamiques, je la désactive de manière sélective lorsque la mémoire tampon ou les filtres (par exemple, la compression) ont la priorité. Voici un petit exemple :

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

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

 # Contenu dynamique ou streaming : la flexibilité prime sur le « Zero-Copy »
    location /api/ {
 sendfile off;
 proxy_pass http://app_upstream;
    }
}

Cette séparation m'évite de perdre des avantages d'un côté simplement parce qu'un autre parcours impose des exigences particulières.

Range, Slices et grands catalogues

Dans le cas de grands projets, gamme-Requests met en avant ses atouts : le client ne charge que les parties nécessaires, et les connexions restent stables. Dans les catalogues de contenu contenant des fichiers très volumineux, j’aime segmenter les transferts de manière logique : la charge du serveur est répartie plus uniformément, et les erreurs telles que les interruptions prennent moins de temps. Dans les scénarios de mise en cache, je préviens les „ thundering herds “ en mettant en mémoire tampon les réponses de manière judicieuse, sans toutefois retenir artificiellement les petits blocs et les données restantes. L’interaction avec tcp_nopush reste ici essentielle : je conserve des segments initiaux volumineux, mais je ne laisse pas la fin attendre.

Stratégie de mesure et d'essai : démontrer de manière fiable les effets

Je valide les optimisations à l'aide de tests reproductibles. Côté serveur, j'observe les profils d'utilisation du processeur, $request_time, 1 TP 4 To envoyés, les connexions actives et les changements de contexte. Sur le réseau, je mesure la taille des segments, les retransmissions et la distribution des RTT ; je corrèle les captures de paquets avec les statistiques des sockets afin de prendre en compte les effets de déchargement. Côté client, je compare le TTFB, le First Contentful Paint et les temps de téléchargement avec des RTT et des bandes passantes réalistes. Je fais varier la MTU, les paramètres Keep-Alive et la taille des fichiers afin de ne pas me limiter aux courbes « best-case ». Au final, je détermine, à l’aide de chiffres concrets, si sendfile/tcp_nopush offrent la stabilité et l’efficacité souhaitées pour la charge de travail concernée – et j’affine les réglages jusqu’à ce que ce soit le cas.

Les détails HTTP qui font la différence : Range et streaming

J'utilise gamme-Requêtes pour les fichiers volumineux, afin que les clients ne rechargent que les parties nécessaires et que les connexions restent stables. Notamment dans le cas des avances vidéo et de la reprise des mises à jour, une prise en charge efficace des plages d'octets permet de répartir le débit de manière optimale ; vous trouverez des informations complémentaires sur la page consacrée à Requêtes HTTP de type « range ». Pour les réponses continues dont le corps ne cesse de s'allonger, je teste des stratégies de streaming et veille à ce que les tampons ne conservent pas involontairement les données trop longtemps. Ce faisant, je respecte les caches et définis des en-têtes pertinents afin que les proxys et les navigateurs se comportent correctement. Je tiens compte de l’interaction avec `tcp_nopush`, car la taille des paquets et le moment du vidage ont une influence directe sur la rapidité perçue.

En bref

Avec sendfile Je transmets efficacement les fichiers directement au noyau, et grâce à `tcp_nopush`, je veille à ce que les paquets soient correctement remplis avant qu'ils n'encombrent la ligne. Ces deux directives se complètent, tandis que `tcp_nodelay` transmet le dernier octet restant sans délai. Je vérifie l’effet en conditions de trafic réel, en prêtant attention au chemin d’accès au stockage, à la MTU, au Keep-Alive et à la compression, et j’effectue des mesures systématiques. Pour les charges de travail de type WordPress et CDN, les avantages se font particulièrement vite sentir, car de nombreuses requêtes concernent des ressources statiques. En utilisant ces paramètres de manière ciblée, on obtient un débit plus élevé par cœur, on réduit la surcharge et on crée des réserves pour faire face aux véritables pics de croissance.

Derniers articles