ZFS et Proxmox : paramètres de stockage VM à modifier immédiatement

Cet article vous a aidé ?

La plupart des « mystères » de performance Proxmox+ZFS ne sont pas des mystères. Ce sont des paramètres par défaut. Des choix faits pour être sûrs, génériques et largement compatibles — puis appliqués silencieusement à votre réalité de stockage très spécifique : SSD grand public avec une protection contre la perte d’alimentation douteuse, pools RAIDZ effectuant des E/S aléatoires, invités émettant des écritures sync, et un hyperviseur qui adore mettre en cache au-dessus d’un autre cache.

Si vos VM semblent rapides jusqu’au moment où elles ne le sont plus — jusqu’à ce qu’un checkpoint de base de données, une mise à jour Windows ou une fenêtre de sauvegarde arrive et que tout devienne pâteux — ceci est pour vous. Nous allons modifier les paramètres par défaut qui comptent vraiment, expliquer pourquoi, et montrer comment prouver les résultats avec des commandes qui ne mentent pas.

L’état d’esprit : ne plus accepter le stockage « ça marche dans mon labo »

ZFS est opinionné. Proxmox est opinionné. Votre charge de travail est aussi opinionnée — surtout si elle inclut des bases de données, des serveurs mail, des runners CI ou tout ce qui génère beaucoup de petites écritures sync. Quand ces trois opinions divergent, vous obtenez des pics de latence qui ressemblent à une « lenteur aléatoire », et vous passez des jours à blâmer le mauvais niveau.

Le piège central est d’assumer que la virtualisation « lisse les choses ». C’est le contraire. La virtualisation prend de nombreux schémas d’E/S — séquentiels, aléatoires, en rafale, sync-intensifs, centrés sur les métadonnées — et les multiplexe dans un pool partagé. Ce pool doit ensuite tenir des promesses : promesses de durabilité (sémantique sync), promesses d’allocation (copy-on-write), promesses de cache (ARC/L2ARC) et promesses d’équité (scheduler). Les valeurs par défaut sont un point de départ, pas une stratégie.

Voici le cadre que j’utilise en production :

  • Sachez quelles écritures doivent être sûres. Si l’invité demande sync, supposez que ça compte sauf si vous tradez délibérément durabilité contre vitesse.
  • Adaptez les tailles de bloc à la réalité. ZFS ne peut pas lire ce qu’il n’a pas écrit. Si vous choisissez un volblocksize pour un zvol qui s’oppose à votre charge, vous en paierez le prix indéfiniment.
  • Minimisez le « double travail ». Double cache, double checksumming, couches CoW redondantes : chacune peut être défendable isolément ; combinées, elles constituent une taxe.
  • Mesurez au bon niveau. iostat dans l’invité peut paraître correct pendant que l’hôte est en feu. Inversement, ZFS peut sembler correct pendant que l’invité exécute des boucles fsync pathologiques.

Faits intéressants et contexte historique (court, utile)

  1. ZFS a popularisé le checksumming de bout en bout dans les déploiements grand public, transformant la corruption silencieuse de « mythique » en « mesurable ». Cela a changé la manière dont les équipes ops considèrent la confiance du stockage.
  2. Le copy-on-write (CoW) explique pourquoi les snapshots sont bon marché, et aussi pourquoi les écritures aléatoires peuvent être coûteuses — surtout sur RAIDZ en virtualisation.
  3. La compression sur ZFS est souvent une fonctionnalité de performance, pas seulement d’espace, car moins d’octets transférés peut compenser le coût CPU (particulièrement avec lz4).
  4. « Les écritures sync sont lentes » était autrefois considéré comme un problème applicatif ; ZFS en a fait une question de conception système en respectant strictement la sémantique sync.
  5. Les dispositifs SLOG sont devenus une industrie cottage parce que les gens ont appris à la dure que « un SSD » n’est pas équivalent à « un dispositif journal sûr et à faible latence ».
  6. Proxmox a déplacé beaucoup d’utilisateurs de LVM-thin vers ZFS car les snapshots et la réplication sont opérationnellement addictifs — jusqu’à ce que vous découvriez l’effet des paramètres par défaut sur la latence.
  7. L’industrie a passé des années à redécouvrir l’amplification d’écriture : de petites écritures aléatoires sur des systèmes de fichiers CoW peuvent exploser en un travail physique beaucoup plus important, surtout avec des RAID à parité.
  8. Les erreurs ashift sont quasi définitives (pratiquement parlant) : si vous créez un pool avec la mauvaise hypothèse sur la taille de secteur, les performances peuvent être durablement entravées.

Les paramètres Proxmox+ZFS qui méritent un scepticisme immédiat

1) Comportement sync : vous ne pouvez plus l’ignorer

Les valeurs par défaut de Proxmox ne vous protègent pas de la latence des écritures sync. Vos invités peuvent émettre des écritures sync (fsync, O_DSYNC, barrières/flushes), et ZFS traitera ces écritures comme « devant être stables en cas de perte de courant ». Si vous n’avez pas de SLOG et que votre pool est sur HDD ou des SSD saturés, les charges sync-intensives donneront l’impression d’une maison hantée.

Mais le pire, c’est l’ambiguïté : certaines charges sont sync-intensives seulement pendant des phases spécifiques — commits de base de données, vidages de journal, sauvegardes VM déclenchant des comportements FS. Vous obtenez alors une misère intermittente et un faux sentiment de « ça va la plupart du temps ».

Point de décision : si la durabilité vous importe, gardez sync=standard et construisez le pool pour le supporter. Si ça ne vous importe pas (lab, CI éphémère), vous pouvez choisir sync=disabled délibérément — jamais par accident.

2) volblocksize : le réglage qui décide discrètement de votre économie d’I/O

