ZFS NFS : les réglages qui font ressembler le stockage à un disque local

Cet article vous a aidé ?

On ne remarque pas le « stockage » quand il fonctionne. On le remarque quand la file de build s’arrête, que votre VM démarre comme si les octets traversaient un touilleur à café,
et que votre base de données commence à journaliser « fsync prend trop de temps » pendant que tout le monde accuse le réseau parce que c’est un bouc émissaire socialement acceptable.

ZFS sur NFS peut donner une sensation étonnamment proche d’un disque local — jusqu’à ce que ce ne soit plus le cas. L’écart vient presque toujours des réglages, d’hypothèses divergentes, et de quelques
valeurs par défaut petites mais létales. Réparons ça.

Le modèle mental : pourquoi « NFS est lent » est généralement un mensonge

« NFS est lent » n’est pas un diagnostic. C’est un état émotionnel. En production, la lenteur provient généralement d’une des quatre sources :
latence, sérialisation, sémantique sync, ou fragmentation/désalignement avec la charge. ZFS et NFS ont tous deux des opinions fortes
sur la façon dont les E/S doivent se produire. Quand leurs opinions s’alignent, vous obtenez quelque chose qui paraît local. Quand elles ne s’alignent pas, vous obtenez un
déni de service distribué construit à partir de petits choix par défaut bien intentionnés.

Votre travail est d’aligner le pipeline :

  • Forme des E/S applicatives : aléatoire vs séquentiel, petit vs grand, sync vs async, lourde en métadonnées vs streaming.
  • Comportement NFS : caching des attributs, read-ahead, délégations/verrouillage, nombre de RPC parallèles, sémantique de montage.
  • Comportement ZFS : recordsize, compression, primarycache, dimensionnement de l’ARC, special vdev, politique sync, ZIL/SLOG.
  • Réalité matérielle et réseau : plancher de latence, débit du lien, profondeur de file d’attente, modération d’interruption, offloads NIC.

Le mode d’échec le plus courant est de supposer que le stockage est « assez rapide » parce qu’il donne de bons résultats en local sur le serveur.
NFS change le modèle d’E/S. ZFS réagit. La latence est amplifiée par les allers-retours et les sémantiques synchrones. Un pool qui fait 2 GB/s en lectures séquentielles
peut toujours sembler horrible pour une charge qui effectue des écritures synchrones de 4 Ko via NFS.

Un point important : « ressemble à un disque local » ne veut pas dire « même débit ». Cela signifie « mêmes latences extrêmes sous charge normale ».
La latence tail est ce qui pousse les utilisateurs à ouvrir des tickets, ou pire, à bricoler des contournements.

Idée paraphrasée (attribuée) : John Allspaw a soutenu que la fiabilité consiste à réduire les surprises, pas seulement à empêcher les pannes.
Le tuning NFS est un projet de réduction des surprises.

Faits et histoire qui importent encore en production

Quelques éléments concrets de contexte rendent les choix de réglage d’aujourd’hui moins mystérieux. Ce ne sont pas des anecdotes ; ils expliquent pourquoi les valeurs par défaut existent,
et pourquoi votre charge peut encore chuter brusquement.

  1. NFS a été conçu à l’origine en supposant des réseaux peu fiables. Les premiers designs s’appuyaient fortement sur la statelessness (surtout NFSv3), ce qui affecte la façon dont les clients récupèrent et mettent en cache.
  2. NFSv4 a introduit l’état. Verrouillage et délégations ont changé la coordination client/serveur et peuvent améliorer la performance—jusqu’à ce qu’ils entrent en conflit avec des comportements clients étranges ou des schémas de basculement.
  3. ZFS a été conçu autour du copy-on-write. Excellent pour les snapshots et l’intégrité ; cela signifie aussi que de petites écritures aléatoires peuvent devenir des modèles d’E/S plus larges et complexes.
  4. Le ZIL existe même sans SLOG dédié. On pense encore parfois « pas de SLOG = pas de ZIL ». Le ZIL est une structure de journal ; SLOG est simplement un dispositif plus rapide pour celui-ci.
  5. Les écritures synchrones sont une promesse sémantique, pas une préférence de performance. Les bases de données et les hyperviseurs forcent souvent le fsync pour de bonnes raisons.
  6. Le recordsize n’est pas « la taille de bloc ». C’est la taille logique maximale des blocs pour les fichiers, ce qui affecte la façon dont ZFS emballe les données et combien il lit/écrit pour une requête donnée.
  7. Le caching des attributs en NFS est un hack de performance avec des conséquences. Il peut accélérer considérablement les charges lourdes en métadonnées — ou introduire de la confusion « pourquoi je ne vois pas le fichier ? » dans les applications distribuées.
  8. Les checksums ont changé la donne. Le checksumming et les scrubs de ZFS expliquent pourquoi les histoires de « corruption silencieuse » sont moins des légendes urbaines en stockage d’entreprise.
  9. Le 10GbE a rendu le débit facile, la latence reste difficile. Beaucoup d’équipes « montent le tuyau » puis découvrent que leur goulot d’étranglement est le RTT sync et le temps de flush du stockage.

Les réglages client et serveur NFS qui déplacent la courbe

Choisir volontairement la version du protocole

NFSv4.x est généralement le bon choix par défaut en 2025 : meilleur modèle de sécurité, opérations composées, fonctionnalités stateful qui peuvent réduire le bavardage.
Mais NFSv3 a encore sa place, surtout dans des environnements où vous voulez un comportement plus simple, ou si vous traitez avec certains hyperviseurs
et piles héritées qui sont « spéciales » au point de ruiner des week-ends.

L’essentiel est la cohérence. Des versions mixtes entre clients peuvent créer des différences de comportement non évidentes (verrouillage, cache, récupération), et vous vous retrouvez à déboguer
la « performance » alors que vous déboguez en réalité la sémantique.

