Le pire type de problème de stockage est celui qui « fonctionne la plupart du temps ». La VM démarre. La base de données passe ses tests de fumée.
Puis quelqu’un lance une vraie charge à 10:14 un mardi et votre graphique de latence iSCSI devient une œuvre d’art moderne.
Le symptôme est une saccade : des arrêts périodiques, des latences en longue traîne, et des utilisateurs qui décrivent ça comme une « lenteur » comme si c’était une vraie métrique.
Si vous exportez des ZVOLs ZFS via iSCSI, vous tenez une chaîne de couteaux aiguisés : groupes de transactions ZFS, sémantique sync,
filetage iSCSI, multipath, et cache du système invité. Si vous vous trompez de géométrie, vous passerez la semaine à blâmer « le réseau »
pendant que ZFS attend poliment que votre petit SLOG cesse de fondre.
Modèle mental : d’où viennent les saccades
Les « saccades » sous charge sont rarement un problème de débit brut. C’est de la variance. Votre I/O médiane semble correcte, mais votre centile 99,9 devient moche :
l’invité se fige, le checkpoint de la base de données ralentit, l’hyperviseur panique et réessaye, et l’équipe applicative ouvre un ticket intitulé
« Le stockage se fige aléatoirement ».
Avec des ZVOLs ZFS exportés via iSCSI, les saccades proviennent généralement d’un des goulets d’étranglement suivants :
- Gestion des écritures synchrones : le client émet une écriture avec sémantique FUA/flush ; ZFS doit l’engager de façon sûre. Sans SLOG approprié, il y a des pics de latence.
- Comportement des transaction groups (TXG) : ZFS regroupe les écritures et les synchronise périodiquement. Des limites de données sales mal dimensionnées ou un pool lent peuvent faire exploser le temps de sync des TXG.
- Inadéquation de la taille de bloc : le client effectue des écritures aléatoires 4K mais votre ZVOL a volblocksize 128K, forçant une amplification read-modify-write.
- Mise en file et backpressure : la profondeur de file de l’initiateur iSCSI, la mise en file côté target et les files de vdev ZFS peuvent provoquer un comportement en « scie » de la latence.
- Outliers de latence niveau physique : un SSD qui se meurt, un HBA qui se comporte mal, un chemin qui clignote en multipath. ZFS vous le dira, si vous posez les bonnes questions.
L’objectif pratique : une latence prévisible sous charge soutenue, même si le débit maximum baisse un peu.
En production, l’ennuyeux et constant l’emporte.
Faits et contexte intéressants (pour arrêter de répéter l’histoire)
- ZFS est né chez Sun au milieu des années 2000 comme une pile de stockage bout-en-bout : checksums, stockage poolé, snapshots et copy-on-write. Ce n’est pas « un système de fichiers sur RAID » autant que « du stockage qui refuse de mentir ».
- Le copy-on-write rend les snapshots peu coûteux, mais signifie aussi que les réécritures deviennent de nouvelles écritures, et la fragmentation existe. Les charges en bloc qui effectuent beaucoup de réécritures aléatoires peuvent « vieillir » un pool plus vite que prévu.
-
Les ZVOLs ne sont pas des fichiers. Un ZVOL est un périphérique bloc géré par ZFS. Cette distinction compte : les ZVOLs n’ont pas de
recordsize; ils ontvolblocksize, et il est plus difficile à modifier ensuite. - iSCSI date des années 1990 comme « SCSI sur TCP ». Il a gagné parce qu’Ethernet a gagné, pas parce que c’est charmant. C’est aussi la raison pour laquelle « performance de stockage » peut être affectée par de petits comportements TCP.
- Le ZFS Intent Log (ZIL) existe pour rendre les écritures synchrones durables. Le périphérique de log séparé (SLOG) n’est pas un cache d’écriture ; c’est un point d’atterrissage à faible latence pour l’intention d’écriture synchrone.
- Les premières recommandations ZFS étaient façonnées par les disques spinning et les grosses écritures séquentielles. Les pools modernes SSD/NVMe déplacent le goulot d’étranglement du temps de seek vers l’amplification de latence et le comportement de mise en file.
- Les secteurs 4K ont tout changé (Advanced Format). Si vous alignez mal ashift, vous pouvez transformer involontairement une écriture 4K en un read-modify-write au niveau du disque. C’est une taxe que vous payez pour toujours.
- La compression faisait peur sur les charges bloc. LZ4 moderne est suffisamment rapide pour qu’activer la compression réduise souvent les I/O et améliore la latence, surtout pour les images VM et les bases de données avec motifs répétitifs.
- Le multipath servait à la redondance mais sert aujourd’hui aussi à la performance. Si vous le configurez mal, vous pouvez vous équilibrer vers la perte de paquets et les timeouts.
Choix d’architecture qui comptent (et ceux qui n’en valent pas la peine)
Choisir ZVOL vs dataset comme si vous le pensiez vraiment
Si le client attend un périphérique bloc (datastore hyperviseur, volume Windows, base de données clusterisée qui veut des disques bruts), utilisez un ZVOL.
Si vous pouvez présenter des fichiers (NFS, SMB) et que vous contrôlez les patterns d’I/O de l’application, un dataset est souvent plus simple à régler et à observer.
Mais cet article porte sur les ZVOLs, donc on reste sur ce front.
Volblocksize : la décision de « format » que vous ne refaites pas facilement
volblocksize est la taille de bloc interne que ZFS utilise pour le ZVOL. Elle influence fortement l’amplification d’écriture et le churn des métadonnées.
Les blocs plus petits conviennent mieux aux I/O aléatoires. Les blocs plus grands réduisent l’overhead des métadonnées pour les charges séquentielles mais pénalisent les petites écritures aléatoires.
- Disques système/boot de VM : 8K ou 16K est un bon point de départ. 8K l’emporte souvent pour les lectures/écritures aléatoires mixtes. 16K peut réduire l’overhead si la charge n’est pas trop bavarde.
- Bases de données (OLTP-ish) : 8K si la taille de page DB est 8K (fréquent). Alignez sur la réalité. Ne combattez pas la physique.
- Grand séquentiel (cibles de sauvegarde, médias) : 64K–128K peuvent convenir, mais n’exportez pas ça comme datastore VM général à moins d’aimer les saccades mystères.
Vous pouvez changer volblocksize seulement en recréant le ZVOL et en migrant les données. Ce n’est pas un projet de week-end en production.
Ashift : décidez une fois, subissez toujours
ashift est l’exposant de la taille de secteur du pool (par ex., 12 signifie 2^12 = 4096 octets). Si vos dispositifs physiques sont 4K (ils le sont), mettez ashift=12.
Pour beaucoup de SSD, 12 est correct ; pour certains dispositifs 8K, vous pourriez vouloir 13.
L’essentiel : ne laissez pas « auto-detect » se tromper et ne le découvrir qu’après que votre pool contient des données.
Écritures synchrones : comprenez ce que le client vous demande de garantir
Les écritures synchrones sont la partie où le système de stockage promet que les données ne disparaîtront pas en cas de coupure de courant.
Sur iSCSI, les invités et les systèmes de fichiers émettent des flushs et des écritures FUA plus souvent qu’on ne le pense—surtout dans les stacks virtualisés.
ZFS peut gérer les écritures synchrones sans SLOG en écrivant sur le pool principal, mais la latence suivra la latence d’écriture stable du vdev le plus lent.
Si vous tenez à la latence en queue, vous voulez probablement un SLOG dédié sur SSD/NVMe bas-latence avec protection contre la perte de puissance (PLP).
SLOG : pas « plus de cache », mais « moins d’attente »
Un SLOG accélère l’accusé de réception des écritures synchrones en persistant rapidement l’intention. Plus tard, ZFS flushera le transaction group vers le pool principal.
Si votre charge sync est lourde, le SLOG doit :
- Faible latence sous écritures soutenues (pas seulement « rapide en séquentiel »).
- Protection contre la perte de puissance ou vous pouvez perdre des écritures synchrones reconnues.
- Endurance suffisante pour le taux d’écriture (les écritures ZIL peuvent être brutales).
Blague n°1 : Acheter un « NVMe gaming » pour SLOG, c’est comme engager un sprinteur comme veilleur de nuit—rapide oui, mais endormi quand le courant coupe.
Compression : activez-la sauf raison forte contraire
Utilisez compression=lz4 pour la plupart des charges ZVOL. Même si les données ne compressent pas beaucoup, le surcoût est faible sur les CPU modernes.
Le gain est souvent moins d’octets écrits sur disque et moins d’I/O, ce qui peut réduire la latence.
Dedup : n’en faites pas
La dedup sur ZVOLs est un classique « ça avait l’air bien sur une slide ». Elle augmente la pression mémoire et peut amplifier la latence.
À moins d’avoir modélisé, mesuré et de pouvoir payer la RAM et la complexité opérationnelle, n’en mettez pas.
vdevs spéciaux et métadonnées : utiles, mais faciles à mal utiliser
Les dispositifs d’allocation spéciale peuvent accélérer les métadonnées et les petits blocs.
Sur des systèmes à forte utilisation de ZVOLs, cela peut aider certains patterns, mais c’est aussi un nouveau domaine de fiabilité.
Si vous perdez un special vdev qui contient des métadonnées, vous pouvez perdre le pool à moins qu’il soit correctement mirroré.
Traitez-le comme du stockage central, pas comme un « SSD bonus ».
Réseau : 10/25/40/100GbE ne corrige pas la latence
iSCSI est sensible à la perte, à la pression des buffers et à l’instabilité de chemins. Un lien rapide avec micro-burst peut toujours provoquer des saccades.
Votre objectif est une latence constante, pas seulement des gros chiffres dans iperf.
Construire une cible iSCSI ZVOL qui reste fluide
Hypothèses de base
Les exemples supposent un hôte ZFS basé sur Linux exécutant OpenZFS, exportant des LUNs bloc via iSCSI en utilisant LIO (targetcli).
Le client est un initiateur Linux, mais nous signalerons les particularités Windows/ESXi.
Adaptez à votre plateforme, mais gardez les principes : alignez la géométrie, respectez le sync, et mesurez la latence là où elle est créée.
Disposition du pool : les mirrors surpassent RAIDZ pour latence d’écriture aléatoire
Pour les charges VM/bloc iSCSI, les mirrors surpassent généralement RAIDZ en latence et en cohérence d’IOPS. RAIDZ peut convenir pour des charges essentiellement séquentielles
ou majoritairement en lecture, mais les petites écritures aléatoires doivent toucher la parité et peuvent amplifier la latence pendant les rebuilds.
Si vous devez utiliser RAIDZ pour des raisons de capacité, prévoyez des écritures sync plus lentes et des latences de queue plus prononcées pendant les scrubs/resilvers.
Vous pouvez quand même faire de la production dessus ; vous n’avez juste pas le droit d’être surpris.
Créer le ZVOL avec des propriétés sensées
Un bon ensemble de départ pour un ZVOL de type datastore VM général :
volblocksize=8Kou16Kselon la chargecompression=lz4sync=standard(ne pas mettredisabledpour « corriger » la latence sauf si vous aimez la perte de données)logbias=latencypour les charges sync-intensives (courant pour le stockage VM)
Décidez aussi si vous voulez la provisionnement fin (thin). Les ZVOLs peuvent être sparse (thin) ou thick. Le thin est pratique. Le thin permet aussi aux gens
de surpromettre jusqu’à ce que le pool atteigne 100% et que tout devienne un incident au ralenti.
Exportez-le via iSCSI avec une mise en file prévisible
Avec LIO, vous ferez typiquement :
- Créer un backstore pointant sur le ZVOL
- Créer un IQN de cible iSCSI et un portail
- Créer un mapping de LUN et des ACL
- Optionnellement régler sessions, recovery d’erreur et timeouts
Là où se cachent les saccades : un trop grand nombre d’I/O en attente peut faire paraître la latence comme un « gel périodique » quand la file se vide.
Un sous-réglage peut plafonner le débit, mais un sur-réglage provoque des pics de latence en queue et des timeouts. Vous voulez suffisamment de profondeur de file pour saturer les disques,
pas assez pour créer un embouteillage I/O.
Multipath côté client : ennuyeux, spécifique et obligatoire en production
Le multipath résout deux problèmes : basculement et distribution de charge. Il crée aussi un tout nouveau mode de défaillance : path flapping, où le client
bascule sans cesse entre les chemins et votre stockage semble « perdre des paquets » alors qu’en réalité il est yo-yo par la politique.
Utilisez deux chemins physiquement séparés si vous revendiquez la redondance. NICs séparées, switches séparés si possible, tout séparé. Sinon, c’est du théâtre.
Une citation qui appartient vraiment aux opérations
« L’espoir n’est pas une stratégie. » — idée paraphrasée souvent attribuée aux opérateurs et ingénieurs en fiabilité
Tâches pratiques : commandes, sorties et décisions
Vous ne pouvez pas régler ce que vous ne pouvez pas observer. Ci‑dessous des tâches pratiques à exécuter sur la cible ZFS/iSCSI et l’initiateur.
Chaque tâche inclut : la commande, ce que signifie une sortie typique, et la décision que vous en tirez.
Task 1: Verify pool health and obvious hardware errors
cr0x@server:~$ sudo zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 0 days 02:11:43 with 0 errors on Sun Dec 22 03:10:16 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
nvme3n1 ONLINE 0 0 0
errors: No known data errors
Signification : tout READ/WRITE/CKSUM non nul est un indice, pas une suggestion. Même un seul dispositif instable peut créer des « saccades »
à cause des réessais et des terminaisons d’I/O lentes.
Décision : si vous voyez des erreurs ou un vdev dégradé, arrêtez les réglages. Réparez le matériel d’abord. Travailler la performance sur un stockage cassé, c’est du cosplay.
Task 2: Confirm ashift and vdev topology (latency expectations start here)
cr0x@server:~$ sudo zdb -C tank | egrep -i 'ashift|vdev_tree|type'
type: 'root'
type: 'mirror'
ashift: 12
type: 'mirror'
ashift: 12
Signification : ashift=12 indique un alignement secteur 4K. Si vous découvrez ashift=9/10/11 sur des dispositifs 4K, vous avez trouvé une taxe permanente.
Décision : ashift incorrect signifie généralement « reconstruire le pool correctement ». Si ce n’est pas possible immédiatement, documentez le risque et arrêtez de promettre une faible latence.
Task 3: Check how full the pool is (ZFS gets cranky when it’s crowded)
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint tank
NAME USED AVAIL REFER MOUNTPOINT
tank 18.2T 2.11T 256K /tank
Signification : avec seulement ~10% libre, la fragmentation et le comportement de l’allocateur peuvent augmenter la variance de latence, surtout sur les charges bloc.
Décision : visez à garder un espace libre significatif (souvent 20%+ pour les pools occupés). Si vous êtes juste, planifiez de la capacité avant de régler les profondeurs de file.
Task 4: Inspect the ZVOL properties (block size, compression, sync)
cr0x@server:~$ zfs get -o name,property,value -s local,default volblocksize,compression,sync,logbias,refreservation tank/zvol/vmstore
NAME PROPERTY VALUE
tank/zvol/vmstore volblocksize 8K
tank/zvol/vmstore compression lz4
tank/zvol/vmstore sync standard
tank/zvol/vmstore logbias latency
Signification : c’est votre checklist de base « est-ce que c’est sensé ». sync=disabled sur un datastore VM est un drapeau rouge sauf décision de risque explicite.
Décision : si volblocksize est manifestement inadapté à la charge (par ex., 128K pour OLTP), planifiez une migration vers un nouveau ZVOL. Ne prétendez pas que c’est un réglage sysctl.
Task 5: Create a ZVOL correctly (example) and explain why
cr0x@server:~$ sudo zfs create -V 4T -b 8K -o compression=lz4 -o logbias=latency -o sync=standard tank/zvol/vmstore2
Signification : -V crée un volume bloc, -b définit volblocksize à la création, et nous choisissons explicitement un comportement favorable à la latence pour les écritures synchrones.
Décision : choisissez 8K quand vous ne savez pas et que vous attendez des écritures aléatoires. Choisissez 16K si votre charge est mixte mais pas très petite et que vous voulez un peu moins de métadonnées.
Task 6: Confirm the block device exists and see its sector sizes
cr0x@server:~$ ls -l /dev/zvol/tank/zvol/vmstore2
lrwxrwxrwx 1 root root 13 Dec 25 10:12 /dev/zvol/tank/zvol/vmstore2 -> ../../zd16
cr0x@server:~$ sudo blockdev --getss /dev/zd16
4096
cr0x@server:~$ sudo blockdev --getpbsz /dev/zd16
4096
Signification : le ZVOL présente ici des secteurs logiques 4K. C’est typiquement bon pour des invités modernes et s’aligne sur ashift=12.
Décision : si votre stack initiateur/OS attend 512 et que vous présentez du 4K, certains anciens invités se comportent mal. Pour les systèmes modernes, 4K est généralement correct et souvent meilleur.
Task 7: Verify whether you have a dedicated SLOG and whether it’s mirrored
cr0x@server:~$ sudo zpool status tank | sed -n '1,120p'
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
nvme3n1 ONLINE 0 0 0
logs
mirror-2 ONLINE 0 0 0
nvme4n1 ONLINE 0 0 0
nvme5n1 ONLINE 0 0 0
Signification : un SLOG mirror réduit le risque qu’une défaillance d’un périphérique de log entraîne la perte d’écritures sync récentes (selon le mode de défaillance).
Décision : si vous exécutez beaucoup de sync iSCSI et que vous tenez à la correction, utilisez un SLOG mirroré avec PLP. Si vous ne pouvez pas, acceptez une latence sync plus élevée et ajustez vos attentes, pas la physique.
Task 8: Watch ZFS latency and queueing in real time
cr0x@server:~$ sudo zpool iostat -v tank 1
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 18.2T 2.11T 820 1900 91.3M 76.2M
mirror - - 410 950 45.6M 38.1M
nvme0n1 - - 205 470 22.8M 19.3M
nvme1n1 - - 205 480 22.8M 18.8M
mirror - - 410 950 45.7M 38.1M
nvme2n1 - - 205 475 22.9M 19.1M
nvme3n1 - - 205 475 22.8M 19.0M
logs - - 0 600 0 12.0M
mirror - - 0 600 0 12.0M
nvme4n1 - - 0 300 0 6.0M
nvme5n1 - - 0 300 0 6.0M
Signification : vous pouvez voir si les écritures frappent le périphérique de log (charge sync) et si un vdev traîne.
Décision : si un dispositif montre constamment moins d’opérations ou de bande passante sous mirror, suspectez la latence du dispositif, le firmware, la limitation thermique ou des problèmes de topologie PCIe.
Task 9: Check TXG behavior and “stutter cadence” clues
cr0x@server:~$ sudo arcstat.py 1 5
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
10:20:01 920 80 8 0 0% 40 50% 40 50% 128G 128G
10:20:02 980 70 7 0 0% 35 50% 35 50% 128G 128G
10:20:03 910 95 10 0 0% 47 49% 48 51% 128G 128G
10:20:04 940 82 9 0 0% 41 50% 41 50% 128G 128G
10:20:05 960 78 8 0 0% 39 50% 39 50% 128G 128G
Signification : la pression ARC et les misses se corrèlent souvent avec la latence de lecture, pas les saccades d’écriture. Mais si votre « saccade » est en réalité des tempêtes de misses du cache lecture,
cela le montrera : taux de miss élevé pendant que l’application se fige.
Décision : si l’ARC est saturé et miss% élevé, envisagez de la mémoire, une taille de working set, ou de déplacer les charges lecture-intensives vers des protocoles fichiers où le caching fonctionne mieux.
Ne sautez pas sur L2ARC avant de l’avoir mesuré.
Task 10: Confirm iSCSI target configuration and mapped LUNs
cr0x@server:~$ sudo targetcli ls
o- / ............................................................................. [...]
o- backstores ................................................................. [...]
| o- block ............................................................. [Storage Objects: 1]
| | o- vmstore2 ........................................ [/dev/zvol/tank/zvol/vmstore2 (4.0TiB)]
o- iscsi ............................................................... [Targets: 1]
o- iqn.2025-12.lab:storage.tank ............................................. [TPGs: 1]
o- tpg1 .......................................................... [no-gen-acls, no-auth]
o- acls ............................................................... [ACLs: 1]
| o- iqn.2025-12.lab:client01 .............................................. [Mapped LUNs: 1]
o- luns ............................................................... [LUNs: 1]
| o- lun0 ............................... [block/vmstore2 (/dev/zvol/tank/zvol/vmstore2)]
o- portals ......................................................... [Portals: 1]
o- 10.0.10.10:3260 .............................................................. [OK]
Signification : vérifiez que le backstore pointe vers le ZVOL prévu et que les ACL mappent le bon IQN d’initiateur.
Décision : si vous voyez des backstores fileio pour du stockage VM haute performance, reconsidérez : les backstores bloc vers ZVOLs sont typiquement plus propres et plus rapides.
Task 11: On the initiator, confirm sessions and negotiated parameters
cr0x@server:~$ sudo iscsiadm -m session -P 3 | sed -n '1,120p'
iSCSI Transport Class version 2.0-870
iscsiadm version 2.1.9
Target: iqn.2025-12.lab:storage.tank
Current Portal: 10.0.10.10:3260,1
Persistent Portal: 10.0.10.10:3260,1
DataDigest: None
HeaderDigest: None
MaxRecvDataSegmentLength: 262144
MaxXmitDataSegmentLength: 262144
FirstBurstLength: 262144
MaxBurstLength: 1048576
InitialR2T: No
ImmediateData: Yes
Signification : ces paramètres influencent la performance et le coût CPU. Les digests ajoutent une charge CPU mais aident à détecter la corruption sur de mauvais réseaux.
La plupart des réseaux DC propres fonctionnent sans digest.
Décision : si le CPU est le goulot ou si vous voyez des retransmissions, revoyez d’abord le réseau et le MTU. Ne « tunez » pas les bursts iSCSI en première intention ; ce n’est rarement le principal problème.
Task 12: Verify multipath status (path flaps create “stutter”)
cr0x@server:~$ sudo multipath -ll
mpatha (36001405f3f2b7f8d9d5b3d2a8c1e0001) dm-3 IET,VIRTUAL-DISK
size=4.0T features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=50 status=active
| `- 4:0:0:0 sdb 8:16 active ready running
`-+- policy='service-time 0' prio=50 status=enabled
`- 5:0:0:0 sdc 8:32 active ready running
Signification : vous voulez des chemins stables « active ready running ». Si vous voyez des chemins alternant entre failed/active, c’est votre générateur de pics de latence.
Décision : corrigez le câblage/le switching/les NIC/les MTU avant de toucher aux tunables ZFS. Le tuning stockage ne peut pas voter contre la physique et la perte de paquets.
Task 13: Check for TCP retransmits and NIC drops on the target
cr0x@server:~$ sudo nstat -az | egrep 'TcpRetransSegs|TcpExtTCPRenoReorder|IpInDiscards'
TcpRetransSegs 12 0.0
IpInDiscards 0 0.0
Signification : les retransmissions ajoutent de la variance à la latence. Quelques-unes sur une longue uptime sont acceptables ; une montée rapide sous charge ne l’est pas.
Décision : si les retransmissions montent pendant vos « saccades », investigatez buffers de switch/ECN, mismatch MTU, optiques/câbles défectueux, ou saturation IRQ/CPU sur la NIC.
Task 14: Observe disk latency directly (don’t guess)
cr0x@server:~$ sudo iostat -x 1 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
12.10 0.00 5.20 2.80 0.00 79.90
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %util await r_await w_await
nvme0n1 210.0 480.0 24000 20000 0.0 0.0 71.0 1.80 1.20 2.10
nvme1n1 215.0 470.0 24500 19800 0.0 0.0 69.0 1.90 1.30 2.20
nvme2n1 205.0 475.0 23500 19900 0.0 0.0 73.0 1.70 1.10 2.00
nvme3n1 205.0 475.0 23600 20100 0.0 0.0 72.0 1.75 1.15 2.05
Signification : si await saute dans les dizaines/centaines de millisecondes pendant une saccade, vos dispositifs de pool sont le goulot (ou sont forcés en waits sync).
Décision : si la latence des dispositifs est correcte mais que le client voit des saccades, suspectez la mise en file iSCSI, les flaps multipath, ou le comportement des écritures synchrones (SLOG, tempêtes de flush).
Task 15: Identify synchronous write pressure (ZIL/SLOG usage clues)
cr0x@server:~$ sudo zfs get -o name,property,value sync,logbias tank/zvol/vmstore2
NAME PROPERTY VALUE
tank/zvol/vmstore2 sync standard
tank/zvol/vmstore2 logbias latency
cr0x@server:~$ sudo zpool iostat -v tank 1 | sed -n '1,20p'
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 18.2T 2.11T 200 2400 22.0M 98.0M
logs - - 0 1200 0 24.0M
Signification : des ops d’écriture significatives sur logs indiquent une activité sync (ZIL). Si vous n’avez pas de SLOG, ces écritures sync frappent les vdevs principaux et peuvent faire monter la latence.
Décision : si votre charge est sync-intensive et sensible à la latence, implémentez un SLOG adapté. Si vous en avez déjà un et que les saccades persistent, vérifiez qu’il n’est pas saturé ou en throttling thermique.
Task 16: Run a controlled fio test from the initiator (measure the right thing)
cr0x@server:~$ sudo fio --name=iscsi-4k-randwrite --filename=/dev/mapper/mpatha --direct=1 --rw=randwrite --bs=4k --iodepth=32 --numjobs=4 --time_based=1 --runtime=60 --group_reporting
iscsi-4k-randwrite: (groupid=0, jobs=4): err= 0: pid=4121: Thu Dec 25 10:30:12 2025
write: IOPS=18.2k, BW=71.2MiB/s (74.7MB/s)(4272MiB/60001msec)
slat (usec): min=4, max=1120, avg=15.2, stdev=9.8
clat (usec): min=90, max=84210, avg=650.1, stdev=2100.4
lat (usec): min=110, max=84230, avg=666.2, stdev=2101.0
clat percentiles (usec):
| 1.00th=[ 140], 10.00th=[ 180], 50.00th=[ 310], 90.00th=[ 980], 99.00th=[ 5800]
| 99.90th=[38000], 99.99th=[79000]
Signification : la latence moyenne semble correcte, mais 99.90th à 38ms et 99.99th à 79ms représentent votre « saccade ». C’est ce que ressentent les utilisateurs.
Décision : optimisez pour la latence en queue, pas la moyenne. Si les queues montent périodiquement, corrélez avec les temps de sync TXG, le comportement du SLOG et les retransmissions réseau.
Feuille de route de diagnostic rapide
Quand la saccade se produit, vous avez besoin d’une liste courte qui réduit rapidement le périmètre. Voici l’ordre que j’utilise parce qu’il trouve
la classe des « évidences cassées » avant que vous perdiez des heures sur des tunables.
Première étape : exclure défaillances et flaps
- zpool status : des erreurs de dispositif, vdevs dégradés, ou resilvers ? Si oui, c’est l’histoire.
- multipath -ll sur les initiateurs : des chemins qui échouent/clignotent ? Si oui, corrigez le réseau/les chemins.
- nstat / compteurs NIC : retransmissions, drops, overruns de ring. Si oui, vous avez un problème réseau/IRQ CPU.
Seconde étape : décider si c’est la latence disque ou la sémantique sync
- iostat -x sur la cible : des pics d’await ? Si oui, disques ou SLOG lents ou saturés.
- zpool iostat -v 1 : les périphériques logs montrent-ils beaucoup d’écritures ? Si oui, vous êtes sync-heavy ; la qualité du SLOG compte.
- fio percentiles : une queue tail élevée avec une moyenne modérée pointe souvent vers des flushs/sync périodiques ou des événements de vidage de file.
Troisième étape : rechercher inadéquations de configuration et amplification
- volblocksize : inadapté à la charge ? Un ZVOL 128K pour des écritures 4K aléatoires saccadera comme une horloge sous pression.
- remplissage du pool : les pools proches de la capacité amplifient la douleur de l’allocateur et la fragmentation.
- RAIDZ + petites écritures sync aléatoires : attendez-vous à des queues plus élevées, surtout pendant scrubs/resilvers.
Quatrième étape : régler la profondeur de file avec précaution
Le réglage de la profondeur de file est l’étape finale car il peut masquer des problèmes et en créer de nouveaux. Mais une fois le système vérifié sain,
ajuster la profondeur d’initiateur et les politiques multipath peut lisser la latence sans sacrifier la cohérence.
Erreurs courantes : symptôme → cause → correction
-
Symptôme : pics de latence périodiques toutes les quelques secondes sous charge d’écriture
Cause : pression de sync TXG + stockage stable lent, souvent pas de SLOG ou SLOG inadéquat
Correction : ajouter un SLOG miroir PLP ; vérifier que les écritures de log y accèdent ; s’assurer que le pool n’est pas presque plein ; programmer scrubs/resilvers en dehors des heures de pointe. -
Symptôme : bon débit mais « gels » dans les VMs, surtout sur invités Windows
Cause : tempêtes de flush (système de fichiers invité, hyperviseur ou appli), latence des écritures sync exposée via iSCSI
Correction : SLOG correct, gardersync=standard; envisager un réglage côté invité (politique de cache d’écriture) uniquement après revue des risques. -
Symptôme : IOPS aléatoires 4K catastrophiques, forte utilisation disque, bande passante étonnamment basse
Cause : volblocksize trop grand causant une amplification read-modify-write
Correction : créer un nouveau ZVOL avec volblocksize 8K/16K et migrer ; ne tentez pas de « ruser » avec des réglages. -
Symptôme : la saccade n’apparaît qu’avec multipath activé
Cause : chemin secondaire instable, path checker trop agressif, mauvaise config de switch, routage asymétrique
Correction : stabiliser L2/L3 d’abord ; définir des politiques multipath sensées ; éviter « round-robin tout » si votre cible ou réseau ne peut pas le gérer proprement. -
Symptôme : la latence empire après activation de L2ARC
Cause : L2ARC vole RAM/CPU, thrash de cache, ou contention SSD avec la charge pool
Correction : retirer L2ARC ; augmenter la RAM ; n’ajouter L2ARC que si vous avez mesuré le working set lecture et pouvez dédier un périphérique rapide. -
Symptôme : perf s’effondre pendant scrub/resilver
Cause : disposition du pool (RAIDZ), marge IOPS limitée, scrub en concurrence avec la production, déséquilibre de vdev
Correction : planifier les scrubs ; ajuster le comportement du scrub si nécessaire ; concevoir des pools avec marge ; mirrors pour charges bloc sensibles à la latence. -
Symptôme : pauses « aléatoires » ; logs montrent timeouts/reconnects iSCSI
Cause : retransmissions TCP, mismatch MTU, offloads NIC bugués, saturation IRQ CPU
Correction : valider MTU de bout en bout ; vérifier les drops ; pinner les IRQs ; envisager de désactiver les offloads problématiques ; garder simple et mesurable. -
Symptôme : l’utilisation d’espace semble correcte, puis tout ralentit soudainement près de la capacité
Cause : sur-souscription liée au thin-provisioning + pool atteignant une forte utilisation
Correction : appliquer quotas/refreservations ; alerter plus tôt ; maintenir de l’espace libre ; traiter la capacité comme un SLO, pas un tableur.
Trois mini-récits d’entreprise du terrain
Mini-récit 1 : L’incident causé par une fausse hypothèse (volblocksize « ça n’a pas d’importance »)
Une entreprise de taille moyenne a migré depuis un SAN Fibre Channel vieillissant vers une cible iSCSI basée sur ZFS. Le plan de test était « copier quelques VMs,
exécuter des tests de connexion, considérer que c’est bon ». Tout semblait correct en labo. En production, le système ERP a commencé à « se bloquer » quelques secondes
par fois pendant les heures de pointe.
L’équipe infra a supposé que le réseau était congestionné parce que iSCSI est « sur TCP », et TCP est « fragile ». Ils ont ajouté de la bande passante :
monté les uplinks, réorganisé les VLANs, même remplacé un switch. La saccade a persisté, poliment inchangée. Les utilisateurs décrivaient toujours « ça se fige puis rattrape ».
L’indice est venu d’un fio ciblé qui a reproduit le problème : des écritures aléatoires 4K montraient de grandes latences en queue, même si la latence moyenne
semblait acceptable. Du côté ZFS, le ZVOL avait été créé avec volblocksize 128K—parce que quelqu’un avait lu un billet « les blocs plus gros sont plus rapides ».
Pour la charge ERP, l’I/O était petite, aléatoire et sync-intensive.
Sous charge, ZFS faisait des cycles read-modify-write sur de gros blocs pour de petites mises à jour, moulinant des métadonnées et forçant des I/O supplémentaires.
Le système n’était pas « lent » autant que « par vagues avec de la misère périodique ». La correction fut sans gloire : créer un nouveau ZVOL avec volblocksize 8K,
migrer le LUN au niveau hyperviseur, et garder la compression activée.
L’upgrade réseau n’a pas été vain—il a amélioré la marge—mais il n’a pas touché la cause racine. Le postmortem a changé le processus de construction :
la taille de bloc est devenue une entrée de conception formelle, pas une valeur par défaut.
Mini-récit 2 : L’optimisation qui a échoué (sync=disabled « pour la perf »)
Un autre client faisait tourner un cluster de virtualisation sur ZFS iSCSI. Ils avaient un bon pool, un réseau décent, et recevaient quand même des plaintes sur des pauses VM
pendant les fenêtres de patch. Quelqu’un a découvert que mettre sync=disabled rendait les benchmarks excellents. Ils l’ont appliqué au ZVOL principal VM
pendant une fenêtre de maintenance et ont déclaré victoire.
Pendant un temps, tout semblait parfait. Les graphes de latence se sont lissés. Le helpdesk s’est tu. Puis un événement d’alimentation a touché un rack—pas tout le datacenter,
juste une rangée où un PDU a lâché. Le serveur de stockage a redémarré. Une poignée de VMs sont revenues avec des systèmes de fichiers corrompus.
Pas toutes. Juste assez pour rendre l’incident réel et rageant.
L’« optimisation » de l’équipe n’était pas un réglage de perf. C’était un changement d’intégrité. Avec sync disabled, le système accusait réception d’écritures encore en cache volatil.
Pour certaines VMs ça n’a pas posé de problème ; pour d’autres, absolument. La récupération fut un mélange de restaurations depuis sauvegarde,
réparations de systèmes de fichiers, et un long week-end à expliquer à la direction pourquoi la « solution rapide » avait fait disparaître des données.
La correction à long terme n’a pas été une conférence, mais une architecture : SLOG PLP mirror pour les charges sync, et refus de changer la sémantique de sécurité des données
pour poursuivre des graphes plus jolis. Ils ont aussi ajouté des tests qui simulent la perte d’alimentation en forçant des redémarrages brutaux pendant des charges synthétiques d’écriture sync
en pré-production.
Blague n°2 : sync=disabled est l’équivalent stockage de retirer les détecteurs de fumée parce que le bip est agaçant.
Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise (marge de capacité + discipline des scrubs)
Une société financière utilisait ZFS iSCSI pour dev/test et un sous-ensemble de charges analytiques production. Leur lead stockage avait une politique opiniâtre :
garder les pools sous un seuil d’utilisation, et exécuter les scrubs selon un calendrier avec alertes claires pour toute erreur de checksum.
C’était ennuyeux. Cela signifiait aussi qu’ils se disputaient souvent avec les chefs de projet sur les demandes de capacité. Mais ils gardaient une marge, et traitaient
les scrubs comme une « hygiène non optionnelle » plutôt que « quelque chose qu’on fait quand on s’ennuie ».
Un trimestre, un job batch a commencé à marteler le stockage avec des écritures aléatoires et des flushs sync inattendus. La latence a augmenté, mais elle n’est pas devenue
catastrophique. Le pool avait encore de l’espace libre, l’allocateur n’était pas coincé, et les mirrors avaient une marge IOPS. L’équipe a pu ralentir le job batch,
ajuster les horaires, et régler la profondeur de file de l’initiateur sans être sous pression existentielle.
Pendant la même période, un scrub a détecté tôt des erreurs de checksum sur un dispositif. Ils l’ont remplacé de façon préventive. Pas d’incident, pas de drame, pas de « on a perdu une demi-journée ».
La politique ne les a pas rendus héros. Elle a rendu le système prévisible, ce qui est mieux.
Listes de contrôle / plan pas à pas
Pas à pas : construire un nouveau ZFS iSCSI ZVOL qui ne saccade pas
- Choisir la disposition du pool pour la latence : mirrors pour VM/iSCSI sauf raison forte contraire.
-
Confirmer ashift avant de créer des données : vérifier avec
zdb -C. Si c’est faux, corriger maintenant, pas plus tard. - Décider volblocksize selon la charge : 8K/16K pour un magasin VM général ; aligner sur la taille de page DB quand connue.
- Créer le ZVOL avec des propriétés explicites : compression lz4, sync standard, logbias latency si sync-heavy.
- Planifier l’espace libre : cible opérationnelle (par ex., 20% libre). Mettre des alertes avant d’atteindre la douleur.
- Ajouter un SLOG approprié si sync-heavy : mirroré, PLP, faible latence, endurance adaptée.
- Exporter via iSCSI avec une config stable : backstore bloc vers ZVOL ; ACL explicites ; configuration portail cohérente.
- Configurer multipath sur les initiateurs : valider que les deux chemins sont vraiment indépendants ; confirmer « active ready running » stable.
- Exécuter des fio percentiles depuis les initiateurs : mesurer les queues, pas seulement la moyenne ; tester patterns sync-ish (fsync) et async.
- Enregistrer une baseline : zpool iostat, iostat -x, retransmits, percentiles de latence. Cela devient votre « connu bon ».
Checklist opérationnelle : lors d’ajout de nouveaux LUNs ou nouveaux tenants
- Confirmer le seuil d’espace libre du pool et la croissance projetée.
- Valider que
volblocksizecorrespond au profil I/O attendu du tenant. - Décider d’utiliser
refreservationpour éviter les surprises du thin-provisioning. - Vérifier la santé du SLOG et les indicateurs d’usure (hors du périmètre des commandes ZFS, mais obligatoire).
- Planifier des scrubs et surveiller les erreurs de checksum comme signal prioritaire.
- Exécuter un court test fio smoke après changements réseau ou politiques multipath.
FAQ
1) Dois‑je utiliser un dataset (fichier) via NFS au lieu d’un ZVOL iSCSI ?
Si votre hyperviseur et votre charge sont satisfaits d’un NFS et que vous voulez un réglage et une observabilité plus simples, les datasets NFS sont souvent plus faciles.
Utilisez ZVOL iSCSI quand vous avez besoin de sémantique bloc ou que l’OS l’exige.
2) Quel volblocksize choisir pour le stockage VM ?
Commencez avec 8K pour les charges VM générales quand vous tenez à la latence des écritures aléatoires. Utilisez 16K si vous avez mesuré que vos charges penchent vers du plus gros
et que vous voulez un peu moins d’overhead métadonnées. Évitez 64K/128K pour des stores VM mixtes sauf si vous avez vraiment des patterns séquentiels.
3) Puis‑je changer volblocksize plus tard ?
Pas en place. Vous créez typiquement un nouveau ZVOL avec le volblocksize désiré et migrez les données côté client/hyperviseur.
Planifiez cette réalité en amont.
4) Ai‑je besoin d’un SLOG pour iSCSI ?
Si votre charge émet des écritures sync (beaucoup le font) et que vous tenez à la cohérence de la latence, oui—un SLOG miroiré PLP adapté est souvent la différence
entre « fluide » et « pauses mystères ». Si votre charge est majoritairement async et que la latence sync est tolérable, vous pouvez vous en passer.
5) Pourquoi ne pas simplement mettre sync=disabled et profiter de la vitesse ?
Parce que cela change la correction. Vous pouvez perdre des écritures reconnues en cas de perte de puissance ou crash, et la défaillance peut être partielle et douloureuse.
Si vous acceptez ce risque pour un environnement scratch, documentez-le. En production, non.
6) L2ARC aide‑t‑il les performances iSCSI ZVOL ?
Parfois, pour des charges lecture‑lourdes avec un working set supérieur à la RAM. Mais L2ARC consomme RAM et CPU et peut entrer en concurrence avec les périphériques.
Mesurez les hits ARC et la latence réelle de lecture avant d’ajouter. Ce n’est pas un levier magique « plus de cache ».
7) Mirrors vs RAIDZ pour iSCSI : quelle différence pratique ?
Les mirrors offrent généralement une meilleure latence d’écriture aléatoire et des IOPS plus prévisibles pendant rebuild/scrub. RAIDZ échange cela contre une efficacité de capacité.
Pour VM/bases de données sur iSCSI, les mirrors sont le défaut le plus sûr.
8) Mon réseau est 25/100GbE—pourquoi j’ai toujours des saccades ?
Parce que la bande passante ne corrige pas la latence en queue. Microbursts, retransmissions, flaps de chemin, et saturation des interruptions CPU peuvent provoquer des pauses même sur des liens rapides.
Vérifiez d’abord les drops/retransmits et la stabilité multipath.
9) Dois‑je activer la compression sur les ZVOLs ?
Oui, généralement lz4. Cela réduit souvent les I/O physiques et améliore la latence. Il existe des exceptions (flux déjà compressés),
mais « désactivée par défaut » est une vieille superstition.
10) Pourquoi les benchmarks semblent corrects mais les applis se figent ?
Beaucoup de benchmarks rapportent des moyennes et masquent la latence en queue. Les utilisateurs ressentent le centile 99.9. Utilisez fio percentiles et corrélez avec TXG ZFS,
l’activité SLOG, et les retransmissions réseau.
Conclusion : prochaines étapes réalisables cette semaine
Si votre ZFS iSCSI ZVOL saccade sous charge, ce n’est généralement pas un seul réglage magique. C’est une chaîne : géométrie de taille de bloc, sémantique sync, qualité du périphérique de log,
mise en file, et stabilité réseau. Votre travail consiste à trouver où les attentes se créent, puis enlever les pires sans tricher sur la durabilité.
Prochaines étapes pratiques :
- Exécutez la feuille de route de diagnostic rapide pendant un événement de saccade et capturez des preuves :
zpool status,zpool iostat -v 1,iostat -x 1, compteurs de retransmissions, et percentiles fio. - Auditez le
volblocksizede chaque ZVOL et identifiez les valeurs hors norme qui ne correspondent pas à la réalité de la charge. - Décidez explicitement si vous avez besoin d’un SLOG. Si oui, achetez la bonne classe de périphérique (PLP, faible latence, mirror), pas un « NVMe grand public rapide ».
- Confirmez la stabilité multipath de bout en bout. Éliminez le path flapping avant de toucher aux tunables de stockage.
- Définissez une politique de capacité et des alertes qui maintiennent le pool hors de la zone « presque plein » où les saccades deviennent un mode de vie.