Les ZVOLs ont volblocksize. Les datasets ont recordsize. Les gens confondent ces paramètres, puis se demandent pourquoi leur tuning n’a rien changé.

volblocksize est défini à la création du zvol et est essentiellement permanent (vous pouvez changer la propriété, mais les blocs existants ne se réécrivent pas ; vous migrez généralement pour en bénéficier pleinement). Proxmox crée souvent des zvols avec un défaut qui ne correspond pas à votre charge.

Conseils typiques (non sacrés) :

  • 16K : souvent bon pour les disques VM généraux, les charges mixtes et les bases de données effectuant beaucoup de petites E/S aléatoires.
  • 8K : peut aider pour des patterns particulièrement sync- ou log-intensifs, mais augmente le overhead métadonnées.
  • 64K/128K : peut être excellent pour des charges séquentielles importantes (média, sauvegardes), souvent inadapté pour les disques système.

Sur RAIDZ, les blocs plus petits peuvent être particulièrement punitifs à cause du comportement parité et read-modify-write. C’est là que naissent les rumeurs « ZFS est lent ».

3) Compression : laisser de la performance sur la table

Si vous n’utilisez pas compression=lz4 sur le stockage VM, vous choisissez en pratique de déplacer plus d’octets que nécessaire. Pour de nombreuses charges VM (fichiers OS, logs, texte, dépôts de paquets), la compression réduit les I/O physiques et améliore la latence sous pression.

La compression peut se retourner contre vous sur des hôtes déjà contraints en CPU ou sur des charges incompressibles (médias pré-compressés, volumes chiffrés). Mais pour la plupart des hyperviseurs Proxmox, lz4 est le choix par défaut que vous devriez vouloir.

4) atime : mort par mille lectures

atime=on signifie que des lectures deviennent des écritures parce que les temps d’accès sont mis à jour. Sur le stockage VM, c’est généralement du churn inutile. Si vous tenez à l’endurance de vos SSD et à votre latence, définissez atime=off pour les datasets VM.

5) Cache primaire : le double cache n’est pas un trait de personnalité

ZFS ARC met en cache agressivement. Les invités mettent aussi en cache. Si vous laissez ZFS mettre en cache des données que l’invité mettra de nouveau en cache, vous brûlez de la mémoire des deux côtés et obtenez une efficacité de cache moindre.

Approche commune : pour les disques VM basés sur zvol, envisagez primarycache=metadata (cacher les métadonnées, pas les données) pour réduire le double caching. C’est situationnel : si vos invités sont minuscules et que votre hôte a beaucoup de RAM, mettre en cache les données peut encore aider. Mais prenez cette décision intentionnellement.

6) Provisionnement thin : l’« espace libre » est une construction sociale

Les zvols thin donnent l’impression d’efficacité jusqu’à ce que le pool atteigne une falaise. Une fois qu’un pool ZFS est trop plein, les performances peuvent s’effondrer à cause de la pression d’allocation et de la fragmentation. « Mais il nous reste 15% ! » est ce que disent les gens juste avant une mauvaise journée.

Règle opérationnelle : gardez un espace libre significatif. Pour de nombreux pools VM, considérez 20–30% libre comme normal. Si cela vous semble gaspilleur, vous êtes sur le point d’apprendre ce que ressent un approvisionnement d’urgence en stockage.

Blague #1 : RAIDZ avec un pool presque plein, c’est comme une réunion qui « aurait dû être un email ». Elle continue, ralentit, et personne ne peut partir.

ZVOL vs images fichier dataset (raw/qcow2) : choisir le moins pire

ZVOLs (périphériques bloc) : chemin simple, sémantique forte

Les ZVOLs sont des périphériques bloc gérés par ZFS. Proxmox les apprécie car les snapshots et la réplication s’intègrent proprement, et vous évitez certaines bizarreries filesystem-on-filesystem.

Compromis :

  • volblocksize compte beaucoup, et vous n’avez pas d’essais infinis.
  • Le comportement discard/TRIM peut être délicat selon les versions et les paramètres. Vous devez vérifier que la récupération d’espace fonctionne réellement.
  • Les sémantiques de cache (primarycache) deviennent importantes pour éviter de se battre avec l’invité.

Fichiers dataset (raw/qcow2) : flexibilité avec une couche en plus

Stocker des disques VM en tant que fichiers sur un dataset ZFS peut être parfaitement acceptable. Le principal risque est d’empiler des couches CoW (qcow2 est CoW ; ZFS est CoW). Cela peut amplifier la fragmentation et le overhead métadonnées, surtout sous une pression d’écritures aléatoires.

Conseils orientés :

  • Préférez raw plutôt que qcow2 sur ZFS sauf si vous avez une fonctionnalité qcow2 spécifique dont vous avez vraiment besoin.
  • Utilisez qcow2 avec prudence pour des cas niche (sparse + snapshots internes), mais comprenez que vous payez pour cette flexibilité.

Comment décider rapidement

  • Si vous exécutez des bases de données ou des services sensibles à la latence : zvols avec un volblocksize cohérent et plan pour les écritures sync.
  • Si vous traitez principalement des données séquentielles en masse : les fichiers dataset peuvent convenir, ajustez recordsize, et gardez la simplicité.
  • Si vous avez beaucoup de petites VM et que vous valorisez la simplicité opérationnelle : les zvols sont souvent plus faciles à raisonner dans l’outil Proxmox.

Les changements que j’applique dès le premier jour (et pourquoi)

Changement 1 : Activer la compression lz4 sur le stockage VM

Faites-le sauf preuve du contraire. lz4 a une faible latence, et les disques VM sont souvent compressibles. Le gain est souvent visible sous charge quand le pool est occupé.