rsize/wsize : arrêtez d’être timide

Les réseaux et noyaux modernes gèrent bien les grandes tailles d’E/S. Utilisez 1M lorsque c’est supporté. Si votre environnement ne le supporte pas, la négociation vous le dira rapidement.
De petites valeurs rsize/wsize produisent plus de RPC, plus de surcharge, et plus d’occasions d’atteindre le mur de latence.

Mais ne faites pas du cargo-cult : si vous êtes sur un lien WAN à haute latence, de grandes tailles peuvent améliorer le débit mais empirer la latence tail interactive dans certains schémas.
Mesurez avec votre charge, pas avec un test séquentiel synthétique.

nconnect et parallélisme : le meilleur ami du débit

Les clients Linux supportent nconnect= pour ouvrir plusieurs connexions TCP vers le serveur pour un seul montage. Cela peut augmenter considérablement le débit
en répartissant la charge sur les files CPU et en évitant qu’un flux unique devienne le point d’étranglement. Ce n’est pas gratuit ; plus de connexions signifie plus d’état et parfois
plus de contention de verrouilles côté serveur.

Montages hard vs soft : soyez brave, pas imprudent

Utilisez des montages hard pour tout ce qui compte. Les montages soft renvoient des erreurs sur timeout, que beaucoup d’applications traitent comme une corruption ou « supprimé et réessayer ».
C’est ainsi que vous transformez un glitch transitoire en perte de données.

Pour des répertoires home interactifs des développeurs, « soft » peut sembler plus agréable quand le serveur est down, mais c’est un piège. Si vous voulez de la réactivité, ajustez les timeouts et
retransmits. Ne sacrifiez pas la cohérence pour la commodité.

actimeo et cache d’attributs : choisissez explicitement votre poison

Les charges lourdes en métadonnées (systèmes de build, gestionnaires de paquets) peuvent bénéficier du caching des attributs. Mais les applications distribuées qui attendent une visibilité quasi-instantanée
des changements de fichiers peuvent être perturbées si les clients mettent en cache les attributs trop longtemps.

L’approche propre : définir actimeo sur quelque chose de raisonnable (comme 1–5 secondes) plutôt que de désactiver complètement le cache.
« actimeo=0 » est souvent une auto-sabotage de performance pour la plupart des charges de travail.

Threads serveur et comportement RPC

Sur les serveurs NFS Linux, le nombre de threads nfsd compte en cas de forte concurrence. Trop peu de threads et les requêtes font la queue ; trop et vous brûlez du CPU sur des changements de contexte
et de la contention. Vous voulez « assez pour garder le pipeline plein », pas « autant que la RAM peut en contenir ».

Les réglages de dataset et de pool ZFS qui changent les résultats

recordsize : alignez-le sur votre charge, pas sur vos impressions

Si vous servez des images de VM ou des bases de données via NFS, le gain le plus courant est de régler recordsize sur quelque chose comme 16K ou 32K (parfois 8K),
car ces charges effectuent beaucoup d’E/S aléatoires petites. Le 128K par défaut est excellent pour le streaming et les sauvegardes, pas pour des invités à écritures aléatoires lourdes.

Pour des répertoires home généralistes, 128K convient. Pour des archives médias, envisagez des tailles de record plus grandes si votre plateforme le permet.
L’objectif est d’éviter l’amplification read-modify-write et de garder l’ARC utile.

compression : activez-la sauf raison contraire

compression=lz4 est l’un des rares repas presque gratuits en stockage. Cela améliore souvent le débit et réduit les E/S. Sur les CPU modernes, le coût est modeste.
Vous ne « sauvez pas de performance » en désactivant la compression ; vous forcez souvent plus d’octets sur le disque et le réseau.

atime : désactivez-le pour la plupart des exports NFS

Les mises à jour d’heure d’accès créent des écritures supplémentaires et de la turbulence méta. Sauf exigence de conformité ou applicative, utilisez atime=off.
Pour les systèmes de fichiers partagés servant beaucoup de lectures, c’est une réduction de latence facile.

xattr et comportement ACL : choisissez un mode qui correspond à vos clients

Les clients Linux, les clients Windows (via des passerelles SMB) et les hyperviseurs peuvent avoir des attentes différentes concernant les ACL et les attributs étendus.
Un mauvais alignement se manifeste par des tempêtes de métadonnées et des bizarreries de permissions. Décidez du cas d’usage principal, puis ajustez pour celui-ci.

special vdev : les métadonnées méritent mieux que « n’importe quel disque restant »

Si votre charge est lourde en métadonnées (millions de petits fichiers, builds, arbres sources), un special vdev peut être transformateur.
Placez les métadonnées (et éventuellement les petits blocs) sur des SSD rapides. Les hits ARC sont excellents, mais les misses ARC arrivent encore, et les misses de métadonnées sont la mort par mille seeks.

primarycache et secondarycache : soyez intentionnel

L’ARC est de la mémoire ; le L2ARC est un cache SSD. Pour des exports NFS servant de larges lectures en streaming, la mise en cache peut évincer des métadonnées utiles.
Pour des images de VM, la mise en cache des données peut aider, mais validez d’abord la taille de la mémoire. Un modèle courant :
primarycache=metadata pour certains datasets, en gardant l’ARC concentré sur ce qui aide le plus.

ashift : vous ne le réglez pas plus tard

ashift est fixé à la création du vdev et affecte l’alignement des secteurs. Si vous vous trompez, vous payez pour toujours en amplification d’écriture.
Si vous êtes sur des disques à secteurs 4K ou des SSD (c’est le cas), ashift=12 est le choix sûr habituel. Ne laissez pas la détection automatique se tromper.

