Miroirs ZFS : la configuration qui rend les E/S aléatoires proches du NVMe

Cet article vous a aidé ?

Il y a un plaisir particulier qu’on ne ressent qu’en production : quand une charge de travail qui avait l’air de traîner un réfrigérateur sur du gravier se remet soudain à répondre. Le CPU cesse d’idling. La base de données cesse de se plaindre. Les graphiques de latence ne ressemblent plus à un sismographe. Vous n’avez pas acheté de nouveaux serveurs. Vous n’avez pas réécrit l’application. Vous avez changé la disposition du stockage.

Les miroirs ZFS sont souvent ce changement. Pas parce qu’ils sont magiques, mais parce qu’ils s’alignent sur la physique des disques et la mathématique des files d’attente. Les miroirs transforment les lectures aléatoires en un problème parallélisable, et la plupart des tickets « mon stockage est lent » cachent en réalité un problème de latence de lecture aléatoire. Si vous avez déjà vu une pool RAIDZ offrir un beau débit séquentiel pendant que votre base de données plante, bienvenue. Ceci explique pourquoi les miroirs peuvent faire ressentir les E/S aléatoires comme du NVMe — sans prétendre en être réellement.

Pourquoi les miroirs donnent l’impression d’être rapides (et quand ce n’est pas le cas)

Les miroirs gagnent sur les lectures aléatoires pour une raison simple mais puissante : ils offrent des choix à ZFS. Pour chaque bloc présent sur deux (ou trois) disques, ZFS peut choisir quelle copie lire. Ce n’est pas seulement de la redondance — c’est de la liberté de planification. Avec un seul disque, les lectures aléatoires se mettent en file et attendent leur tour. Avec un miroir, ZFS peut envoyer différentes lectures vers différents membres, et contourner un disque qui a une mauvaise journée (ou qui est simplement occupé).

En pratique, les vdevs miroir se comportent comme des « amplificateurs d’IOPS » pour les lectures. Une pool construite à partir de plusieurs vdevs miroirs multiplie encore cet effet parce que ZFS stripe les données à travers les vdevs. Le résultat final est qu’une base de données effectuant beaucoup de petites lectures peut voir la latence s’effondrer lorsqu’on passe d’un large vdev RAIDZ à plusieurs vdevs miroirs, même si le nombre brut de disques reste identique.

Les écritures sont une autre histoire. Pour un miroir 2-way simple, chaque écriture doit être écrite sur les deux membres. Cela signifie que les écritures sur miroir ne sont pas plus rapides qu’un seul disque dans le même vdev (en ignorant le comportement du ZIL/SLOG). Mais le parallélisme au niveau du pool aide toujours : si vous avez plusieurs vdevs miroirs, vos écritures se répartissent entre eux. Vous pouvez donc obtenir un bon débit d’écriture avec beaucoup de miroirs, mais un seul vdev miroir n’augmente pas magiquement les IOPS d’écriture.

Voici le modèle mental clé : la performance ZFS est dominée par le nombre et le type de vdevs, pas par le nombre de disques. Les miroirs sont généralement déployés comme de nombreux petits vdevs (miroirs 2 disques, ou parfois 3 disques), ce qui augmente le nombre de vdevs et donne à ZFS plus de files d’attente indépendantes.

Et quand les miroirs ne semblent-ils pas rapides ? Lorsque votre goulot n’est pas les disques. Si vous saturez une file HBA unique, si votre CPU est coincé dans le checksum ou la compression avec un mauvais algorithme, si votre réseau est le facteur limitant, ou si votre charge est majoritairement d’écritures synchrones sans SLOG approprié, les miroirs ne vous sauveront pas. Ils resteront corrects. Ils ne seront juste pas héroïques.

Blague #1 : Un miroir, c’est comme une rotation de pager : la redondance ne fait pas disparaître le travail, elle permet juste à quelqu’un d’autre de prendre l’appel.

Faits et historique utiles à 3 a.m.

Quelques points de contexte courts, concrets et étonnamment utiles quand vous plaidez pour un changement de conception en réunion et que quelqu’un pense que RAID5 résout tout :

  1. ZFS est né chez Sun au milieu des années 2000 en tant que système de fichiers + gestionnaire de volumes intégré, conçu pour détecter et corriger la corruption silencieuse avec des checksums à tous les niveaux.
  2. RAIDZ existe parce que le RAID traditionnel avait un write hole : le RAID par parité pouvait accuser réception d’écritures non entièrement engagées lors d’une coupure d’alimentation, laissant une incohérence silencieuse. Le modèle transactionnel de ZFS réduit cette classe de défaillance.
  3. « Les vdevs sont l’unité de performance » n’est pas un slogan — c’est la façon dont ZFS planifie les IO. ZFS stripe les allocations à travers les vdevs de premier niveau, pas à travers les disques à l’intérieur d’un vdev comme le feraient des contrôleurs RAID classiques.
  4. Les miroirs permettent la sélection de lecture : ZFS peut choisir la branche de miroir la moins chargée, et utiliser la latence historique pour préférer le membre le plus rapide.
  5. Les disques « 4K sector » modernes ont changé la donne : utiliser le mauvais ashift peut pénaliser en permanence les petites écritures via un comportement read-modify-write. Cela affecte aussi les miroirs, mais les vdevs parité souffrent davantage.
  6. Les SSD ont rendu les « lectures aléatoires » normales : les bases de données et les clusters de recherche ont commencé à s’attendre à un stockage à faible latence, et les baies HDD parité ont montré leurs limites sur ces charges.
  7. L2ARC n’a jamais été une tier SSD magique : il peut aider les jeux de données en lecture intensifs qui ne tiennent pas en RAM, mais il consomme de la RAM pour les métadonnées et n’améliore pas la latence d’écriture.
  8. Le SLOG n’est pas un cache d’écriture : c’est un dispositif de journal séparé pour les écritures synchrones ; il accélère la latence de commit, pas le débit en vrac.
  9. Le comportement de resilver diffère : les miroirs résilverisent souvent plus vite que les vdevs parité larges parce qu’ils peuvent copier seulement les blocs alloués (selon plateforme/fonctionnalités) et la reconstruction est mathématiquement plus simple.