Changement 2 : Désactiver atime pour les datasets VM

C’est un classique : un petit réglage qui évite du churn inutile. Le stockage VM n’a pas besoin des écritures de mise à jour du temps d’accès.

Changement 3 : Décidez explicitement de votre politique sync

La plupart des gens exécutent involontairement sync=standard sur du matériel incapable de le soutenir, puis « corrigent » en désactivant sync globalement, et oublient qu’ils l’ont fait. Ne soyez pas cette personne.

Choisissez une voie :

  • Voie durable : sync=standard, ajoutez un SLOG adéquat si nécessaire, et vérifiez la latence.
  • Voie performance à tout prix : sync=disabled sur les datasets/zvols spécifiques où la perte de données est acceptable.

Changement 4 : Définir primarycache de manière réfléchie pour les pools zvol lourds

Si l’hôte manque de mémoire, l’ARC qui entre en compétition avec les invités est un combat à mort. Pour beaucoup de disques VM basés sur zvol, primarycache=metadata est un choix sensé. Si vous avez énormément de RAM et des invités majoritairement en lecture, le cache des données peut aider. Mesurez, ne devinez pas.

Changement 5 : Arrêtez de surremplir les pools

Notez ceci : un pool ZFS à 85–90% plein n’est pas “acceptable”. C’est un incident de latence programmé.

Changement 6 : Utilisez les bonnes options de disque virtualisé (et vérifiez)

Les paramètres de disque Proxmox comme cache, discard, iothread et le modèle de contrôleur comptent. Mais « compter » signifie « apparaître dans les mesures », pas « sonner cool dans un post de forum ». Votre référence devrait être une latence stable et des modes de panne prévisibles.

Blague #2 : Activer toutes les options de performance d’un coup, c’est comme boire cinq boissons énergisantes pour « mieux dormir ». Vous apprendrez des choses, mais pas ce que vous vouliez.

Tâches pratiques : commandes, sorties et la décision que vous prenez

Voici des vérifications réelles que j’exécute sur un hôte Proxmox quand le stockage VM est lent, incohérent ou « parfait jusqu’à ce que ça ne le soit plus ». Chaque tâche inclut une commande, une sortie d’exemple, ce que la sortie signifie, et la décision suivante.

Task 1: Identify pools, health, and obvious red flags

cr0x@server:~$ zpool status
  pool: rpool
 state: ONLINE
status: Some supported features are not enabled on the pool.
action: Upgrade the pool to enable all features.
  scan: scrub repaired 0B in 00:12:44 with 0 errors on Sun Dec 22 03:12:26 2025
config:

        NAME                        STATE     READ WRITE CKSUM
        rpool                       ONLINE       0     0     0
          mirror-0                  ONLINE       0     0     0
            ata-SAMSUNG_SSD_1TB_A   ONLINE       0     0     0
            ata-SAMSUNG_SSD_1TB_B   ONLINE       0     0     0

errors: No known data errors

Ce que ça signifie : Pool en ligne, pas d’erreurs, scrub propre. L’avertissement sur les features n’est pas un problème de performance en soi.

Décision : Si vous voyez des vdevs dégradés, des erreurs de checksum ou des resilvers constants, arrêtez le tuning et réparez le matériel d’abord. Tuner des performances sur un pool défaillant, c’est comment on obtient des rapports de panne créatifs.

Task 2: Check pool fullness (the silent performance killer)

cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint -r rpool
NAME                 USED  AVAIL  REFER  MOUNTPOINT
rpool                720G   180G   104K  /rpool
rpool/data           680G   180G   104K  /rpool/data
rpool/data/vmdata    640G   180G    96K  /rpool/data/vmdata

Ce que ça signifie : ~80% utilisé. Vous entrez dans la zone où fragmentation et overhead d’allocation commencent à se manifester.

Décision : Si vous êtes au-dessus de ~80–85% sur un pool lourd en VM, planifiez une action capacitaire maintenant : ajoutez des vdevs, migrez des VM froides, ou séparez les charges. N’essayez pas d’« optimiser » votre sortie de la physique.

Task 3: Inspect critical dataset properties (compression, atime, sync)

cr0x@server:~$ zfs get -o name,property,value -s local,default compression,atime,sync,primarycache rpool/data/vmdata
NAME               PROPERTY      VALUE
rpool/data/vmdata  compression   off
rpool/data/vmdata  atime         on
rpool/data/vmdata  sync          standard
rpool/data/vmdata  primarycache  all

Ce que ça signifie : Compression désactivée et atime activé : vous payez des I/O supplémentaires. sync standard : la sémantique durable est en jeu. primarycache all : ARC peut double-cacher les données invitées.

Décision : Activez compression=lz4 et atime=off sur les datasets VM sauf raison contraire. Évaluez primarycache selon la pression mémoire et le cache invité.

Task 4: Apply safe, reversible dataset changes (lz4 + atime off)

cr0x@server:~$ sudo zfs set compression=lz4 atime=off rpool/data/vmdata
cr0x@server:~$ zfs get -o name,property,value compression,atime rpool/data/vmdata
NAME               PROPERTY     VALUE
rpool/data/vmdata  compression  lz4
rpool/data/vmdata  atime        off

Ce que ça signifie : Les écritures futures seront compressées ; les mises à jour d’heure d’accès cessent de générer du bruit.

Décision : C’est généralement un gain net. Si le CPU devient un goulot d’étranglement (rare avec lz4), vous le verrez dans les métriques CPU hôte sous charge I/O.

Task 5: List zvols and check volblocksize