Écritures synchrones, SLOG, et pourquoi « sync=disabled » est une mauvaise idée de carrière

Les clients NFS émettent souvent des écritures synchrones selon les options de montage et le comportement applicatif. Les bases de données appellent fsync parce qu’elles veulent que leurs données
survivent à une coupure de courant. Les hyperviseurs utilisent souvent la sémantique sync pour les disques VM parce que « j’ai perdu un système de fichiers VM » est une réunion coûteuse.

Dans ZFS, les écritures synchrones sont acquittées seulement quand elles sont engagées en toute sécurité. Cela signifie que le chemin ZIL compte.
Sans SLOG dédié, le ZIL vit sur votre pool principal, et la latence des écritures sync devient « à quelle vitesse le pool peut engager de petites écritures en sécurité ».
Sur un pool HDD, ça peut être brutal. Sur un pool SSD, cela peut aller. Sur des pools mixtes, cela dépend de l’étape cohérente la plus lente.

Un dispositif SLOG dédié peut réduire drastiquement la latence des écritures synchrones. Mais uniquement s’il s’agit du bon dispositif : faible latence, protection contre les pertes de puissance, performance cohérente,
et connexion fiable. Un NVMe grand public sans PLP est un générateur d’incidents déguisé.

Blague #1 : Un SSD grand public comme SLOG, c’est comme utiliser un parapluie en papier dans un ouragan — techniquement un parapluie, émotionnellement une erreur.

Ne désactivez pas sync pour « réparer la performance »

sync=disabled fait paraître les benchmarks incroyables. Cela transforme aussi « écriture acquittée » en « peut-être écrite éventuellement », ce que beaucoup d’applications n’attendent pas.
Si le serveur plante, vous pouvez perdre des données que le client croyait durables. Ce n’est pas du tuning ; c’est un tour de magie avec une trappe.

Comprendre les modes sync : standard, always, disabled

  • sync=standard : respecter les demandes des applications (par défaut, généralement correct).
  • sync=always : traiter toutes les écritures comme synchrones. Utile pour certains cas de conformité ; souvent pénalisant.
  • sync=disabled : mentir aux clients. Seulement pour des cas spéciaux où vous avez explicitement accepté le risque et documenté cela comme un adulte.

Logbias et intention de charge

logbias=latency indique à ZFS de favoriser un comportement de journalisation basse latence (souvent approprié pour les charges sync-heavy). logbias=throughput peut aider pour le streaming.
C’est un réglage pour aligner l’intention, pas un levier magique de performance. Testez-le par dataset.

Chemin réseau : réglages ennuyeux qui gagnent des millisecondes

NFS est sensible à la latence parce que chaque RPC est un aller-retour, et les écritures synchrones sont une chaîne d’accusés de réception.
Vous n’avez pas besoin d’un réseau sophistiqué. Vous avez besoin d’un réseau prévisible.

Jumbo frames : pas obligatoires, mais ne faites pas à moitié

Si vous activez MTU 9000, cela doit être bout en bout : NICs, switches, VLANs, bonds, et le serveur de stockage. Une configuration jumbo partielle est pire que rien car vous obtiendrez
de la fragmentation ou des trous noirs. Si vous ne contrôlez pas tout le chemin, laissez tomber et concentrez-vous sur l’évitement des pertes.

Offloads NIC et CPU

Les offloads peuvent aider, mais ils peuvent aussi introduire des pics de latence étranges selon les pilotes et firmwares. L’approche correcte est empirique :
mesurer la charge softirq CPU, les drops et la latence, puis décider. Ne désactivez pas des fonctionnalités parce qu’un billet de blog de 2013 le disait.

Congestion et bufferbloat

Sur des LAN rapides, vous pouvez toujours obtenir des micro-burst et de la mise en file. Surveillez les buffers de switch, le queueing hôte, et les retransmissions TCP.
Si votre NFS « semble lent » seulement sous charge, vous regardez peut-être l’accumulation de files plutôt que des limites de débit brut.

Tâches pratiques : commandes, sorties et ce que vous décidez ensuite

Ce sont des tâches de terrain que vous pouvez exécuter lors d’une plainte de performance sans transformer l’incident en projet d’archéologie.
Chaque tâche inclut : commande, ce que la sortie signifie, et la décision que vous prenez à partir de cela.

Tâche 1 : Confirmer les options de montage NFS (client)

cr0x@server:~$ nfsstat -m
/home from nas01:/tank/home
 Flags: rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.10.10.21,local_lock=none

Ce que cela signifie : Vous êtes en NFSv4.2 avec rsize/wsize 1M, montage hard, TCP. C’est une base saine.

Décision : Si vous voyez de petits rsize/wsize (comme 64K) ou vers=3 de façon inattendue, corrigez les montages d’abord. Si c’est soft, changez-le sauf si ces données sont jetables.

Tâche 2 : Vérifier rapidement la version NFS négociée et le transport (client)

cr0x@server:~$ cat /proc/mounts | grep nfs
nas01:/tank/home /home nfs4 rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.10.10.21,local_lock=none 0 0

Ce que cela signifie : Confirme ce que le noyau pense, pas ce que votre fstab souhaitait.

Décision : Si votre fstab indique nconnect=8 et que ce n’est pas présent ici, vous ne l’utilisez pas réellement. Corrigez l’automatisation de montage.

Tâche 3 : Mesurer la latence vers le serveur NFS (client)

cr0x@server:~$ ping -c 5 nas01
PING nas01 (10.10.10.10) 56(84) bytes of data.
64 bytes from 10.10.10.10: icmp_seq=1 ttl=64 time=0.312 ms
64 bytes from 10.10.10.10: icmp_seq=2 ttl=64 time=0.287 ms
64 bytes from 10.10.10.10: icmp_seq=3 ttl=64 time=0.301 ms
64 bytes from 10.10.10.10: icmp_seq=4 ttl=64 time=0.295 ms
64 bytes from 10.10.10.10: icmp_seq=5 ttl=64 time=0.289 ms