Architecture des miroirs : vdevs, files d’attente et la « mathématique IOPS »

Ce que ZFS fait vraiment quand vous créez des miroirs

Un pool ZFS (zpool) est construit à partir d’un ou plusieurs vdevs de premier niveau. Ces vdevs peuvent être :

  • un disque unique (ne faites pas ça en production à moins d’aimer la douleur),
  • un miroir (2-way, 3-way…),
  • un groupe RAIDZ (raidz1/2/3).

Quand vous construisez une pool à partir de plusieurs vdevs de premier niveau, ZFS distribue les allocations entre eux. C’est le striping. Ce n’est pas un RAID0 fixe comme un contrôleur ; c’est basé sur les allocations, mais l’effet est similaire : plus de vdevs signifie plus de files d’attente IO indépendantes.

Pourquoi les miroirs aident les lectures aléatoires

Les charges de travail de lecture aléatoire (bases de données, images VM, serveurs mail, caches CI, systèmes de fichiers riches en métadonnées) sont dominées par les temps de seek/latence sur HDD et par la profondeur de file/latence sur SSD. Avec un miroir, chaque lecture peut être servie par l’un ou l’autre membre. ZFS peut :

  • envoyer des lectures concurrentes vers différentes branches du miroir,
  • préférer le disque avec la file la plus courte,
  • éviter un disque qui renvoie des erreurs ou met plus de temps que prévu.

Si vous avez N vdevs miroir, vous avez N files d’attente vdev indépendantes. Pour les lectures aléatoires, vous avez aussi deux plateaux possibles par vdev. Vous obtenez donc deux types de concurrence : entre les vdevs et au sein de chaque vdev (choix de la branche). L’effet combiné peut sembler spectaculaire comparé à un seul large vdev RAIDZ, qui n’a qu’une file vdev et doit toucher plusieurs disques pour chaque opération.

Mais les miroirs doublent-ils les IOPS ?

Sur les lectures, les miroirs peuvent approcher 2× IOPS de lecture par vdev dans les bonnes conditions, parce que les lectures peuvent être réparties entre les branches. Dans la réalité, c’est moins parfait : cache, prélecture, tailles de requête et le fait que certaines lectures sont séquentielles réduisent le gain théorique. Pourtant, il est courant d’observer une amélioration significative.

Sur les écritures, un vdev miroir 2-way doit écrire deux fois. Donc les IOPS d’écriture par vdev sont à peu près celles d’un seul disque (encore une fois, en ignorant ZIL/SLOG). Le débit d’écriture au niveau du pool s’améliore en ajoutant des vdevs miroirs, pas en espérant qu’un seul miroir écrive plus vite que la physique.

Comparaison RAIDZ sans théologie

RAIDZ est excellent pour l’efficacité de capacité et le débit séquentiel. C’est aussi très simple en « un gros vdev ». Mais les vdevs parité ont plus de difficultés avec les petites IO aléatoires parce que :

  • une petite écriture peut devenir un read-modify-write sur plusieurs disques,
  • les lectures aléatoires doivent toujours se coordonner entre disques (même si parfois elles peuvent être servies par un disque, il y a plus de surcoût et moins de liberté de planification),
  • le vdev est une unité de planification ; un RAIDZ2 large reste un seul vdev.

C’est pourquoi les pools miroirs sont la réponse par défaut pour les charges sensibles à la latence. RAIDZ n’est pas « mauvais » ; il est juste mieux adapté à d’autres profils de performance.

Une note sur les comparaisons avec NVMe

Non, les miroirs ne transforment pas des HDD en NVMe. Mais ils peuvent donner au système l’impression d’être proche du NVMe pour une application principalement bloquée par la latence des lectures aléatoires en queue longue, surtout quand les hits ARC sont élevés et que les lectures restantes sont bien réparties. L’expérience subjective change : moins de blocages, moins de longues pauses, moins de « tout va bien sauf la base de données ».

Blague #2 : Appeler des miroirs HDD « NVMe » revient à appeler un vélo « une moto avec une excellente consommation » — techniquement ça vous déplace, mais ne le faites pas courir.

Décisions de conception : largeur, nombre et quoi acheter

2-way vs 3-way miroirs

Les miroirs 2-way sont la norme : bonne redondance, bonne performance en lecture, coût de capacité acceptable.

Les miroirs 3-way sont pour quand le risque de rebuild et la disponibilité comptent plus que la capacité. Ils peuvent réduire la probabilité qu’une deuxième défaillance tue le vdev pendant un resilver, et améliorer encore la sélection de lecture. Ils coûtent cher en espace utilisable, donc ils sont généralement justifiés pour des pools chauds et petits (métadonnées VM, journaux DB critiques, etc.) ou quand les taux de panne sont mauvais et les remplacements lents.

Beaucoup de petits miroirs valent mieux qu’un gros miroir

Si vous avez 12 disques, la conversation sur la performance n’est généralement pas « un gros truc à 12 disques » mais « combien de vdevs de premier niveau puis-je avoir ? »

  • 6 vdevs miroir (2-way) vous donnent 6 files d’attente vdev et une excellente montée en charge des lectures aléatoires.
  • 1 vdev RAIDZ2 vous donne 1 file d’attente vdev et un bon débit séquentiel avec une bonne capacité.

Si votre charge est du stockage VM, des bases de données, des caches CI, des serveurs de fichiers de type maildir, ou tout ce qui implique beaucoup de petits fichiers : les miroirs gagnent généralement.

Mathématiques de capacité à faire avant d’acheter des disques