cr0x@server:~$ zfs list -t volume -o name,volblocksize,used,refer,logicalused -r rpool/data/vmdata
NAME                         VOLBLOCKSIZE  USED  REFER  LOGICALUSED
rpool/data/vmdata/vm-101-disk-0  128K       64G   64G       120G
rpool/data/vmdata/vm-102-disk-0  8K         20G   20G        22G

Ce que ça signifie : Volblocksize incohérent. Un disque OS en 128K a souvent de mauvaises performances en I/O aléatoire. LOGICALUSED > REFER indique compression/snapshots ou effets de thin provisioning.

Décision : Pour les disques VM généraux, standardisez (souvent 16K) sauf raison mesurée contraire. Pour les disques existants, planifiez une migration pour en tirer pleinement parti.

Task 6: Check whether you’re abusing sync semantics (latency spikes)

cr0x@server:~$ sudo zpool iostat -v rpool 1 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
rpool        720G   180G    150    980  12.4M  5.1M
  mirror-0   720G   180G    150    980  12.4M  5.1M
    ata-SAMSUNG_SSD_1TB_A     -      -     75    490  6.2M  2.6M
    ata-SAMSUNG_SSD_1TB_B     -      -     75    490  6.2M  2.6M

Ce que ça signifie : Bande passante modérée mais opérations d’écriture élevées : pattern classique de petites écritures. Si la latence est mauvaise pendant cela, les écritures sync peuvent forcer des attentes.

Décision : Ensuite, inspectez la latence ZFS et le comportement sync (tâches ci-dessous). Si c’est un hôte de base de données, supposez que sync compte jusqu’à preuve du contraire.

Task 7: Check ZFS latency directly

cr0x@server:~$ sudo zpool iostat -rlv rpool 1 3
                              read                              write
pool        r/s   w/s  rMB/s  wMB/s  rlat  wlat  cholat  dlat
----------  ----  ---- -----  -----  ----  ----  ------  ----
rpool        120   950  10.1   4.9   2ms   38ms   42ms   1ms

Ce que ça signifie : Latence d’écriture ~38ms, plus élevée en charge. C’est le territoire « les VM paraissent lentes », particulièrement pour les métadonnées et le journaling.

Décision : Si wlat augmente régulièrement dans les dizaines/centaines de ms, vous devez traiter le chemin sync, la saturation du pool ou le comportement des périphériques (firmware/PLP). Tuner les invités ne réparera pas la latence hôte.

Task 8: See if you even have a separate log (SLOG)

cr0x@server:~$ zpool status -v rpool
  pool: rpool
 state: ONLINE
config:

        NAME                        STATE     READ WRITE CKSUM
        rpool                       ONLINE       0     0     0
          mirror-0                  ONLINE       0     0     0
            ata-SAMSUNG_SSD_1TB_A   ONLINE       0     0     0
            ata-SAMSUNG_SSD_1TB_B   ONLINE       0     0     0

errors: No known data errors

Ce que ça signifie : Pas de section logs. Les écritures sync atterrissent sur les vdevs principaux.

Décision : Si vous avez des charges sync-intensives et de la douleur en latence, évaluez un SLOG approprié (mirrored, power-loss protected). Sans PLP, vous achetez juste de nouvelles façons de perdre des données rapidement.

Task 9: Check ARC pressure and memory reality

cr0x@server:~$ grep -E 'MemTotal|MemFree|MemAvailable' /proc/meminfo
MemTotal:       131900192 kB
MemFree:         4021184 kB
MemAvailable:   18944128 kB
cr0x@server:~$ cat /proc/spl/kstat/zfs/arcstats | egrep '^(size|c |c_min|c_max|hits|misses) '
size                            4    82463313920
c                               4    85899345920
c_min                           4    4294967296
c_max                           4    85899345920
hits                            4    2840093011
misses                          4    390129220

Ce que ça signifie : ARC ~82G, peut monter à ~85G. MemAvailable ~18G suggère que l’hôte n’est pas affamé, mais les invités pourraient l’être.

Décision : Si l’hôte swap régulièrement ou MemAvailable est continuellement faible, réduisez l’ARC (ou ajoutez de la RAM). Si les invités manquent de mémoire, envisagez primarycache=metadata pour les zvols VM afin d’empêcher l’hôte de « trop aider ».

Task 10: Verify discard/TRIM is enabled end-to-end

cr0x@server:~$ lsblk -D
NAME        DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
sda                0      512B       2G         0
sdb                0      512B       2G         0
cr0x@server:~$ sudo zpool get autotrim rpool
NAME   PROPERTY  VALUE     SOURCE
rpool  autotrim  off       default

Ce que ça signifie : Les disques supportent discard, mais autotrim du pool est off.

Décision : Envisagez d’activer autotrim sur les pools SSD là où la récupération d’espace compte et votre charge ne sera pas affectée par une activité trim supplémentaire. Puis vérifiez que le discard invité est activé dans Proxmox pour les disques VM.

Task 11: Enable autotrim (if appropriate) and observe

cr0x@server:~$ sudo zpool set autotrim=on rpool
cr0x@server:~$ sudo zpool get autotrim rpool
NAME   PROPERTY  VALUE  SOURCE
rpool  autotrim  on     local

Ce que ça signifie : Le pool transmettra les trims. Cela peut aider la performance SSD et le comportement d’espace à long terme.

Décision : Si activer trim corrèle avec des pics de latence sur certains SSD, désactivez-le et exécutez des trims programmés pendant les fenêtres calmes.

Task 12: Check fragmentation (especially on long-lived VM pools)

cr0x@server:~$ zpool list -o name,size,alloc,free,frag,cap,dedupratio
NAME   SIZE  ALLOC   FREE  FRAG  CAP  DEDUP
rpool  900G   720G   180G   42%  80%  1.00x