--- nas01 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4090ms
rtt min/avg/max/mdev = 0.287/0.296/0.312/0.009 ms

Ce que cela signifie : RTT sous la milliseconde sur LAN. Bien. Si c’est 2–5 ms, les charges sync se sentiront « collantes ».

Décision : Si le RTT est élevé ou instable, arrêtez de tuner ZFS. Corrigez d’abord le chemin réseau, les problèmes NIC ou le routage.

Tâche 4 : Vérifier les retransmissions TCP et les pertes (client)

cr0x@server:~$ netstat -s | egrep -i 'retrans|segments retransm|lost|timeouts' | head
    12 segments retransmitted
    0 retransmit timeouts
    0 connections reset due to unexpected data

Ce que cela signifie : Peu de retransmissions. Si cela augmente pendant les plaintes, vous perdez des paquets ou subissez un fort queueing.

Décision : Des retransmissions en hausse sous charge = vérifier les stats NIC, les ports de switch, le mismatch MTU, ou le bufferbloat.

Tâche 5 : Confirmer que le serveur NFS exporte bien ce que vous pensez (serveur)

cr0x@server:~$ exportfs -v
/tank/home  10.10.10.0/24(rw,async,wdelay,hide,no_subtree_check,sec=sys,secure,root_squash,no_all_squash)

Ce que cela signifie : L’export est async au niveau NFS (c’est le comportement de réponse du serveur, pas la sémantique sync de ZFS). Root squashing activé.

Décision : Si vous servez des bases de données/VM, réfléchissez attentivement à async. Beaucoup d’organisations gardent l’export NFS async mais comptent sur ZFS sync pour la durabilité ; d’autres exigent des exports synchros. Ne devinez pas—adaptez au modèle de risque.

Tâche 6 : Vérifier le nombre de threads nfsd (serveur Linux)

cr0x@server:~$ cat /proc/fs/nfsd/threads
32

Ce que cela signifie : 32 threads nfsd. Si vous avez des centaines de clients effectuant des ops metadata, trop peu de threads feront la queue.

Décision : Si le CPU est bas et que les clients sont en file d’attente, augmentez modérément les threads (ex. 64). Si le CPU est haut et la latence augmente, ajouter des threads peut empirer la situation.

Tâche 7 : Observer l’activité RPC NFS (serveur)

cr0x@server:~$ nfsstat -s
Server rpc stats:
calls      badcalls   badclnt    badauth   xdrcall
482913     0          0          0         0

Server nfs v4:
null         compound     read         write        getattr
0            412001       32941        21887        100221

Ce que cela signifie : Beaucoup de compound et getattr suggèrent du trafic lourd en métadonnées. Les compteurs read/write montrent le mix I/O.

Décision : Si getattr domine et que la latence souffre, envisagez un special vdev ZFS, focalisez l’ARC sur les métadonnées, et ajustez le caching d’attributs côté client.

Tâche 8 : Vérifier la santé du pool ZFS et les indicateurs d’E/S lentes (serveur)

cr0x@server:~$ zpool status -v
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 02:11:43 with 0 errors on Sun Dec 22 01:10:18 2025
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     0
            sdc     ONLINE       0     0     0
            sdd     ONLINE       0     0     0
            sde     ONLINE       0     0     0
            sdf     ONLINE       0     0     0

errors: No known data errors

Ce que cela signifie : Pool sain, scrub propre. Pas une preuve de performance, mais écarte « vdev dégradé » de la liste des suspects.

Décision : Si vous voyez un disque dégradé ou un resilver, arrêtez. Tuner la performance pendant un resilver, c’est comme tuner une voiture en feu au niveau des pneus.

Tâche 9 : Voir la latence ZFS en temps réel et le comportement sync (serveur)

cr0x@server:~$ zpool iostat -v tank 1 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        3.12T  8.54T    220   1450   48.1M  31.2M
  raidz2-0  3.12T  8.54T    220   1450   48.1M  31.2M
    sda         -      -     35    240   8.2M   5.3M
    sdb         -      -     36    241   8.1M   5.2M
    sdc         -      -     37    239   8.0M   5.3M
    sdd         -      -     37    242   8.0M   5.2M
    sde         -      -     38    243   8.0M   5.1M
    sdf         -      -     37    245   7.8M   5.1M

Ce que cela signifie : Les IOPS d’écriture sont élevés, le débit modéré — charge classique d’écritures petites. Un RAIDZ2 HDD faisant beaucoup d’E/S sync se sentira lent.

Décision : Si ce sont des VM/bases de données via NFS, envisagez un SLOG et un recordsize plus petit. Si c’est de la turbulence metadata, pensez special vdev et atime off.

Tâche 10 : Inspecter les propriétés clés du dataset (serveur)

cr0x@server:~$ zfs get -o name,property,value -s local,default recordsize,compression,atime,sync,logbias,primarycache tank/home
NAME       PROPERTY      VALUE
tank/home  recordsize    128K
tank/home  compression   lz4
tank/home  atime         off
tank/home  sync          standard
tank/home  logbias       latency
tank/home  primarycache  all

Ce que cela signifie : Valeurs par défaut sensées pour un usage général, mais recordsize peut être inadapté pour images VM ou bases de données.

Décision : Si ce dataset sert des disques VM, mettez recordsize plus petit (16K–32K) et envisagez primarycache=metadata selon la RAM et le schéma d’accès.

Tâche 11 : Vérifier la pression ARC et le taux de hits (serveur)