Les miroirs « gaspillent » la moitié de la capacité brute (ou les deux tiers pour du 3-way). Mais ce gaspillage n’est pas vain : il vous achète de la marge de performance et de manœuvre opérationnelle. Quand les systèmes sont lents, les équipes font des choses stupides : elles désactivent la sécurité, désactivent sync, réduisent la réplication. Payer pour des miroirs est souvent moins coûteux qu’une semaine de réponse à incident.

Cependant, faites les calculs en amont :

  • Prévoyez de rester en dessous d’environ ~70–80% d’utilisation du pool pour les charges sensibles à la latence. ZFS ralentit à mesure que l’espace libre diminue car l’allocation devient plus difficile et la fragmentation augmente.
  • Prévoyez la redondance et des pièces de rechange. Si vous ne pouvez pas remplacer un disque rapidement, votre miroir est temporairement un disque unique. Ce n’est pas de la redondance ; c’est de l’espoir.

Considérations sur les disques et contrôleurs

Les miroirs exposent la latence. C’est bien, jusqu’à ce que votre HBA ou expander commence à faire des choses « créatives » avec le queueing et la récupération d’erreurs. Quelques notes pratiques :

  • Utilisez des HBAs en mode IT (pass-through). ZFS veut voir les disques.
  • Évitez de mélanger des types de disques très différents dans le même vdev miroir. ZFS peut router les lectures, mais les écritures doivent attendre les deux, et le temps de resilver suit le membre le plus lent.
  • Réglez un timeout d’erreur de disque raisonnable (TLER/ERC) pour les environnements de type RAID. Les récupérations internes longues peuvent bloquer les files d’attente IO et déclencher des timeouts.

Propriétés et réglages qui comptent vraiment

ashift : la décision permanente

ashift définit l’alignement des secteurs du pool. Se tromper et vous pouvez verrouiller une amplification d’écriture pour la durée de vie du vdev. Pour les disques modernes, ashift=12 (secteurs 4K) est généralement le minimum raisonnable ; beaucoup d’admins choisissent ashift=13 (8K) pour certains SSD afin d’aligner sur les pages internes. Vous ne pouvez pas changer ashift après création sans reconstruire.

recordsize (et volblocksize) : adapter au workload

Pour les systèmes de fichiers, recordsize contrôle la taille maximale de bloc que ZFS utilisera pour les données de fichier. De grands records (1M) sont excellents pour le débit séquentiel (sauvegardes, médias), mais peuvent nuire aux IO aléatoires si votre application lit de petits morceaux dans de gros blocs.

Pour les zvols (devices bloc pour iSCSI/VMs), volblocksize est défini à la création et doit correspondre au filesystem invité et à la charge (souvent 8K/16K pour bases de données, 16K/32K pour usage VM général). Encore une fois : vous ne pouvez pas le changer plus tard sans recréer le zvol.

compression : performance gratuite jusqu’à un certain point

compression=lz4 est souvent gagnant : moins d’octets lus/écrits signifie moins de temps disque. Pour les charges de lecture aléatoire, la compression peut réduire la taille des IO et améliorer la latence. Mais la compression consomme du CPU, et sur des systèmes déjà limités par le CPU elle peut se retourner contre vous.

atime : mort par mille écritures de métadonnées

atime=on met à jour les temps d’accès lors des lectures, provoquant des écritures supplémentaires. Sur des systèmes de fichiers chargés, cela peut devenir un flux continu de petites mises à jour métadonnées quasi-synchrones selon la charge. Pour la plupart des charges serveur, atime=off est une amélioration simple.

écritures sync, ZIL et SLOG

Les écritures synchrones sont une garantie contractuelle : l’appelant veut la confirmation que les données sont en stockage stable. ZFS le satisfait via le ZIL (ZFS Intent Log). Si vous ajoutez un dispositif SLOG dédié (rapide, basse latence, protégé contre la perte de puissance), vous pouvez accélérer dramatiquement la latence de commit synchrone.

Les miroirs et le SLOG forment un couple courant : miroirs pour les IOPS de lecture aléatoire, SLOG pour la latence d’écriture sync. Mais si votre charge est majoritairement d’écritures asynchrones, le SLOG n’aidera pas beaucoup. Si votre charge est majoritairement d’écritures synchrones et que vous n’avez pas de SLOG, les miroirs ne régleront pas non plus la latence en queue.

Tâches pratiques avec commandes (et comment lire la sortie)

Les commandes ci-dessous supposent un système Linux typique avec OpenZFS. Ajustez les noms de périphériques et les noms de pool/dataset. L’objectif n’est pas le copier-coller héroïque ; c’est d’acquérir l’habitude de vérifier ce que le système fait réellement.

Task 1: Inspecter la topologie du pool (confirmer que vous avez bien construit des miroirs)

cr0x@server:~$ sudo zpool status -v
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 00:17:02 with 0 errors on Sun Dec 22 02:17:05 2025
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        ONLINE       0     0     0
          mirror-0                  ONLINE       0     0     0
            ata-WDC_WD80...-part1   ONLINE       0     0     0
            ata-WDC_WD80...-part1   ONLINE       0     0     0
          mirror-1                  ONLINE       0     0     0
            ata-WDC_WD80...-part1   ONLINE       0     0     0
            ata-WDC_WD80...-part1   ONLINE       0     0     0

errors: No known data errors

Interprétation : Vous voulez plusieurs vdevs de premier niveau mirror-X. Si vous voyez un grand vdev RAIDZ, votre histoire d’IO aléatoire sera différente. Confirmez aussi que l’état est ONLINE, pas DEGRADED.

Task 2: Surveiller les IO par vdev en temps réel (trouver le vdev chaud)

cr0x@server:~$ sudo zpool iostat -v tank 1
                    capacity     operations     bandwidth
pool              alloc   free   read  write   read  write
----------------  -----  -----  -----  -----  -----  -----
tank              3.21T  4.05T    820    210  41.0M  12.3M
  mirror-0        1.60T  2.02T    610    105  30.4M   6.2M
    ata-WDC...      -      -     320     52  15.2M   3.1M
    ata-WDC...      -      -     290     53  15.2M   3.1M
  mirror-1        1.61T  2.03T    210    105  10.6M   6.1M
    ata-WDC...      -      -     110     52   5.3M   3.0M
    ata-WDC...      -      -     100     53   5.3M   3.1M