Ce que ça signifie : 42% de fragmentation n’est pas catastrophique, mais peut contribuer à la latence d’E/S aléatoire sur des pools occupés, surtout combinée à une forte occupation.

Décision : Si frag est élevé et le pool est aussi plein, arrêtez. Planifiez une migration ou une expansion. Le « tuning » de fragmentation est principalement de la gestion capacitaire déguisée.

Task 13: Check whether dedup is accidentally enabled

cr0x@server:~$ zfs get -o name,property,value dedup -r rpool/data/vmdata
NAME               PROPERTY  VALUE
rpool/data/vmdata  dedup     off

Ce que ça signifie : Dedup est off. Bien.

Décision : Si dedup est activé pour le stockage VM et que vous n’en avez pas conçu l’utilisation, désactivez-le pour les nouvelles écritures et planifiez une remédiation. Dedup sans dimensionnement et tests transforme la RAM en goulot de performance.

Task 14: Observe per-vdev device latency with iostat

cr0x@server:~$ iostat -x 1 3
Linux 6.8.12-pve (server) 	12/25/2025 	_x86_64_	(32 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           8.12    0.00    2.91   11.44    0.00   77.53

Device            r/s     w/s   rkB/s   wkB/s  avgrq-sz avgqu-sz   await  r_await  w_await  svctm  %util
sda             85.0   490.0  6200.0  2600.0     27.4     3.10   38.2     3.1     44.1    0.8   46.2
sdb             85.0   490.0  6200.0  2600.0     27.4     3.06   37.9     3.0     43.7    0.8   46.0

Ce que ça signifie : iowait hôte non négligeable (11%). Les écritures ont un await ~44ms : cela correspond à wlat ZFS. Les périphériques ne sont pas à 100% util, mais la latence est élevée — courant quand le périphérique fait du garbage collection interne ou gère des flushes.

Décision : Si await est élevé alors que %util n’est pas saturé, suspectez le comportement des flushes, le firmware ou la pression sync plutôt qu’une saturation pure du débit.

Task 15: Check Proxmox VM disk config for risky cache modes

cr0x@server:~$ qm config 101 | egrep 'scsi|virtio|ide|sata|boot'
boot: order=scsi0;net0
scsi0: rpool/data/vmdata/vm-101-disk-0,discard=on,iothread=1,cache=writeback,ssd=1

Ce que ça signifie : cache=writeback peut être rapide, mais modifie les sémantiques d’échec. En writeback, l’hôte peut accuser réception des écritures avant qu’elles ne soient sûres sur disque.

Décision : Pour les bases de données et tout ce qui tient à la cohérence, préférez des modes de cache plus sûrs (et comptez sur ZFS + du matériel approprié). Si vous choisissez writeback en connaissance de cause, documentez-le comme une arme chargée.

Task 16: Confirm pool ashift (because you can’t fix it later)

cr0x@server:~$ sudo zdb -C rpool | egrep 'ashift|vdev_tree' -n | head
54:        vdev_tree:
86:            ashift: 12

Ce que ça signifie : ashift=12 (secteurs 4K). C’est généralement correct pour les disques modernes.

Décision : Si vous voyez ashift=9 sur des disques réellement 4K, attendez-vous à des douleurs de performance. La réparation implique généralement de reconstruire le pool. Planifiez en conséquence.

Task 17: Check snapshot bloat (because “free space” might be trapped)

cr0x@server:~$ zfs list -o name,used,usedbysnapshots,usedbydataset,logicalused -r rpool/data/vmdata | head
NAME               USED  USEDSNAP  USEDDS  LOGICALUSED
rpool/data/vmdata  640G     210G    96K       1.1T

Ce que ça signifie : 210G utilisés par les snapshots. Ce n’est pas « mauvais » ; c’est une décision de politique. Mais cela impacte l’occupation du pool et les performances.

Décision : Si les snapshots mangent de l’espace et vous poussent vers la zone dangereuse d’occupation élevée, resserrez la rétention ou déplacez les sauvegardes ailleurs. « On garde tout pour toujours » n’est pas une stratégie de stockage.

Task 18: Verify compression is actually working (ratio check)

cr0x@server:~$ zfs get -o name,property,value compressratio -r rpool/data/vmdata | head
NAME               PROPERTY      VALUE
rpool/data/vmdata  compressratio 1.38x

Ce que ça signifie : 1.38x est un gain significatif. Vous réduisez les I/O physiques pour de nombreuses charges.

Décision : Si compressratio est ~1.00x pour des données chiffrées/incompressibles, c’est attendu. Pourtant, l’overhead lz4 est généralement suffisamment faible pour rester activé.

Idée paraphrasée — John Allspaw : La fiabilité vient du fait de concevoir des systèmes qui échouent en sécurité, pas d’assumer qu’ils n’échoueront pas.

Playbook de diagnostic rapide (premières/secondes/troisièmes vérifs)

Voici le flux de triage rapide quand le ticket est « le stockage VM est lent » et que vous avez 15 minutes avant la prochaine réunion que vous ignorerez de toute façon.

Première étape : le niveau stockage hôte est-il malade ou juste occupé ?

  • Exécutez zpool status : cherchez des périphériques dégradés, erreurs de checksum, resilverings ou scrubs en cours pendant les pics.
  • Exécutez zpool iostat -rlv 1 3 : vérifiez la latence d’écriture (wlat). Si wlat est élevé, le niveau stockage est le problème.
  • Exécutez iostat -x 1 3 : confirmez await sur périphérique et iowait. Un await élevé confirme que la douleur est réelle au niveau périphérique.

Deuxième étape : êtes-vous noyé par des écritures sync ?

  • Vérifiez la propriété sync du dataset/zvol (et ne présumez pas). Si sync=standard, les écritures sync attendront un média stable.
  • Confirmez si vous avez un SLOG. Si non, la latence sync est payée sur les vdevs principaux.
  • Cherchez des charges déclenchant des sync storms : bases de données, mail, NFS à l’intérieur d’invités, filesystems journalling sous stress.

Troisième étape : êtes-vous limité par la capacité et la fragmentation ?

  • Vérifiez cap et frag du pool. Haute capacité plus haute frag est un multiplicateur de latence.
  • Vérifiez l’utilisation des snapshots. Les snapshots peuvent emprisonner de l’espace et accélérer le comportement « pool trop plein ».
  • Vérifiez les surprises de thin provisioning : les invités croient avoir de l’espace, le pool non.

Si ces trois vérifs sont propres

Alors vous examinez la configuration niveau VM : mode cache, bus disque, iothread, profondeur de queue et comportement système de fichiers invité. Mais ne commencez pas par là. C’est comme tuner le tableau de bord alors que le moteur manque un cylindre.

Erreurs courantes : symptôme → cause racine → correctif

1) Symptôme : « Tout se fige pendant 1–5 secondes aléatoirement »