cr0x@server:~$ arcstat 1 3
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
12:01:11   780    90     11    22    2    68    9     0    0   42G   48G
12:01:12   802    95     12    24    2    71    9     0    0   42G   48G
12:01:13   799    88     11    21    2    67    8     0    0   42G   48G

Ce que cela signifie : ~11–12% de miss. Pas terrible. Si miss% grimpe pendant la charge, les disques seront frappés et la latence NFS augmentera.

Décision : Si l’ARC est trop restreint ou la mémoire manque, ajustez la taille de l’ARC (prudemment) ou concentrez la mise en cache sur les métadonnées via les propriétés dataset.

Tâche 12 : Vérifier la présence et le rôle du SLOG (serveur)

cr0x@server:~$ zpool status tank | sed -n '1,80p'
  pool: tank
 state: ONLINE
config:

        NAME          STATE     READ WRITE CKSUM
        tank          ONLINE       0     0     0
          raidz2-0    ONLINE       0     0     0
            sda       ONLINE       0     0     0
            sdb       ONLINE       0     0     0
            sdc       ONLINE       0     0     0
            sdd       ONLINE       0     0     0
            sde       ONLINE       0     0     0
            sdf       ONLINE       0     0     0
        logs
          nvme0n1p1   ONLINE       0     0     0

Ce que cela signifie : Un périphérique de log dédié existe. Bien. Maintenant assurez-vous que c’est la bonne classe de périphérique (latence, PLP).

Décision : S’il n’y a pas de SLOG et que vous avez des charges sync-heavy sur HDDs, ajoutez un SLOG en miroir à partir de périphériques de qualité entreprise.

Tâche 13 : Détecter la « douleur d’écriture sync » côté client (client)

cr0x@server:~$ dd if=/dev/zero of=/home/testfile bs=4k count=4096 conv=fdatasync status=progress
16777216 bytes (17 MB, 16 MiB) copied, 2.10 s, 8.0 MB/s
4096+0 records in
4096+0 records out
16777216 bytes (17 MB, 16 MiB) copied, 2.10 s, 8.0 MB/s

Ce que cela signifie : Les écritures 4K sync-flush sont lentes (8 MB/s). C’est la douleur que ressentent les utilisateurs sur les bases de données et journaux VM.

Décision : Si c’est « mauvais », ne chassez pas rsize/wsize. Chassez la qualité du SLOG, la latence du pool, et les sémantiques sync.

Tâche 14 : Comparer la performance streaming asynchrone (client)

cr0x@server:~$ dd if=/dev/zero of=/home/testfile2 bs=1M count=4096 status=progress
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 9.12 s, 471 MB/s
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 9.12 s, 471 MB/s

Ce que cela signifie : Les grosses écritures en streaming semblent excellentes. Ce contraste est classique : le débit est bon, la latence sync ne l’est pas.

Décision : Optimisez pour la charge que vous exécutez réellement. Si votre appli fait des 4K sync, concentrez-vous sur ZIL/SLOG et la latence, pas le débit.

Tâche 15 : Vérifier les suspects d’amplification d’écriture par dataset (serveur)

cr0x@server:~$ zfs get -o name,property,value copies,dedup,checksum tank/home
NAME       PROPERTY  VALUE
tank/home  copies    1
tank/home  dedup     off
tank/home  checksum  on

Ce que cela signifie : Pas de dedup (bon pour la plupart), copie unique, checksumming activé. Dedup activé sur un dataset NFS chargé est une histoire courante de « pourquoi tout est lent ? »

Décision : Si dedup est activé par accident, planifiez une migration hors de son dataset. Le désactiver n’undedupe pas les blocs existants.

Tâche 16 : Repérer les erreurs NIC et les mismatches MTU (serveur)

cr0x@server:~$ ip -s link show dev eno1
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 3c:fd:fe:aa:bb:cc brd ff:ff:ff:ff:ff:ff
    RX:  bytes packets errors dropped  missed   mcast
    918G  612M       0      12       0   1200
    TX:  bytes packets errors dropped carrier collsns
    877G  590M       0       3       0       0

Ce que cela signifie : Quelques drops. Pas forcément fatal, mais si les drops montent pendant les pics, la latence NFS et les retransmissions suivront.

Décision : Si MTU est 9000 ici mais 1500 ailleurs, corrigez le réseau. Si les drops persistent, vérifiez les buffers d’anneau, l’affinité IRQ, et la congestion du switch.

Playbook de diagnostic rapide

Quand quelqu’un dit « NFS est lent », vous avez besoin d’un plan qui trouve le goulot d’étranglement en quelques minutes, pas dans une file d’emails.
Voici l’ordre qui minimise le temps perdu.

Premièrement : décidez si c’est de la douleur de latence ou de débit

  • Douleur de latence : petites E/S, sync-heavy, ops metadata. Symptômes : git status lent, installations de paquets lentes, bases de données qui se plaignent de fsync, pauses VM.
  • Douleur de débit : gros transferts lents. Symptômes : sauvegardes ralenties, copies de gros fichiers sous-performantes par rapport à la vitesse du lien.

Exécutez la paire rapide : un dd sync-flush (Tâche 13) et un gros dd séquentiel (Tâche 14). Si le séquentiel va bien mais que le sync est terrible, vous avez déjà réduit le champ.

Deuxièmement : vérifiez le réseau pour une trahison évidente

  • Ping RTT et jitter (Tâche 3).
  • Retransmissions (Tâche 4).
  • Erreurs/interfaces drops (Tâche 16).

Si vous voyez des retransmissions augmenter pendant l’incident, arrêtez et corrigez le chemin réseau. Le tuning du stockage ne surclassera pas la perte de paquets.