----------------  -----  -----  -----  -----  -----  -----

Interprétation : Si un vdev miroir fait la plupart du travail, vous pouvez avoir un skew (placement des données, dataset chaud, ou un petit ensemble de blocs vivant surtout sur un vdev dû à l’âge du pool et à son historique d’expansion). Les miroirs vous donnent de la concurrence, mais uniquement si les allocations sont raisonnablement réparties.

Task 3: Obtenir le signal de 30 secondes « suis-je limité par le cache ou par le disque ? »

cr0x@server:~$ arcstat 1
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
12:01:10  12K  2.1K    17%   890   7%  1.2K  10%     0   0%  96.3G  128G
12:01:11  11K  2.4K    21%   1.1K 10%  1.3K  12%     0   0%  96.3G  128G

Interprétation : De hauts taux de hit ARC masquent souvent les différences de disposition disque. Quand les misses augmentent, la capacité réelle de lecture aléatoire du pool compte. Si les misses montent et que la latence grimpe avec, vous êtes limité par le disque.

Task 4: Vérifier les propriétés des datasets qui sabotent discrètement la latence

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

Interprétation : Un dataset de base de données avec recordsize=1M est un classique auto-infligé. atime=on sur un filesystem chaud crée une pression d’écritures de fond. sync=disabled est un rapport d’incident en attente.

Task 5: Déterminer si les écritures sync sont votre vrai problème

cr0x@server:~$ sudo zpool iostat -v tank 1 | head -n 20
                    capacity     operations     bandwidth
pool              alloc   free   read  write   read  write
----------------  -----  -----  -----  -----  -----  -----
tank              3.21T  4.05T    120    950  6.0M   38.0M
  mirror-0        1.60T  2.02T     70    480  3.4M   19.2M
  mirror-1        1.61T  2.03T     50    470  2.6M   18.8M
----------------  -----  -----  -----  -----  -----  -----

Interprétation : Beaucoup d’opérations d’écriture avec peu de bande passante signifie souvent beaucoup de petites écritures. Si l’application exige des garanties sync (commits DB, NFS avec sync, flush VM), votre prochaine question est : avez-vous un SLOG, et est-il sain ?

Task 6: Confirmer s’il existe un SLOG et ce que c’est

cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
config:

        NAME                         STATE     READ WRITE CKSUM
        tank                         ONLINE       0     0     0
          mirror-0                   ONLINE       0     0     0
            /dev/sdb1                ONLINE       0     0     0
            /dev/sdc1                ONLINE       0     0     0
          mirror-1                   ONLINE       0     0     0
            /dev/sdd1                ONLINE       0     0     0
            /dev/sde1                ONLINE       0     0     0
        logs
          nvme-SAMSUNG_MZ...-part1   ONLINE       0     0     0

Interprétation : Si vous vous souciez de la latence des écritures synchrones, le dispositif de log doit être basse-latence et protégé contre la perte de puissance. Un SSD grand public utilisé comme SLOG peut échouer de manières qui ne se voient pas dans les benchmarks mais se manifestent par des « pourquoi fsync a-t-il pris 800ms ? »

Task 7: Créer correctement une pool miroir (avec ashift explicite)

cr0x@server:~$ sudo zpool create -o ashift=12 tank \
  mirror /dev/disk/by-id/ata-DISK_A /dev/disk/by-id/ata-DISK_B \
  mirror /dev/disk/by-id/ata-DISK_C /dev/disk/by-id/ata-DISK_D

Interprétation : Utilisez des identifiants de périphériques stables. Un ashift explicite évite que les valeurs par défaut de la plateforme vous mordent plus tard. Plusieurs vdevs miroirs : c’est ça que vous achetez : des files d’attente.

Task 8: Ajouter un autre vdev miroir (scaler performance et capacité)

cr0x@server:~$ sudo zpool add tank mirror \
  /dev/disk/by-id/ata-DISK_E /dev/disk/by-id/ata-DISK_F

Interprétation : Voilà comment les pools miroirs grandissent : ajoutez d’autres vdevs miroirs. Vous ne pouvez généralement pas « transformer » un vdev RAIDZ en miroirs. La disposition est un choix de conception au moment de la création.

Task 9: Remplacer un disque défaillant dans un miroir (la manière mature)

cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: DEGRADED
config:

        NAME        STATE     READ WRITE CKSUM
        tank        DEGRADED     0     0     0
          mirror-0  DEGRADED     0     0     0
            sdb1    ONLINE       0     0     0
            sdc1    FAULTED     12     0     0  too many errors
          mirror-1  ONLINE       0     0     0
            sdd1    ONLINE       0     0     0
            sde1    ONLINE       0     0     0

cr0x@server:~$ sudo zpool replace tank sdc1 /dev/disk/by-id/ata-NEW_DISK-part1
cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
  scan: resilver in progress since Tue Dec 24 09:12:03 2025
        312G scanned at 1.20G/s, 41.2G issued at 160M/s, 3.21T total
        41.2G resilvered, 1.26% done, 05:22:11 to go

Interprétation : zpool replace est l’opération de cycle de vie souhaitée. Surveillez les taux de resilver. Si le resilver avance au ralenti, vous pouvez être limité par la charge, les limites du contrôleur, ou un disque survivant en difficulté.

Task 10: Mettre un disque offline/online pour maintenance (simuler une panne en sécurité)

cr0x@server:~$ sudo zpool offline tank /dev/disk/by-id/ata-DISK_B
cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: DEGRADED
config:

        NAME                       STATE     READ WRITE CKSUM
        tank                       DEGRADED     0     0     0
          mirror-0                 DEGRADED     0     0     0
            ata-DISK_A             ONLINE       0     0     0
            ata-DISK_B             OFFLINE      0     0     0
          mirror-1                 ONLINE       0     0     0
            ata-DISK_C             ONLINE       0     0     0
            ata-DISK_D             ONLINE       0     0     0