Cause racine : Pics de latence d’écriture sync (flushes, fsync storms) sur un pool sans SLOG approprié, souvent combinés à des SSD grand public qui se bloquent sous la pression des flushes.

Correctif : Gardez sync=standard pour les données importantes, ajoutez un SLOG miroir capable de PLP si besoin, et validez avec zpool iostat -rlv. Si les données sont jetables, définissez sync=disabled sur ce dataset/zvol spécifique et documentez le risque.

2) Symptôme : « Les VM sont rapides en benchmark, mais les applis réelles sont lentes »

Cause racine : Les benchmarks touchent des chemins séquentiels ; les applis touchent des patterns aléatoires sync-intensifs et métadonnées. Aussi fréquent : mismatch de volblocksize pour les zvols.

Correctif : Adaptez volblocksize à la charge (souvent 16K pour les disques VM généraux), évitez qcow2-sur-ZFS quand inutile, et mesurez la latence pas seulement le débit.

3) Symptôme : « Le pool a de l’espace, mais les performances sont terribles »

Cause racine : Pool trop plein (80–95%), snapshots emprisonnent de l’espace, l’allocateur est sous pression ; la fragmentation augmente.

Correctif : Réduisez la rétention des snapshots, migrez des données, élargissez le pool. Traitez l’espace libre comme une réserve de performance, pas une suggestion.

4) Symptôme : « Après activation d’autotrim, la latence s’est aggravée »

Cause racine : Certains SSD gèrent mal les trims continus ; les opérations trim concurrencent les écritures en premier plan.

Correctif : Désactivez autotrim et lancez des trims planifiés pendant les fenêtres calmes. Envisagez des SSD d’entreprise au comportement trim prévisible.

5) Symptôme : « L’hôte a beaucoup de RAM, mais les invités swappent sous charge »

Cause racine : ARC grandit agressivement et vole de la mémoire nécessaire aux invités, ou vous double-cachez les données VM sur hôte et invité.

Correctif : Envisagez primarycache=metadata pour les zvols VM ; limitez l’ARC si nécessaire ; validez avec arcstats et les métriques mémoire invitées.

6) Symptôme : « Les sauvegardes rendent la production inutilisable »

Cause racine : I/O de snapshot/sauvegarde qui entre en collision avec les écritures aléatoires de production ; les sauvegardes peuvent induire une amplification de lecture et du churn métadonnées.

Correctif : Planifiez les sauvegardes, bridez si possible, isolez le stockage de sauvegarde, et évitez de placer les cibles de sauvegarde sur le même pool stressé.

7) Symptôme : « On a ajouté un cache SSD rapide et rien n’a changé »

Cause racine : L2ARC n’aide pas la latence d’écriture ; il aide le cache de lecture, et seulement si votre working set et pattern d’accès s’y prêtent. De plus, les dispositifs de cache peuvent voler de la RAM et ajouter du overhead.

Correctif : Résolvez la latence d’écriture au niveau vdev/sync. N’ajoutez L2ARC qu’après avoir confirmé que les lectures sont le goulot et que le hit rate ARC est insuffisant.

Trois mini-histoires du monde corporate depuis le front du stockage

Mini-histoire n°1 : L’incident causé par une mauvaise hypothèse

Ils ont migré une petite flotte de VM applicatives sur Proxmox avec des miroirs ZFS sur des « bons SSD ». C’était un design sensé, approuvé par le budget : deux disques, miroir, beaucoup d’IOPS sur le papier. Les applis étaient majoritairement des services web sans état avec une petite VM base de données et un broker de messages.

L’hypothèse erronée était subtile : « Si c’est un miroir SSD, les écritures sync sont presque gratuites. » Personne ne l’a dit à voix haute, ce qui explique comment les hypothèses survivent. Ils ont aussi supposé que les réglages de durabilité de la base étaient conservateurs mais pas agressifs. La plateforme est passée en production, a bien paru, puis a commencé à produire de courts pics de latence pendant les heures de pointe.

L’équipe on-call a chassé des fantômes : jitter réseau, voisins bruyants, steal CPU, même « peut-être que Linux a une régression de scheduler ». Pendant ce temps, la VM base de données faisait des choses parfaitement raisonnables — commits avec fsync — et ZFS faisait des choses parfaitement raisonnables — attendre le stockage stable.

Une fois qu’ils ont tracé la latence d’écriture hôte à côté des timeouts applicatifs, l’histoire s’est écrite d’elle-même. Les SSD étaient des modèles grand public avec des latences de flush incohérentes. Quand la base a déclenché une rafale d’écritures sync, les périphériques se sont bloqués. Le miroir ne les a pas sauvés ; il a juste fourni deux périphériques capables de se bloquer en sympathie.