Troisièmement : validez la sémantique de montage et la version du protocole

  • Confirmez options de montage et rsize/wsize négociés, version, proto (Tâches 1–2).
  • Vérifiez si nconnect est réellement en vigueur.
  • Recherchez actimeo=0 ou des timeouts bizarres.

Quatrièmement : identifiez si le serveur est lié CPU, threads, ou I/O

  • Threads serveur NFS (Tâche 6).
  • Mix d’opérations NFS (Tâche 7) : metadata vs data.
  • ZFS pool iostat (Tâche 9) : profil IOPS et bande passante.
  • Comportement ARC (Tâche 11) : manquez-vous le cache et allez-vous sur disque ?

Cinquièmement : confirmez le chemin sync (SLOG/ZIL) et les propriétés du dataset

  • Présence du SLOG (Tâche 12).
  • Dataset sync/logbias/recordsize (Tâche 10).
  • Surprises dedup/copies (Tâche 15).

Si c’est sync-heavy et que vous n’avez pas un SLOG approprié, vous avez votre réponse. Si vous en avez un, suspectez la qualité du dispositif SLOG ou sa saturation,
ou que vous ne l’utilisez pas réellement à cause des propriétés du dataset.

Trois mini-récits d’entreprise depuis le terrain

Incident : la mauvaise hypothèse (« NFS async signifie assez sûr »)

Une entreprise moyenne exécutait ses artefacts CI et une petite instance Postgres sur un export NFS soutenu par ZFS. L’équipe stockage avait configuré l’export NFS en async
parce que « ça améliorait la performance », et elle supposait que ZFS couvrirait la durabilité de toute façon. L’équipe applicative supposait « NFS est disque partagé, donc durable ».

Puis un événement d’alimentation est survenu. Pas dramatique — juste une brève coupure et un redémarrage chaotique. L’instance Postgres a redémarré, et a immédiatement commencé à signaler des pages corrompues.
Le système CI montrait aussi des morceaux d’artefacts manquants qui avaient été « uploadés avec succès » quelques minutes plus tôt. Le canal d’incident s’est rempli des classiques :
« Ça pourrait être DNS ? » et « Je pensais que ZFS empêchait la corruption. »

Le problème racine n’était pas une corruption ZFS. C’était la sémantique. Le serveur NFS avait répondu aux écritures avant qu’elles ne soient durables sur un stockage stable.
ZFS avait de l’intégrité, mais de l’intégrité de ce qui était effectivement commis. Certaines écritures acquittées ne sont jamais arrivées. Ce n’est pas un problème de checksum ; c’est un problème de promesse.

La correction n’a pas été un simple commutateur. Ils ont séparé les charges : les artefacts CI sont restés sur des exports async (risque acceptable, données recréables),
les bases de données ont été déplacées vers un export et une politique de dataset respectant la durabilité synchrone, avec un SLOG miroir entreprise.
Ils ont aussi documenté la politique dans le catalogue de services pour que « async » cesse d’être une mine invisible.

Optimisation qui a échoué : le pari recordsize

Une autre organisation servait des images VM via NFS depuis un nouveau pool ZFS brillant. Quelqu’un a remarqué le recordsize=128K par défaut et a décidé que « des blocs plus gros = plus rapide. »
Ils ont mis recordsize à 1M sur le dataset hébergeant les disques VM. Les tests initiaux semblaient excellents : copier de gros ISO était plus rapide, et un benchmark séquentiel synthétique
donnait un joli graphique.

Deux semaines plus tard, des plaintes de latence aléatoire ont commencé : temps de boot des VM erratiques, sessions interactives saccadées, et des logs hyperviseur montraient des timeouts d’E/S occasionnels.
Le serveur de stockage ne paraissait pas « occupé » en termes de bande passante, mais il était occupé de la pire manière : amplification read-modify-write et inefficacité du cache.
De petites écritures invitées forçaient le stockage à toucher de gros records, et l’ARC commençait à mettre en cache de gros blocs de données au lieu des métadonnées et des régions chaudes importantes.

Le dépannage a pris plus de temps qu’il n’aurait dû parce que tout le monde regardait le débit. Le débit allait bien. La latence tail non.
Finalement, quelqu’un a comparé les tailles d’E/S de l’hyperviseur avec le recordsize ZFS et a réalisé qu’ils avaient ajusté pour la mauvaise charge.

Le plan de récupération a été ennuyeux : nouveau dataset avec recordsize sensé (16K–32K), storage vMotion/migration des disques VM, et conservation du recordsize 1M pour les archives de sauvegarde.
Leçon : ne tunez pas un système de fichiers pour un benchmark que vous n’exécutez pas en production.

Pratique ennuyeuse mais correcte qui a sauvé la mise : datasets séparés, valeurs par défaut sensées, intention documentée

Une grande entreprise avait une « plateforme NFS » interne utilisée par dev, build, analytics, et quelques services stateful. Ils ont fait quelque chose de profondément peu sexy :
ils ont standardisé des templates de dataset. Les home dirs avaient un template ; les caches de build un autre ; les images VM un autre. Chaque template avait recordsize, atime, compression,
et politique de cache alignés sur le cas d’usage.

Lorsqu’un incident de performance a frappé pendant une grosse semaine de release, l’on-call n’a pas eu à deviner à quoi servait « ce partage ». Le nom du dataset codait l’intention, et les
propriétés correspondaient. Ils ont exécuté zfs get et ont immédiatement écarté les erreurs classiques : pas de dedup surprise, pas de sync=always accidentel,
pas de churn atime sur des partages read-heavy.

Le problème s’est avéré être la congestion réseau sur un ToR switch. Parce que la configuration stockage était prévisible, ils n’ont pas perdu des heures à basculer des réglages ZFS
et redémarrer des clients. Ils ont corrigé le queueing, et le problème a disparu.