cr0x@server:~$ sudo zpool online tank /dev/disk/by-id/ata-DISK_B

Interprétation : Utile pour la maintenance contrôlée. Ne laissez pas les miroirs dégradés plus longtemps que nécessaire ; vous êtes à un incident d’indisponibilité.

Task 11: Scrub et vérification (voir si votre pool souffre silencieusement)

cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
  scan: scrub in progress since Tue Dec 24 10:03:41 2025
        1.20T scanned at 820M/s, 510G issued at 350M/s, 3.21T total
        0B repaired, 15.87% done, 02:22:10 to go

Interprétation : Les scrubs détectent et corrigent les mauvais blocs grâce à la redondance des miroirs. Si les scrubs « réparent » régulièrement des données, vos disques, câbles ou chemin contrôleur méritent une attention. Les miroirs pardonnent ; ils ne donnent pas le droit d’ignorer les erreurs.

Task 12: Vérifier la fragmentation et l’espace libre (prévoir l’avenir)

cr0x@server:~$ sudo zpool list -o name,size,alloc,free,frag,capacity,health
NAME  SIZE  ALLOC  FREE  FRAG  CAPACITY  HEALTH
tank  7.25T  3.21T 4.05T   18%      44%  ONLINE

Interprétation : Une forte fragmentation et une utilisation élevée de capacité se corrèlent avec une latence plus mauvaise. Si vous êtes au-delà d’environ ~80% et que l’app est sensible à la latence, vous payez maintenant l’intérêt d’un optimisme passé.

Task 13: Trouver les plus gros consommateurs IO (comptabilité IO par dataset)

cr0x@server:~$ sudo zfs iostat -r -v tank 1
                              capacity     operations     bandwidth
dataset                      alloc   free   read  write   read  write
---------------------------  -----  -----  -----  -----  -----  -----
tank                         3.21T  4.05T      0      0      0      0
  tank/db                    820G   1.20T    640    520  32.0M  24.0M
  tank/vm                    1.90T  2.10T    180    310  9.0M   14.0M
  tank/home                  120G   800G      5     18  200K   900K
---------------------------  -----  -----  -----  -----  -----  -----

Interprétation : Cela vous dit d’où vient l’IO. Si « db » est chaud et a le mauvais recordsize ou le mauvais sync, vous avez une correction ciblée plutôt qu’une panique vague de stockage.

Task 14: Vérifier ashift sur les vdevs existants

cr0x@server:~$ sudo zdb -C tank | grep -E 'ashift|vdev_tree|type: mirror' -n
15:        vdev_tree:
34:            type: 'mirror'
48:                ashift: 12
71:            type: 'mirror'
85:                ashift: 12

Interprétation : Confirmez l’alignement. Si vous découvrez ashift=9 sur des disques 4K, vous avez trouvé une cause structurelle de latence. La correction est de reconstruire/remplacer les vdevs, pas de courir après des sysctls pour se rassurer.

Task 15: Mesurer la latence indirectement (indices de temps de service via iostat)

cr0x@server:~$ iostat -x 1
Linux 6.8.0 (server)  12/24/2025  _x86_64_  (32 CPU)

Device            r/s   w/s  rkB/s  wkB/s  await  svctm  %util
sdb              90.0  60.0  4600   5100    7.2   1.1    18.0
sdc              88.0  62.0  4500   5200    8.0   1.2    19.0
sdd              30.0  90.0  1400   7800   25.0   1.3    22.0
sde              28.0  92.0  1300   7900   27.5   1.4    23.0

Interprétation : Une await qui augmente alors que %util n’est pas saturé peut indiquer du queueing au-dessus de la couche device (contrôleur, filesystem, blocages d’écriture sync). Une branche de miroir montrant systématiquement un await pire est un indice : ce disque, chemin ou câble peut être dégradé.

Plan de diagnostic rapide

Voici la routine « entrer dans la salle, regarder trois choses, et ne pas se laisser distraire ». Elle est conçue pour les incidents et ralentissements où vous avez besoin d’une hypothèse rapide.

Première étape : est-ce le cache, le disque ou le sync ?

  1. Taux de hit ARC : lancez arcstat 1 (ou équivalent). Si les misses sont faibles, la disposition disque pourrait ne pas être le problème actuellement.
  2. Forme IO du pool : lancez zpool iostat -v tank 1. Cherchez beaucoup d’opérations d’écriture petites, une charge vdev déséquilibrée, et si la lecture ou l’écriture domine.
  3. Pression sync : vérifiez si la charge est sync-heavy (commits DB, NFS sync). Confirmez s’il y a un SLOG via zpool status. Si pas de SLOG et que les écritures sync dominent, vous avez probablement trouvé le coupable de latence.

Deuxième étape : un seul device/chemin se comporte-t-il mal ?

  1. Santé et erreurs : zpool status -v. Des erreurs READ/WRITE/CKSUM ? Des vdevs DEGRADED ?
  2. Indices de latence par disque : iostat -x 1. Un disque avec un await élevé ou des retries est souvent « le problème », même si le pool est « ONLINE ».
  3. Logs noyau : vérifiez les resets/timeouts de lien.

Troisième étape : manque d’espace ou noyé dans la fragmentation ?

  1. Capacité et frag : zpool list -o size,alloc,free,frag,capacity. Si vous êtes au-dessus d’environ 80% et que frag est élevé, la douleur IO aléatoire est attendue.
  2. Datasets coupables : zfs iostat -v 1 pour trouver les datasets chauds, puis inspecter leurs propriétés.
  3. Travail de fond : scrubs/resilvers peuvent dominer l’IO. Vérifiez la ligne scan de zpool status.