La réparation n’était pas exotique. Ils ont déployé un SLOG mirroir sur des dispositifs protégés contre la perte d’alimentation et arrêté de prétendre que la latence de flush n’avait pas d’importance. Les pics ont disparu. L’équipe a aussi documenté quels datasets toléraient sync=disabled (peu) et lesquels ne le pouvaient pas (la base et le broker). La leçon clé était opérationnelle : ne présumez jamais que votre stockage honore rapidement la durabilité simplement parce que c’est « SSD ».

Mini-histoire n°2 : L’optimisation qui s’est retournée contre eux

Une autre organisation voulait « performance maximale » et s’est montrée agressive dans le tuning. Ils ont désactivé sync globalement. Ils ont mis les disques VM en cache writeback. Ils ont activé tous les toggles de performance côté invité qu’ils ont trouvés. Ils ont aussi choisi qcow2 parce que ça rendait le déplacement des disques « plus facile ».

Pendant un temps, ça a marché. Les benchmarks semblaient héroïques. Les déploiements étaient rapides. Tout le monde s’est tapé dans la main et est retourné au travail produit. Puis un reboot d’hôte est arrivé — mise à jour noyau de routine, rien de dramatique — et quelques VM sont revenues avec des systèmes de fichiers corrompus. La base a récupéré. La VM mail non. Le post-mortem a été… pédagogique.

Le retour de flamme n’était pas dû au fait qu’un réglage était « mauvais » pris isolément. C’était la combinaison : cache writeback plus sync désactivé plus les patterns d’écriture propres à qcow2 ont créé un système qui accusait réception des écritures de façon optimiste. Le système était rapide parce qu’il mentait pratiquement sur ce qui était durable.

Ils sont revenus à des valeurs plus sûres, mais pas aveuglément. Ils ont déplacé le tuning de performance dans une politique : pour les charges jetables, la vitesse primait ; pour les charges étatful, ils ont optimisé le chemin matériel de stockage au lieu de désactiver la cohérence. Ils ont aussi migré de qcow2 vers raw quand possible pour réduire l’empilement CoW et le overhead métadonnées.

Le vrai coût n’était pas la corruption elle-même — c’était la semaine de confiance perdue. Les utilisateurs ne se soucient pas que vous puissiez expliquer les sémantiques de cache. Ils veulent que leurs données reviennent.

Mini-histoire n°3 : La pratique ennuyeuse mais correcte qui a tout sauvé

Une entreprise moyenne faisait tourner des clusters Proxmox pour des services internes. Rien d’extraordinaire : contrôleurs de domaine, Git, monitoring, quelques petites bases, et une surprenante quantité de sync de fichiers. Leur stockage était des miroirs ZFS et du RAIDZ pour le bulk. Ils avaient une pratique qui semblait douloureusement ennuyeuse : scrubs hebdomadaires, surveillance SMART, et seuils stricts d’occupation de pool.

Ils standardisaient aussi les propriétés des datasets VM : compression lz4 activée, atime désactivé, et décisions explicites sur sync. Le plus important : règle stricte — aucun pool VM au-delà de 80% sans plan capacitaire signé. Les gens râlaient. La finance râlait. Tout le monde râle quand on dit « non ».

Un trimestre, une série de SSD a commencé à montrer des erreurs média croissantes. Rien n’a explosé. Pas de voyants rouges. Juste une tendance SMART et quelques lectures lentes visibles comme de légères augmentations de latence pendant les scrubs. Parce que les scrubs étaient réguliers et les alertes liées aux changements, ils l’ont détecté tôt.

Ils ont remplacé des disques pendant les heures ouvrables, un à la fois, avec des resilvers contrôlés. Aucun bridge d’incident. Aucune indisponibilité visible pour les utilisateurs. La pratique ennuyeuse — discipline des scrubs et gestion de capacité — a empêché le pool d’entrer dans la zone « trop plein pour résilver confortablement ». Ils n’ont pas gagné de prix. Ils n’ont juste pas eu une mauvaise semaine.

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

Checklist A: Paramètres par défaut jour un pour un nouveau pool ZFS VM Proxmox

  1. Créez le pool avec le bon ashift (généralement 12). Vérifiez avec zdb -C avant d’y mettre des données.
  2. Créez un dataset dédié pour le stockage VM (ne mettez pas tout dans les datasets racines).
  3. Activez compression=lz4 sur le dataset VM.
  4. Désactivez atime=off sur le dataset VM.
  5. Décidez de la politique sync par dataset : durable par défaut ; désactivez seulement pour les charges que vous pouvez perdre.
  6. Si vous utilisez des zvols, standardisez le volblocksize (souvent 16K pour les disques VM généraux). Décidez avant de créer les disques.
  7. Définissez le comportement du primarycache pour les disques VM (envisagez metadata-only en cas de contention mémoire).
  8. Définissez et appliquez des seuils d’occupation (alerte à 70–75%, action à 80%).

Checklist B: Quand une VM semble lente (triage 15 minutes)

  1. Vérifiez zpool status (erreurs ? resilver ? scrub ?). Si oui, stoppez et stabilisez.
  2. Vérifiez zpool iostat -rlv 1 3 (latence écriture ?). Si élevée, le chemin stockage est le goulot.
  3. Vérifiez iostat -x 1 3 (await périphérique, iowait). Confirmez que ce n’est pas juste une perception invitée.
  4. Vérifiez l’occupation et la frag du pool (zpool list, zfs list) et l’utilisation des snapshots. Si trop plein, vous avez besoin de capacité, pas d’ambiances.
  5. Vérifiez le mode cache du disque VM (qm config) et les propriétés du dataset (zfs get).