Le gain n’était pas un réglage astucieux. Le gain était d’éliminer l’ambiguïté, ce qui est l’optimisation de performance la plus fiable que je connaisse.

Erreurs courantes : symptôme → cause racine → correction

1) « La copie d’un gros fichier est rapide, mais les bases de données sont lentes »

Symptôme : Un dd séquentiel semble excellent, mais tout ce qui fait fsync ralentit ; les invités VM bégayent.

Cause racine : Goulot d’étranglement de latence des écritures sync (pas de SLOG, SLOG faible, flush de pool lent).

Correction : Ajoutez un SLOG miroir adapté avec PLP ; gardez sync=standard. Vérifiez avec des tests sync-flush et observez la latence sous charge.

2) « Tout est devenu plus lent après qu’on ait mis actimeo=0 »

Symptôme : Builds et opérations de listing deviennent lents ; CPU serveur monte ; ops getattr explosent.

Cause racine : Cache d’attributs désactivé, causant une revalidation metadata constante.

Correction : Utilisez un actimeo=1 modéré ou réglez acregmin/acregmax plutôt que zéro ; ajoutez un special vdev pour les métadonnées si nécessaire.

3) « NFS se bloque indéfiniment quand le serveur est down »

Symptôme : Processus coincés en état D ; attentes d’I/O in-killables.

Cause racine : Montage hard qui tient sa promesse, plus une application incapable de tolérer des I/O bloquantes.

Correction : Gardez les montages hard pour la cohérence, mais tunez timeo/retrans sensiblement et concevez des apps avec timeouts ; pour des montages non critiques, envisagez des chemins séparés ou des caches locaux.

4) « Les I/O aléatoires sont terribles sur un pool RAIDZ »

Symptôme : Charge d’écriture IOPS élevée donne une latence affreuse ; iostat montre beaucoup de petites écritures sur les vdevs HDD.

Cause racine : RAIDZ + petites écritures aléatoires + sémantique sync = amplification d’écriture et tempêtes de seeks.

Correction : Utilisez des mirrors pour des pools écriture-aléatoire-intensifs, ou assurez-vous que la charge est cachée/agrégée ; ajoutez un SLOG pour le sync, tunez recordsize, et envisagez un special vdev pour metadata/petits blocs.

5) « On a ajouté des threads nfsd et c’est devenu pire »

Symptôme : Usage CPU en flèche, changement de contexte en hausse, latence augmente.

Cause racine : Trop de threads serveur causant contention et overhead du scheduler.

Correction : Réduisez les threads à un point mesuré optimal ; concentrez-vous sur l’affinité CPU, les interruptions réseau, et la latence du stockage sous-jacent.

6) « Après avoir activé les jumbo frames, certains clients sont aléatoirement lents »

Symptôme : Certains sous-réseaux ou hôtes voient des timeouts, retransmissions ; d’autres sont OK.

Cause racine : Mismatch MTU quelque part sur le chemin causant fragmentation ou pertes.

Correction : Assurez une cohérence MTU bout en bout ou revenez à 1500 ; validez avec des pings DF et vérifications de configuration de switch.

7) « Le taux de hit ARC est correct mais nous sommes toujours lents »

Symptôme : miss% ARC correct, pourtant plaintes clients ; le pool montre une pression d’écriture sync.

Cause racine : Le cache n’aide pas la latence d’engagement sync ; le goulot est le temps de flush/commit.

Correction : Investissez dans un SLOG et des périphériques basse latence ; réduisez les I/O sync là où c’est correct (réglages applicatifs), pas là où c’est dangereux (sync=disabled).

8) « On a activé dedup et maintenant le serveur NFS est hanté »

Symptôme : Pics de latence, pression mémoire, performance imprévisible.

Cause racine : Dedup requiert de grandes structures metadata chaudes ; si mal dimensionnées, ça thrash et pénalise chaque I/O.

Correction : N’utilisez pas dedup pour un NFS générique. Migrez les données hors du dataset dedup ; conservez la compression.

Blague #2 : Dedup est l’équivalent stockage d’adopter un raton laveur — parfois mignon, mais il mettra le bazar partout.

Listes de vérification / plan pas à pas

Plan A : faire qu’un partage ZFS+NFS existant ressemble à local pour des utilisateurs généraux

  1. Baseliner le montage client. Confirmez vers, proto=tcp, hard, et rsize/wsize négociés (Tâches 1–2).
  2. Définir des options de montage sensées. Point de départ typique : NFSv4.2, rsize/wsize=1M, hard, timeo ajusté, et envisagez nconnect=4 ou 8 pour les clients chargés.
  3. Désactiver atime sur le dataset. zfs set atime=off pour les partages utilisateurs sauf exigence contraire.
  4. Activer compression lz4. zfs set compression=lz4.
  5. Surveiller le comportement metadata. Si getattr domine (Tâche 7), envisagez un caching d’attributs modéré et un special vdev pour metadata.
  6. Valider la santé réseau. RTT, retransmissions, drops (Tâches 3–4, 16).
  7. Retester avec des workflows réels. Opérations git, builds, navigation de fichiers, pas seulement un gros dd.

Plan B : servir des images VM via NFS sans regrets

  1. Créer un dataset dédié. Ne réutilisez pas le dataset « home dirs » en espérant que ça ira.
  2. Définir recordsize en fonction des E/S. Commencez à 16K ou 32K pour les disques VM. Testez les deux.
  3. Garder sync honnête. Utilisez sync=standard. Ajoutez un SLOG miroir adapté si vous êtes sur HDD ou si la latence sync est élevée.
  4. Considérer la stratégie de cache. Souvent primarycache=metadata aide si le dataset est volumineux et que l’ARC serait pollué par les données invitées.
  5. Mesurer la latence sync. Utilisez des tests sync-flush (Tâche 13) et observez zpool iostat sous charge (Tâche 9).
  6. Valider le comportement de basculement. La récupération client NFS et les attentes de l’hyperviseur peuvent créer des problèmes qui ressemblent à du « stockage ».