Une fois que vous avez la catégorie — cache miss, latence d’écriture sync, un disque/chemin unique mauvais, ou pool plein/fragmenté — vous pouvez agir. Sans cela, vous passerez des heures à « tuner » un système qui est simplement hors de son enveloppe de conception.

Trois mini-histoires du monde de l’entreprise

1) Incident causé par une mauvaise hypothèse : « Les écritures sur miroir sont rapides, non ? »

Une équipe a migré un service transactionnel d’un DB managé vers des instances auto-hébergées pour des raisons de coût. Le plan de stockage semblait solide : « On utilisera des miroirs ZFS, donc ce sera rapide. » Ils ont construit une pool de plusieurs vdevs miroirs sur des SSD corrects, activé la compression, et ont déclaré le travail terminé. Les premiers tests étaient excellents — parce que les tests consistaient surtout en lectures et en charges en vrac. Le service est passé en production un lundi, évidemment.

Mardi après-midi, la rotation on-call a découvert une nouvelle saveur de fatigue d’alertes. Les pics de latence coïncidaient avec des rafales de transactions. La base n’était pas CPU-bound. Le réseau était propre. Les disques n’étaient pas saturés en bande passante. Mais les commits se bloquaient assez longtemps pour déclencher des timeouts. Le canal d’incident s’est rempli des suspects habituels : « Peut-être que ZFS est lent ? » « Peut-être qu’il faut des instances plus grandes ? » « Peut-être désactiver fsync ? »

L’hypothèse erronée était subtile : ils pensaient que les miroirs accéléreraient les écritures comme ils accélèrent les lectures aléatoires. Mais la charge était dominée par des commits synchrones, et le système n’avait pas de SLOG dédié. ZFS faisait la bonne chose — honorer la sémantique sync en commitant sur un stockage stable — mais le profil de latence des dispositifs du pool principal (et l’amplification d’écriture due aux petites écritures sync) rendait la situation désagréable sous pression.

La correction n’a pas été un mystérieux sysctl. Ils ont ajouté un dispositif SLOG basse-latence protégé contre la perte de puissance (en miroir, car oui, les dispositifs de log peuvent aussi échouer), ont vérifié que la latence des écritures sync avait chuté, et ont retesté avec des patrons de transactions réels. Le service s’est stabilisé. Le postmortem n’était pas « ZFS est lent ». C’était une question d’adapter la disposition à la forme des IO et de comprendre que les miroirs sont une arme pour la latence de lecture, pas une potion universelle de performance.

La leçon retenue : les miroirs leur avaient donné la marge de lectures aléatoires désirée, mais sans SLOG ils souffraient encore de la latence tail des écritures synchrones. Ils ont commencé à traiter « sync-heavy » comme une exigence de premier ordre, pas une option après coup.

2) Une optimisation qui s’est retournée contre eux : « On augmente recordsize et on désactive sync »

Cette histoire commence comme beaucoup de tragédies de stockage : une capture d’écran de dashboard et une phrase confiante. Un développeur a montré que l’application faisait beaucoup d’IO, et quelqu’un a proposé « d’optimiser » le filesystem. La proposition : augmenter recordsize à 1M « pour le débit » et mettre sync=disabled « parce que fsync coûte cher ». L’équipe voulait de beaux graphiques. Ils ont eu ce qu’ils voulaient.

Pendant environ deux semaines, les performances ont été parfaites. Puis une maintenance a inclus une coupure d’alimentation plus longue que prévu. À la remise en route, les données applicatives étaient incohérentes. Pas une perte dramatique de tout — pire. Un petit nombre de transactions récentes manquaient, et certains enregistrements étaient partiellement appliqués. Le type de corruption qui se transforme en une longue semaine de réconciliation et d’excuses.

Désactiver sync a enlevé la garantie contractuelle sur laquelle l’application comptait. ZFS a fait exactement ce qu’on lui disait : traiter les écritures synchrones comme asynchrones. Le miroir n’était pas le coupable. L’« optimisation » l’était. Augmenter le recordsize avait aussi un coût : la base lisait et réécrivait désormais des blocs plus gros que nécessaire, ce qui a rendu les IO aléatoires plus saccadés sous charge, en particulier quand l’ARC ne les captait pas.

Le plan de récupération a impliqué une restauration depuis les sauvegardes et la relecture de ce qu’ils pouvaient depuis les logs en amont. Le changement durable a été culturel : les propriétés du filesystem sont passées en contrôle de changement, et le travail de perf requiert désormais un plan de test représentant la charge. L’équipe a appris à craindre toute optimisation qui commence par « on peut désactiver la sécurité, ça ira ».

Les miroirs ne les ont pas sauvés de leurs propres décisions. Mais la refonte ultérieure a fonctionné : ils ont remis sync à standard, utilisé un vrai SLOG pour les parties sync-heavy, ajusté le recordsize par dataset, et conservé les miroirs parce que le profil de lecture aléatoire était le vrai besoin long terme.

3) Pratique ennuyeuse mais correcte qui a sauvé la journée : remplacer les disques avant qu’ils « tombent en panne »

Dans un grand environnement corporate, le travail le plus héroïque est souvent silencieux. Une flotte de stockage avait une politique : si un disque commence à logger des erreurs moyennes ou montre un taux d’erreurs croissant, le remplacer pendant les heures ouvrables — avant qu’il ne déclenche un vdev en état dégradé. Ce n’était pas spectaculaire. C’était aussi parfois impopulaire car cela ressemblait à dépenser de l’argent « trop tôt ».

Un trimestre, ils ont vu des pics de latence sporadiques sur une pool servant le CI interne et le stockage d’artefacts. Rien dans zpool status. Pas de vdev DEGRADED. Juste des pics de latence tail qui rendaient les builds fragiles et les devs mécontents. Au lieu de blâmer le réseau ou « Kubernetes qui fait du Kubernetes », l’on-call a lancé le triage standard : zpool iostat -v a montré une branche de miroir avec une charge inégale et des temps de service pires. iostat -x a suggéré qu’un disque était parfois en train de staller.