Checklist C: Migration contrôlée pour corriger un volblocksize inapproprié

  1. Créez un nouveau zvol avec le volblocksize désiré.
  2. Utilisez la migration de stockage Proxmox ou une copie bloc contrôlée pendant que la VM est arrêtée (préférable pour la cohérence).
  3. Validez les performances et la latence avec zpool iostat -rlv et des vérifications applicatives.
  4. Supprimez l’ancien zvol et surveillez la fragmentation et l’espace.

FAQ

1) Dois-je utiliser ZFS ou LVM-thin pour le stockage VM Proxmox ?

Si vous voulez des snapshots/réplication simples et une intégrité bout en bout, ZFS est un bon choix. Si vous voulez un modèle mental plus simple pour le stockage bloc et moins d’interaction CoW, LVM-thin peut être plus facile. Pour beaucoup d’équipes, ZFS gagne opérationnellement — à condition de traiter sync, capacité et dimensionnement des blocs comme des préoccupations de premier ordre.

2) compression=lz4 est-il sûr pour les disques VM ?

Oui. C’est transparent et largement déployé. Le « risque » est surtout le coût CPU, généralement mineur comparé aux I/O économisés. Le vrai risque est de ne pas activer la compression et de se demander pourquoi le pool bouge toujours des octets inutiles.

3) Quel volblocksize devrais-je utiliser pour des zvols VM ?

Les valeurs par défaut communes pour les disques VM généraux sont 16K (souvent un bon compromis). Pour des charges spécialisées, mesurez : les bases de données aiment parfois 8K ou 16K ; les charges séquentielles larges peuvent préférer 64K+. L’important est la cohérence et l’intention : choisissez selon la charge, pas la superstition.

4) Puis-je changer volblocksize après création du zvol ?

Vous pouvez changer la propriété, mais les blocs déjà écrits restent à l’ancienne taille. Pour en bénéficier vraiment, migrez les données vers un nouveau zvol créé avec le volblocksize correct.

5) Dois-je désactiver sync pour accélérer Proxmox ?

Seulement si vous acceptez de perdre des écritures récentes en cas de panne ou crash — et seulement pour les datasets où cela est acceptable. Pour des systèmes réels avec des données réelles, construisez un chemin de stockage capable de gérer sync=standard plutôt que d’éteindre la cohérence globalement.

6) Ai-je besoin d’un SLOG pour ZFS sur des miroirs SSD ?

Pas toujours. Si votre charge est majoritairement asynchrone en écriture et en lecture, vous pouvez vous en sortir. Si vous avez des écritures sync significatives et que la latence vous importe, un SLOG approprié peut beaucoup aider. « Approprié » signifie faible latence, protégé contre la perte d’alimentation, et idéalement en miroir.

7) qcow2 est-il une mauvaise idée sur ZFS ?

Souvent, oui — car cela empile CoW sur CoW, augmentant fragmentation et overhead métadonnées. Si vous avez besoin des fonctionnalités qcow2, utilisez-le en connaissance de cause. Sinon, raw sur ZFS est généralement le choix plus calme et prévisible.

8) Pourquoi les performances s’effondrent-elles quand le pool se remplit ?

ZFS a besoin d’espace libre pour allouer efficacement. Quand l’espace libre diminue, les allocations deviennent plus difficiles, la fragmentation augmente, et l’amplification d’écriture croît — surtout avec des E/S aléatoires VM. Garder 20–30% libre n’est pas du gaspillage ; c’est acheter une latence stable.

9) Dois-je définir primarycache=metadata pour tout le stockage VM ?

C’est un bon défaut quand les invités sont gros et qu’il y a une pression mémoire, car cela réduit le double caching. Si l’hôte a beaucoup de RAM et que les invités sont petits/lecture-intensifs, mettre en cache les données peut aider. Ne devinez pas : vérifiez le comportement ARC et la santé mémoire des invités.

10) autotrim aide-t-il toujours sur les pools SSD ?

Souvent il aide le comportement d’espace à long terme et peut maintenir la performance SSD, mais certains dispositifs gèrent mal les trims continus. Activez, observez la latence, et soyez prêt à basculer sur des trims programmés si besoin.

Conclusion : prochaines étapes pratiques

Si vous exécutez Proxmox sur ZFS et que vous n’avez pas touché aux paramètres de stockage, vous avez probablement un système qui se comporte bien un mardi et vous trahit un jeudi. Le corriger n’est pas magique. C’est de la politique.

  1. Activez la compression lz4 et désactivez atime sur les datasets de stockage VM aujourd’hui. C’est peu risqué, souvent très rentable.
  2. Auditez le comportement sync. Décidez ce qui doit être durable et architectez en conséquence. Ne désactivez pas sync par accident sur tout le cluster.
  3. Standardisez le volblocksize pour les nouveaux disques VM (souvent 16K) et planifiez des migrations pour les pires cas.
  4. Arrêtez de surremplir les pools. La capacité est une fonctionnalité de performance. Faites-en un SLO surveillé, pas une surprise nocturne.
  5. Mesurez la latence, pas seulement le débit. Utilisez zpool iostat -rlv et iostat -x pour rester honnête.

Faites ces cinq choses, et la plupart des plaintes « ZFS est lent » disparaîtront. Les rares restantes seront au moins des problèmes honnêtes — limites matérielles, réalités de charge, et la décision occasionnelle que vous avez prise volontairement.

← Précédent
Debian 13 : les retransmissions TCP tuent les performances — localisez l’endroit réel des pertes
Suivant →
Debian 13 — Changement du port SSH : corriger le pare-feu et l’ordre sshd sans se bloquer (cas n°87)

Laisser un commentaire