Plan C : builds lourds en métadonnées et arbres source

  1. Prioriser les métadonnées. Envisagez un special vdev pour metadata/petits blocs.
  2. Utiliser compression et atime=off. Réduisez le churn I/O.
  3. Tuner le caching d’attributs. Ne mettez pas actimeo=0 à moins d’aimer la douleur auto-infligée.
  4. Surveiller le CPU serveur et les threads nfsd. Augmentez les threads seulement si vous voyez de la file d’attente, pas par rituel.
  5. S’assurer que l’ARC a de l’air. Le cache des métadonnées est votre meilleur allié ici.

FAQ

1) Dois-je utiliser NFSv3 ou NFSv4.2 ?

Par défaut, privilégiez NFSv4.2 sur Linux moderne sauf raison de compatibilité. NFSv3 peut être plus simple et parfois plus facile à déboguer, mais les fonctionnalités v4.x
réduisent souvent le bavardage et améliorent la posture de sécurité.

2) Quel rsize/wsize dois-je utiliser ?

Commencez par 1M quand c’est possible. Si la négociation revient en arrière, vous le verrez dans nfsstat -m. Si votre charge est sensible à la latence et heavy small-IO,
rsize/wsize ne vous sauvera pas de la latence sync — SLOG et conception du pool le feront.

3) nconnect est-il toujours bon ?

Souvent bon pour le débit et le parallélisme, surtout sur des liens rapides et des serveurs multicœurs. Mais il augmente l’état de connexion et peut exposer la contention côté serveur.
Essayez 4 ou 8, mesurez, et ne supposez pas que « plus » est mieux.

4) Ai-je besoin d’un SLOG ?

Si vous avez des charges sync-heavy (bases de données, images VM, tout ce qui fait fréquemment fsync) et que votre pool n’a pas déjà une latence excellente, oui. Pour des pools tout-flash
avec une latence excellente, un SLOG peut ne pas aider beaucoup. Mesurez avec des écritures sync-flush.

5) Puis-je simplement mettre sync=disabled pour améliorer la performance ?

Vous pouvez, et ça paraîtra super — jusqu’à ce que vous crashiez et perdiez des écritures acquittées. Pour des données jetables, peut-être. Pour tout ce qui compte, ne le faites pas.
Corrigez le chemin de latence réel à la place.

6) Quel recordsize ZFS devrais-je utiliser pour des partages NFS ?

Pour des partages généraux : 128K convient. Pour images VM et bases de données : commencez à 16K ou 32K. Pour de grandes archives séquentielles : plus grand peut aider.
La bonne valeur dépend de la forme d’E/S, pas de la vitesse du lien.

7) La compression aide ou nuit à la performance NFS ?

Elle aide souvent. Moins de données sur disque et réseau, parfois meilleure utilisation du cache. lz4 est le choix habituel. Si le CPU est saturé et les I/O faibles,
alors testez, mais ne désactivez pas la compression par superstition.

8) Pourquoi mon partage NFS est-il lent seulement aux heures de pointe ?

Congestion et mise en file. Vérifiez les retransmissions, l’utilisation des ports de switch, les drops d’interface, et la charge softirq CPU du serveur. Le stockage peut être OK ; le réseau peut construire des files qui amplifient la latence tail.

9) Dois-je utiliser un special vdev ?

Si votre charge est lourde en métadonnées ou si vous avez des millions de petits fichiers, un special vdev sur SSD rapides peut changer la donne.
Mais traitez-le comme un vdev critique : mettez-le en miroir et surveillez-le, car sa perte peut compromettre le pool selon la config.

10) Comment savoir si le goulot est le serveur NFS ou le pool ZFS ?

Regardez nfsstat -s côté serveur pour le mix et le volume d’opérations, puis corrélez avec zpool iostat. Si les ops NFS grimpent mais que le pool reste inactif,
suspectez CPU/threading/réseau. Si les IOPS et la latence du pool montent, suspectez la conception du stockage (chemin sync, layout des vdevs, recordsize, misses de cache).

Conclusion : prochaines étapes pratiques

Si vous voulez que ZFS sur NFS ressemble à un disque local, optimisez pour la latence tail et les sémantiques, pas pour de jolis graphiques de débit.
Commencez par les bases : confirmez les montages, vérifiez la santé du réseau, observez la forme d’E/S, puis alignez les propriétés ZFS du dataset sur la charge.

  1. Exécutez les deux tests clients rapides : sync-flush et débit séquentiel (Tâches 13 et 14). Décidez si vous luttez contre la latence ou la bande passante.
  2. Vérifiez les options NFS négociées et corrigez les incompatibilités (Tâches 1–2). Ne déboguez pas ce que vous n’avez pas réellement configuré.
  3. Vérifiez le RTT réseau et les retransmissions (Tâches 3–4). Si des paquets tombent, le tuning stockage n’est qu’un déni élaboré.
  4. Côté serveur, corrélez le mix d’opérations NFS avec le comportement du pool ZFS (Tâches 7–9). Identifiez si c’est metadata, sync, ou I/O brute.
  5. Appliquez des changements ZFS ciblés : recordsize par charge, compression activée, atime off, et un SLOG adapté là où le sync compte (Tâches 10–12).

Puis notez ce que vous avez choisi et pourquoi. Le vous du futur sera fatigué, en astreinte, et allergique aux boutons mystères.

← Précédent
Barre de progression de lecture pour articles : CSS d’abord, JS minimal qui ne gâchera pas l’UX
Suivant →
CLUF que personne ne lit : le contrat que tout le monde signe

Laisser un commentaire