Ils ont extrait les données SMART et trouvé des signes précoces de problème — rien qui déclenche un ticket de panne immédiat, mais assez pour corréler avec les stalls. Ils ont remplacé le disque dans une fenêtre planifiée avec zpool replace, surveillé le resilver, et les pics de latence ont disparu. Aucun incident. Aucun postmortem. Juste une boucle fermée entre observation et maintenance.

Des semaines plus tard, un autre disque dans un autre miroir est tombé net. L’équipe a haussé les épaules, l’a remplacé et a continué. L’important : parce qu’ils ont gardé le pool sain et qu’ils avaient une culture de remplacement proactif, la « vraie » panne n’est pas tombée en même temps qu’un second disque marginal, un backlog de scrub et un pool plein. Les miroirs ont fait leur travail parce que les opérations ont fait le leur.

Erreurs courantes : symptômes et corrections

Mistake 1: Construire un unique gros vdev RAIDZ pour une charge IO aléatoire

Symptômes : Les benchmarks séquentiels semblent corrects. Les applications réelles (DB/VMs) montrent une latence élevée et de faibles IOPS. zpool iostat montre un vdev faisant tout parce qu’il n’y a qu’un seul vdev.

Correction : Pour une IO aléatoire sensible à la latence, concevez avec plusieurs vdevs miroirs. Si vous avez déjà construit un RAIDZ, la correction est généralement la migration vers une nouvelle disposition de pool (send/receive, réplication, rebuild). Il n’y a pas de raccourci sûr « convertir en place » qui préserve le même vdev.

Mistake 2: Mauvais ashift

Symptômes : Les petites écritures sont inexplicablement lentes. Le CPU et la bande passante sont corrects, mais la latence persiste. Vous observez un comportement read-modify-write intensif au niveau device.

Correction : Vérifiez avec zdb -C. Si c’est faux, planifiez une reconstruction : remplacez les vdevs par des vdevs correctement alignés ou migrez vers un nouveau pool. Ne perdez pas de temps à chasser des « réglages » pour un problème de géométrie.

Mistake 3: Désactiver sync pour « améliorer » les performances

Symptômes : Les graphiques de performance s’améliorent. Puis une extinction non propre entraîne des données récentes manquantes ou des incohérences applicatives.

Correction : Gardez sync=standard sauf si vous pouvez prouver que l’application n’exige pas de durabilité (rare). Si vous avez besoin de perf sync, ajoutez un SLOG approprié et confirmez qu’il est réellement utilisé (et qu’il est PLP-capable et basse-latence).

Mistake 4: Utiliser un SSD grand public comme SLOG

Symptômes : La latence d’écriture sync est instable ; des stalls longs occasionnels. Le SLOG montre des erreurs ou des resets. Parfois la performance se dégrade avec le temps à mesure que le GC interne du device vous gêne.

Correction : Utilisez un device enterprise avec protection contre la perte d’alimentation. Envisagez de mirrorer le SLOG. Surveillez-le comme si c’était critique — parce que ça l’est.

Mistake 5: Remplir le pool jusqu’à ras bord

Symptômes : La latence augmente à mesure que le pool approche d’une forte utilisation. L’allocation devient coûteuse. La fragmentation monte. Tout devient « mou » et imprévisible.

Correction : Gardez un espace libre (souvent 20–30% pour les pools chauds). Ajoutez des vdevs tôt. Si vous êtes déjà plein, migrez les données froides ailleurs ou étendez ; le tuning ne créera pas d’espace libre.

Mistake 6: Ignorer un disque « légèrement bizarre »

Symptômes : Le pool est ONLINE mais les pics de latence tail surviennent. Un disque montre un await plus élevé ou des erreurs sporadiques. Les scrubs prennent plus de temps que d’habitude.

Correction : Traitez le matériel marginal comme un bug de performance. Remplacez les disques suspects et réparez les câbles/chemins instables. Les miroirs masquent les pannes ; ils cachent aussi les signaux d’alerte précoces si vous ne regardez pas.

Mistake 7: Mélanger tailles ou vitesses de disques dans un même miroir

Symptômes : Vous n’obtenez que la capacité du plus petit disque dans chaque miroir. Le resilver et la latence d’écriture suivent le membre le plus lent. La performance est incohérente.

Correction : Miroirez « like-with-like » quand c’est possible. Si vous devez mélanger, faites-le intentionnellement et acceptez les contraintes (et documentez-les pour que le Futur Vous ne « optimise » pas cela en chaos).

Listes de contrôle / plan étape par étape

Étape par étape : concevoir une pool miroir pour IO aléatoire

  1. Classifiez la charge : lecture aléatoire intensive (DB/VM), écriture sync-intensive (journaux transactionnels, NFS sync), séquentielle (sauvegardes/médias), mixte.
  2. Choisissez la stratégie de vdev de premier niveau :
    • IO aléatoire + sensibilité à la latence : plusieurs vdevs miroir 2-way.
    • Exigences extrêmes de disponibilité : envisagez des miroirs 3-way pour le tier chaud.
    • Priorité capacité + séquentiel : RAIDZ2/3 peut convenir, mais comprenez les compromis sur l’IO aléatoire.
  3. Décidez du pattern de croissance : les miroirs grandissent en ajoutant des vdevs miroirs. Confirmez que l’entreprise peut acheter des disques par paires (ou triples) plus tard.
  4. Choisissez ashift : généralement 12. Soyez explicite.
  5. Planifiez les écritures sync : si vous avez une charge sync-heavy, concevez un SLOG en amont (et budgetez un device PLP).
  6. Définissez des defaults de dataset : compression=lz4, atime=off, et un recordsize raisonnable par dataset (pas du one-size-fits-all).
  7. Politique opérationnelle : calendrier de scrub, monitoring SMART, inventaire de spares, playbook de remplacement.

Étape par étape : valider que les miroirs délivrent la latence attendue

  1. Confirmer la topologie avec zpool status et vérifier que plusieurs vdevs miroirs existent.
  2. IO de base : mesurez avec une charge ressemblant à l’application, pas seulement des tests synthétiques séquentiels.
  3. Observer la distribution : zpool iostat -v 1 doit montrer le travail réparti entre les vdevs.
  4. Vérifier le comportement du cache : arcstat pour voir si vous touchez vraiment le disque.
  5. Tester le mode dégradé : offline un disque pendant une fenêtre contrôlée, observez le comportement, puis remettez-le online. Assurez-vous que les alertes de monitoring fonctionnent.
  6. Documenter le « connu bon » : recordsize/volblocksize, sémantique sync, type de SLOG, ashift.

Étape par étape : quand vous avez déjà RAIDZ et voulez des miroirs

  1. Admettez que c’est une migration : vous ne « tunez » pas pour obtenir des miroirs. Vous migrez des données.
  2. Construisez une nouvelle pool avec des vdevs miroirs et le bon ashift.
  3. Utilisez la réplication : zfs send/zfs receive pour les datasets ; gardez les snapshots cohérents.
  4. Basculer pendant une fenêtre planifiée, valider, puis décommissionner l’ancien pool.

FAQ

1) Les miroirs ZFS sont-ils toujours plus rapides que RAIDZ ?

Non. Les miroirs sont généralement plus rapides pour les lectures aléatoires et les charges sensibles à la latence. RAIDZ peut être excellent pour le débit séquentiel et l’efficacité de capacité. Choisissez selon la forme d’IO et les contraintes opérationnelles.

2) Combien de vdevs miroirs me faut-il ?

Assez pour que votre charge puisse se répartir entre les files d’attente des vdevs. Règle heuristique : plus de vdevs de premier niveau signifie généralement plus d’IOPS et moins de contention. Mais les contrôleurs, le CPU et le réseau peuvent devenir les nouveaux goulots, donc mesurez et n’en faites pas trop aveuglément.

3) Dois-je utiliser des miroirs 2-way ou 3-way ?

Utilisez des miroirs 2-way par défaut. Utilisez 3-way quand la disponibilité et le risque de rebuild dominent et que vous pouvez vous permettre le coût en capacité — surtout pour des datasets chauds et critiques.

4) Les miroirs aident-ils la latence d’écriture ?

Pas directement par vdev. Les écritures doivent aller sur tous les membres d’un miroir. Le débit d’écriture au niveau du pool s’améliore en ayant plusieurs vdevs miroirs, mais la latence d’écriture synchrone est en général traitée avec un SLOG approprié, pas uniquement avec des miroirs.

5) Quel est le réglage unique le plus important à ne pas rater ?

ashift. Obtenez l’alignement des secteurs correct dès la création du pool. Un mauvais ashift peut dégrader définitivement les petites écritures et est pénible à corriger plus tard.

6) Le SLOG est-il requis pour les pools miroirs ?

Non. Il n’est requis que si vous avez une charge d’écritures synchrones significative et que vous vous souciez de la latence. Si votre charge est majoritairement asynchrone, un SLOG apporte souvent peu.

7) Pourquoi mon pool miroir est rapide en benchmark mais lent en production ?

Les benchmarks testent souvent le débit séquentiel ou des profondeurs de queue irréalistes. La douleur en production vient fréquemment de la latence tail due aux écritures sync, un disque/chemin défaillant, un pool presque plein, ou une incompatibilité de propriété dataset (recordsize/volblocksize).

8) Puis-je étendre un vdev miroir en ajoutant un troisième disque plus tard ?

Dans de nombreux environnements OpenZFS, vous pouvez attacher un périphérique supplémentaire à un miroir pour le rendre 3-way, mais le support opérationnel varie selon la plateforme et les politiques. Même si c’est possible, traitez cela comme un changement à risque réel : testez en labo, confirmez le monitoring et assurez-vous que les procédures de remplacement gèrent la nouvelle topologie.

9) Les miroirs réduisent-ils le temps de resilver ?

Souvent, oui. Les resilvers de miroir sont généralement plus simples que la reconstruction par parité. Selon les fonctionnalités et le comportement de la plateforme, ZFS peut resilver seulement les blocs alloués, ce qui peut rendre la récupération plus rapide que de « copier tout le disque ». Mais la vitesse de resilver dépend toujours de la charge, de la santé des disques et des limites du contrôleur.

10) Si je veux à la fois efficacité de capacité et performance aléatoire ?

Séparez les tiers. Utilisez des miroirs pour les datasets chauds à IO aléatoire et RAIDZ pour les données froides/séquentielles — ou des pools séparés entièrement. Essayer de faire tenir tous les workloads sur une seule disposition conduit à des performances médiocres et des incidents au-dessus de la moyenne.

Conclusion

Les miroirs ZFS ne trichent pas avec la physique. Ils l’exploitent. Les IO aléatoires sont un problème de file d’attente, et les miroirs donnent à ZFS plus de choix : plus de files, plus de parallélisme, et plus d’opportunités d’éviter le disque unique qui ruine silencieusement votre latence tail. Quand vous construisez une pool à partir de plusieurs vdevs miroirs, vous ne dupliquez pas simplement les données — vous achetez de la liberté de planification.

Le gain opérationnel dépasse les benchmarks. Les miroirs rendent la gestion des pannes simple, rendent les scrubs significatifs, et la performance plus prévisible sur les charges mixtes. Associez-les à des propriétés sensées, un espace libre suffisant, et (si nécessaire) un vrai SLOG, et vous obtenez l’équivalent stockage d’une rotation on-call bien tenue : pas glamour, mais soudainement tout cesse d’être une urgence.

← Précédent
Courriel : Brute force sur IMAP/SMTP — sécurisez sans vous verrouiller
Suivant →
Serveurs Ubuntu 24.04 : Snap vs apt — quand Snap cause discrètement des problèmes (et que faire)

Laisser un commentaire