Proxmox : la raison cachée pour laquelle votre VM semble lente (même sur NVMe)

Cet article vous a aidé ?

« Mais c’est sur NVMe. » Cette phrase a clos plus d’incidents qu’elle n’en a résolus. Vous avez acheté un média rapide, vous pouvez le benchmarker, et pourtant la VM donne l’impression de réfléchir avant de répondre. Les connexions tardent. Les installations de paquets rampent. Votre base de données affirme être « I/O bound », ce qui est à la fois utile et insuffisant.

La raison cachée n’est généralement pas le débit brut. C’est la latence — en particulier la latence d’écriture — créée par une pile de choix par défaut sûrs, génériques et parfois cruels : les sémantiques sync, les modes de cache, l’ordonnancement, le comportement des provisionnements minces, l’amplification CoW, la réplication de stockage et la contention sur l’hôte. NVMe ne corrige pas les mauvaises décisions ; il les accélère simplement.

La raison cachée : votre VM paye une latence que vous n’avez pas budgétée

Le marketing NVMe célèbre le débit. Vos utilisateurs perçoivent cependant la latence en queue : le délai au 95e/99e percentile des « petites opérations synchrones qui doivent se terminer avant la suite ». La « lenteur » d’une VM est souvent juste mille petites écritures sync qui patientent poliment derrière l’idée de durabilité d’un autre flux.

Dans Proxmox, le chemin de stockage est un gâteau en couches :

  • Guest filesystem & application semantics (fsync, O_DIRECT, journaling, barriers)
  • Virtual device model (virtio-scsi vs virtio-blk, queues, iothreads)
  • QEMU cache mode (writeback/writethrough/none/directsync) and AIO
  • Host filesystem and volume manager (ZFS, LVM-thin, directory, Ceph RBD)
  • Host block layer (scheduler, merge behavior, multipath)
  • Physical device behavior (NVMe firmware, thermal throttling, SLC cache, power-loss protection)

La « raison cachée » est typiquement un décalage entre les attentes du guest et les garanties de l’hôte. Le guest émet des écritures sync, et quelque part en dessous la pile dit : « D’accord, je confirmerai quand ce sera vraiment sûr. » C’est un bon choix d’ingénierie. C’est aussi pourquoi l’installation d’un petit paquet peut ressembler à une déclaration d’impôts.

Conseil personnel : arrêtez de courir après les MB/s affichés. Commencez à mesurer les IOPS en faible profondeur de file, la latence fsync et le temps d’attente côté hôte. La plupart des incidents « NVMe lent » sont soit (a) latence d’écriture sync (ZFS, Ceph, write barriers), (b) contention/queueing (un voisin bruyant), ou (c) une « optimisation » comme discard, compression ou snapshots qui interagit mal avec votre charge.

Blague #1 : NVMe, c’est comme filer une voiture de sport à votre stagiaire — impressionnant jusqu’à ce qu’il réalise qu’il prend toujours la route panoramique pour aller au data center.

Faits et histoire intéressants (parce que les valeurs par défaut ont des histoires)

  1. Les modes de cache de QEMU existent parce que le stockage ment. Aux débuts de la virtualisation, « writeback » pouvait être rapide mais risqué si la pile sous-jacente ne persistait pas réellement les données.
  2. ZFS a été conçu autour des checksums et du copy-on-write. Cela vous offre intégrité et snapshots, mais modifie les schémas d’écriture et peut amplifier de petites écritures aléatoires selon recordsize/volblocksize.
  3. Le grand avantage de NVMe est le parallélisme. Le protocole gère de nombreuses queues de soumission/complétion, mais une VM avec une seule queue peut toujours être limitée par le CPU et les locks.
  4. Les ordonnanceurs I/O Linux ont évolué pour les disques mécaniques. Certains restent utiles pour l’équité et le contrôle de latence ; d’autres ajoutent simplement de la surcharge aux chemins NVMe qui n’ont pas besoin de réordonnancement.
  5. Les write barriers et flushes se sont durcis avec le temps. Les systèmes de fichiers ont appris que « rapide » sans durabilité ordonnée devient « corruption rapide », surtout après une coupure de courant.
  6. La thin provisioning s’est généralisée parce que la capacité coûte cher. Mais les pools minces peuvent se fragmenter et leur métadonnée devenir un limiteur silencieux de performance si mal surveillés.
  7. TRIM/discard n’est pas « gratuit ». Il aide la longévité des SSD et la performance en état stable, mais le discard en ligne peut créer des pics de latence périodiques selon le firmware et la charge.
  8. La force de Ceph est la durabilité distribuée. Cette durabilité ajoute latence réseau et réplication ; NVMe sur les nœuds OSD n’efface pas magiquement le coût de quorum et d’acknowledgment.

Mode d’urgence : comment diagnostiquer vite

Vous n’avez pas besoin d’une semaine d’optimisations. Vous avez besoin de 20 minutes d’observation contrôlée. Voici l’ordre qui identifie le goulot le plus rapidement en production.

Première étape : confirmer que le symptôme est la latence I/O, pas le steal CPU ou la pression mémoire

  • Dans le guest : vérifiez iowait et la latence disque. Si le CPU est saturé ou la mémoire swapée, le tuning stockage est du théâtre.
  • Sur l’hôte : vérifiez un comportement type CPU steal (surcharge hôte), ballooning KSM et swapping.

Deuxième étape : identifier le backend de stockage et ses sémantiques de durabilité

  • ZFS : comportement sync, présence/qualité de SLOG, recordsize/volblocksize, compression, vdevs spéciaux.
  • LVM-thin : usage données/métadonnées, comportement discard, signes de fragmentation.
  • Ceph RBD : latence sur le chemin réseau, commit/apply des OSD, réplication, paramètres client.
  • Directory/ext4/xfs : options de montage de l’hôte, cache d’écriture, barriers, santé du système de fichiers.

Troisième étape : vérifier le modèle de périphérique VM et l’ordonnancement

  • virtio-scsi avec iothread et plusieurs queues lorsque c’est approprié.
  • Mode de cache correct pour le backend (et honnêteté sur les compromis de risque).

Quatrième étape : trouver la contention et la latence tail

  • Cherchez une VM qui effectue de grosses écritures, des sauvegardes ou des merges de snapshot.
  • Mesurez l’utilisation disque et la profondeur de file sur l’hôte, pas seulement à l’intérieur de la VM.

Cinquième étape : vérifier que le NVMe lui-même n’est pas le goulot

  • Throttling thermique, bugs firmware, vitesse de lien PCIe et réglages d’alimentation peuvent transformer « rapide » en « poli ».

Règle de décision : si vous ne pouvez pas pointer vers un des (a) latence sync, (b) queueing/contention, (c) pression CPU/mémoire, (d) mauvaise configuration du backend, vous devinez encore. Continuez à mesurer.

Tâches pratiques : commandes, sorties et décisions

Voici les vérifications que j’exécute réellement. Chaque tâche inclut un extrait plausible de sortie et la décision à en tirer.

Task 1: Identify the VM disk backend from Proxmox

cr0x@server:~$ qm config 104 | egrep -i 'scsi|virtio|ide|sata|boot|machine'
boot: order=scsi0;net0
machine: q35
scsi0: nvme-zfs:vm-104-disk-0,iothread=1,cache=none,discard=on,ssd=1,size=80G
scsihw: virtio-scsi-single

Ce que ça signifie : Cette VM utilise un volume backé par ZFS, virtio-scsi-single, cache=none, iothread activé, discard on.

Décision : Si cette VM est sensible à la latence et effectue des écritures sync, vos prochaines vérifications sont le chemin sync de ZFS et si virtio-scsi-single limite le parallélisme des queues.

Task 2: Confirm host storage type (ZFS vs LVM-thin vs directory)

cr0x@server:~$ pvesm status
Name        Type     Status           Total            Used       Available        %
local       dir      active        19684272        4181248        15403024   21.24%
nvme-zfs    zfspool  active       960123904      412345344       547778560   42.95%
ceph-rbd    rbd      active               0               0               0    0.00%

Ce que ça signifie : Le disque VM est sur un pool ZFS nommé nvme-zfs.

Décision : Concentrez-vous sur les propriétés dataset/zvol ZFS (sync, volblocksize, compression) et si un SLOG approprié existe.

Task 3: Check VM-visible latency inside the guest (quick and dirty)

cr0x@server:~$ iostat -x 1 5
Linux 6.1.0 (guest)  02/04/2026  _x86_64_  (4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           8.02    0.00    3.11   22.70    0.00   66.17

Device            r/s     w/s   rkB/s   wkB/s  avgrq-sz avgqu-sz   await  r_await  w_await  svctm  %util
vda              3.00   45.00   120.0  2480.0     114.7     2.80   58.20    8.20   61.60   2.10  10.20

Ce que ça signifie : w_await est ~62 ms. Ce n’est pas « NVMe rapide ». C’est « quelque chose force les écritures à attendre ».

Décision : Cherchez les contraintes du chemin sync : ZFS sync, réplication Ceph, mode de cache, ou contention hôte.

Task 4: Check host-side disk latency and queueing

cr0x@server:~$ iostat -x 1 5
Linux 6.5.13-pve (pve-host)  02/04/2026  _x86_64_  (16 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          10.40    0.00    4.80   18.20    0.00   66.60

Device            r/s     w/s   rkB/s   wkB/s  avgrq-sz avgqu-sz   await  r_await  w_await  svctm  %util
nvme0n1          20.00  800.00   900.0 68000.0     167.5    45.20   55.10    9.80   56.30   0.45  99.00

Ce que ça signifie : %util est saturé et avgqu-sz est élevé. Le périphérique est saturé ou bridé, et la latence augmente.

Décision : Trouvez qui écrit, si ce sont des sauvegardes/scrubs, et si le disque « rapide » atteint ses limites d’écriture soutenue ou un bridage thermique.

Task 5: Identify top I/O consumers on the host

cr0x@server:~$ pidstat -d 1 5
Linux 6.5.13-pve (pve-host)  02/04/2026  _x86_64_  (16 CPU)

#      Time   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
12:01:10     0      21456      0.00  82000.00  12000.00  vzdump
12:01:10     0      17890      0.00  12000.00      0.00  qemu-system-x86
12:01:10     0      17891      0.00  11800.00      0.00  qemu-system-x86

Ce que ça signifie : vzdump martèle les écritures. L’hôte est occupé à faire des sauvegardes, provoquant probablement les pics de latence VM.

Décision : Limitez le débit des sauvegardes, déplacez-les hors du pool principal, ou planifiez-les en dehors des pics. Si vous le faites déjà, validez le comportement snapshot/merge et le backend de stockage.

Task 6: Check ZFS pool health and latency indicators

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

        NAME        STATE     READ WRITE CKSUM
        nvme-zfs    ONLINE       0     0     0
          nvme0n1   ONLINE       0     0     0

errors: No known data errors

Ce que ça signifie : Pas d’erreurs évidentes. La santé n’est pas la performance.

Décision : Passez aux propriétés ZFS et au comportement sync ; vérifiez aussi l’existence d’un SLOG et s’il est approprié.

Task 7: Check ZFS dataset and zvol properties that affect latency

cr0x@server:~$ zfs get -r compression,atime,recordsize,logbias,sync,primarycache,secondarycache nvme-zfs
NAME      PROPERTY        VALUE           SOURCE
nvme-zfs  compression     zstd            local
nvme-zfs  atime           off             local
nvme-zfs  recordsize      128K            local
nvme-zfs  logbias         latency         local
nvme-zfs  sync            standard        local
nvme-zfs  primarycache    all             default
nvme-zfs  secondarycache  all             default

Ce que ça signifie : sync=standard signifie que les écritures sync sont respectées. Bien. Si votre charge effectue beaucoup de fsync, la latence dépendra de la capacité du pool à commettre en toute sécurité.

Décision : Si la latence sync est élevée et que vous tenez à la consistance, ajoutez un SLOG dédié (protection power-loss) ou repensez le schéma d’écriture. Ne basculez pas sync=disabled à la légère, sauf si vous aimez expliquer des pertes de données.

Task 8: Confirm whether a SLOG exists and is actually separate

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

        NAME        STATE     READ WRITE CKSUM
        nvme-zfs    ONLINE       0     0     0
          nvme0n1   ONLINE       0     0     0

errors: No known data errors

Ce que ça signifie : Aucun vdev logs présent. Les écritures sync doivent être engagées sur le vdev principal.

Décision : Si vous exécutez des bases de données, serveurs mail, runners CI ou tout service fsync-intensif, envisagez un SLOG dédié avec protection contre les pertes d’alimentation. Si vous ne pouvez pas, acceptez au moins la latence comme le coût de la durabilité.

Task 9: Measure ZFS latency live

cr0x@server:~$ zpool iostat -v nvme-zfs 1 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
nvme-zfs     393G   519G     40    820  1.2M  70.1M
  nvme0n1    393G   519G     40    820  1.2M  70.1M
----------  -----  -----  -----  -----  -----  -----

Ce que ça signifie : Beaucoup d’opérations d’écriture et de bande passante. Cela n’affiche pas la latence directement, mais indique que le pool est occupé ; corrélez avec iostat -x sur l’hôte et le calendrier des sauvegardes/scrubs.

Décision : Si « occupé » coïncide avec la douleur utilisateur, vous devez isoler la charge : pools séparés, cibles de sauvegarde séparées, ou throttling I/O via cgroups / limites Proxmox.

Task 10: Check NVMe health and throttling hints

cr0x@server:~$ nvme smart-log /dev/nvme0n1 | egrep -i 'temperature|warning|critical|media|power_cycles|unsafe_shutdowns'
critical_warning                    : 0x00
temperature                         : 72 C
available_spare                     : 100%
media_errors                        : 0
power_cycles                        : 38
unsafe_shutdowns                    : 2

Ce que ça signifie : 72°C est chaud. Certains disques throttlent autour de cette plage selon le modèle et le flux d’air. Les unsafe_shutdowns comptent aussi pour l’intégrité si vous comptez sur des caches volatils.

Décision : Améliorez le refroidissement et confirmez que le périphérique ne réduit pas sa vitesse sous écriture soutenue. Si vous observez des problèmes thermiques, votre « VM lente » est en fait de la « physique lente ».

Task 11: Verify PCIe link speed/width (quietly common)

cr0x@server:~$ lspci -s 03:00.0 -vv | egrep -i 'LnkSta|NVMe'
Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller
LnkSta: Speed 8GT/s (ok), Width x2 (downgraded)

Ce que ça signifie : Le disque fonctionne en PCIe x2, pas x4. Cela peut limiter le débit et parfois aggraver les effets de contention.

Décision : Déplacez le périphérique dans un slot avec toutes les lanes, corrigez les réglages BIOS, ou cessez de partager des lanes avec un composant qui ne devrait pas.

Task 12: Check the host I/O scheduler for NVMe

cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[mq-deadline] none kyber bfq

Ce que ça signifie : mq-deadline est actif. C’est souvent un bon défaut pour des charges mixtes car il contrôle la latence sous charge.

Décision : Si vous observez des pics de latence sous contention, conservez un ordonnanceur conscient de la latence (mq-deadline ou kyber). Si vous avez une charge unique et voulez un overhead minimal, testez none — mais seulement avec des mesures.

Task 13: Inspect VM’s virtio-scsi and queue configuration

cr0x@server:~$ qm config 104 | egrep -i 'scsihw|iothread|queues|numa|cpu|machine'
machine: q35
scsihw: virtio-scsi-single
scsi0: nvme-zfs:vm-104-disk-0,iothread=1,cache=none,discard=on,ssd=1,size=80G
cpu: host
numa: 0

Ce que ça signifie : virtio-scsi-single utilise une seule queue par conception. Pour certaines charges, cela devient un goulot sur des guests avec plusieurs vCPU.

Décision : Envisagez virtio-scsi-pci avec plusieurs queues pour un I/O parallèle si la charge du guest en bénéficie. Ne changez pas à l’aveugle : les bases de données tiennent souvent plus à une latence cohérente qu’au nombre brut de queues.

Task 14: Check for host memory pressure (which masquerades as “slow disk”)

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:            62Gi        54Gi       1.2Gi       2.1Gi       6.8Gi       3.0Gi
Swap:          8.0Gi       2.6Gi       5.4Gi

Ce que ça signifie : Le swap est utilisé et la mémoire disponible est faible. Sous pression, le reclaim hôte et le swapping peuvent bloquer les chemins I/O et les vCPU des VM.

Décision : Corrigez le sur-engagement, la politique de ballooning, ou ajoutez de la RAM. Le tuning stockage ne résoudra pas le swapping.

Task 15: Detect TRIM/discard behavior and whether it’s causing spikes

cr0x@server:~$ systemctl status fstrim.timer | sed -n '1,12p'
● fstrim.timer - Discard unused blocks once a week
     Loaded: loaded (/lib/systemd/system/fstrim.timer; enabled; preset: enabled)
     Active: active (waiting) since Mon 2026-02-03 00:00:00 UTC; 1 day 12h ago
    Trigger: Mon 2026-02-10 00:00:00 UTC; 5 days left

Ce que ça signifie : Un TRIM hebdomadaire est planifié. C’est généralement préférable au discard continu pour la stabilité de latence.

Décision : Préférez TRIM périodique plutôt que discard toujours activé pour de nombreuses charges serveur. Si vous utilisez discard=on dans la config disque VM, confirmez que cela ne crée pas de pics de latence lors d’un fort churn.

Task 16: Identify snapshot/backup merges (a classic “why now?”)

cr0x@server:~$ zfs list -t snapshot -o name,used,creation -s creation | tail -n 5
nvme-zfs/vm-104-disk-0@vzdump-2026_02_04-000001  1.2G  Tue Feb  4 00:00 2026
nvme-zfs/vm-107-disk-0@replica-2026_02_04-001500 800M  Tue Feb  4 00:15 2026
nvme-zfs/vm-104-disk-0@replica-2026_02_04-001500 650M  Tue Feb  4 00:15 2026
nvme-zfs/vm-104-disk-0@replica-2026_02_04-003000 700M  Tue Feb  4 00:30 2026
nvme-zfs/vm-104-disk-0@replica-2026_02_04-004500 720M  Tue Feb  4 00:45 2026

Ce que ça signifie : Snapshots fréquents dus aux sauvegardes/réplications. Le churn de snapshots peut augmenter l’amplification d’écriture sur les systèmes CoW et dégrader la localité.

Décision : Réduisez la fréquence des snapshots pour les volumes à fort churn, séparez les cibles de sauvegarde, ou ajustez la rétention pour éviter des chaînes longues de snapshots anciens qui pincent des blocs.

Analyses approfondies : pourquoi NVMe peut sembler lent

1) Le débit ment ; la latence dit la vérité

La plupart des tickets « ma VM est lente » sont un utilisateur qui rapporte des interactions qui semblent collantes : SSH prend une seconde de plus, apt pause, sites web cafouillent. Ce sont des petites opérations I/O avec des chaînes de dépendances. Un seul fsync qui prend 40 ms n’apparaît pas comme un problème de bande passante, mais il peut ruiner un journal de transactions, un apt install ou un système de fichiers journalisé.

NVMe brille en IOPS élevées et en débit, mais seulement si la pile sait garder les queues pleines et compléter le travail de façon cohérente. Une charge de VM tourne souvent à faible profondeur de file avec des flushes fréquents. Si votre backend transforme ces flushes en attentes coûteuses, votre NVMe devient un périphérique très rapide qui passe son temps à demander la permission.

2) Écritures sync : ZFS et le coût d’être honnête

La posture par défaut de ZFS est : quand une application demande la durabilité, ZFS la prend au sérieux. Cela signifie que les écritures sync sont engagées sur le stockage stable avant d’accuser réception. Sur un pool sans ZIL/SLOG dédié, ces commits vont sur le(s) vdev principal(aux). Avec un seul NVMe, cela peut rester acceptable — jusqu’à ce que vous mélangez les charges, déclenchiez des écritures soutenues, ou rencontriez un comportement firmware qui rend les flushes coûteux.

Le piège est de supposer « NVMe unique = fsync instantané. » Beaucoup de NVMe grand public accélèrent les écritures via des caches volatils et des mécanismes internes. S’ils n’ont pas de protection contre la perte d’alimentation, ils doivent être prudents sur les sémantiques de flush, et ils peuvent faire des tâches de housekeeping qui provoquent des pics de latence. ZFS ne connaît pas le marketing de votre disque ; il ne connaît que les promesses du disque.

À faire : pour des charges sync-intensives, utilisez un NVMe entreprise avec protection PLP ou un SLOG séparé explicitement conçu pour des écritures sync basse latence.

À éviter : régler sync=disabled comme « correctif de performance » sauf si vous acceptez de perdre des écritures reconnues lors d’un crash. Ce n’est pas hypothétique ; cela arrive en production.

3) Modes de cache QEMU : la performance est un contrat, pas une ambiance

Dans Proxmox, le mode de cache disque change la manière dont QEMU interagit avec le cache page de l’hôte et le comportement des flushes. En bref :

  • cache=none : I/O direct (O_DIRECT) contourne le cache page de l’hôte. Souvent bon pour réduire le double-caching et rendre la latence plus prévisible.
  • cache=writeback : peut être rapide, mais dépend du cache de l’hôte. Cela peut aussi augmenter le risque si la pile sous-jacente ou le matériel ment sur la durabilité.
  • cache=writethrough/directsync : plus conservateur ; peut amplifier la latence.

Il n’y a pas de « meilleur » universel. Il n’y a que « meilleur pour vos exigences de durabilité et de performance ». Si vous exécutez des bases de données et que vous valorisez la correction, alignez le mode de cache et le backend pour que les flushes signifient ce que le guest pense qu’elles signifient.

4) virtio-scsi-single : une queue pour tous les goulots

virtio-scsi-single existe pour une raison : compatibilité et simplicité. Mais il serialise aussi l’I/O via une seule queue, qui peut devenir un point de contention CPU et lock pour les guests multi-vCPU avec I/O parallèle.

Si votre charge exécute plusieurs flux I/O indépendants — pensez à des serveurs de build, plusieurs conteneurs dans une VM, ou un serveur de fichiers occupé — une seule queue peut créer une latence artificiellement élevée même si le NVMe est plutôt inactif.

À faire : envisagez virtio-scsi-pci avec des queues adaptées et iothread=1 pour les disques qui en bénéficient.

À éviter : convertir tout en « plus de queues » sans observer. Certaines charges empirent quand vous augmentez la concurrence car la latence tail s’étend sous contention.

5) Thin provisioning : la lente agonie des métadonnées

LVM-thin est parfaitement utilisable et courant dans les installations Proxmox. Mais les thin pools ont deux pièges de performance :

  • Pression sur les métadonnées : quand les métadonnées sont tendues ou fortement mises à jour, des pics de latence apparaissent.
  • Fragmentation : avec le temps, l’allocation devient éparpillée, surtout sous churn de snapshots et écritures aléatoires.

Si vous traitez les thin pools comme de la magie, ils vous rappelleront qu’ils sont des systèmes de comptabilité avec un hobby de bloc-devices.

6) Churn de snapshots et sauvegardes : CoW n’est pas gratuit

Proxmox rend les sauvegardes et snapshots accessibles, ce qui est bien. Il facilite aussi la création d’une machine d’amplification d’écriture permanente :

  • Les snapshots fréquents pincent les anciens blocs.
  • Les écritures aléatoires doivent allouer de nouveaux blocs (CoW), augmentant la fragmentation.
  • Les processus de sauvegarde lisent des disques entiers et peuvent éjecter les caches, augmentant la latence pour les charges interactives.

Les sauvegardes sont nécessaires. Mais « toutes les 15 minutes pour tout » est une politique écrite par quelqu’un qui ne reçoit pas d’alertes la nuit.

7) Contention : le voisin bruyant, c’est souvent vous

Un NVMe unique peut gérer des IOPS impressionnants, mais les charges mixtes lecture/écriture avec flushes sync peuvent le saturer. Pire : une VM effectuant de grosses écritures séquentielles (cible de sauvegarde, agrégateur de logs) peut ruiner la latence d’une autre VM effectuant de petites écritures aléatoires sync (base de données). Individuellement, les deux sont « acceptables ». Ensemble, ils se battent.

L’isolation bat le tuning héroïque. Pools séparés. Périphériques séparés. Trafic de sauvegarde séparé. Ou au moins utilisez les limites I/O Proxmox pour faire respecter l’équité.

8) Le NVMe lui-même : cache SLC, firmware et thermiques

Les disques NVMe grand public annoncent souvent des performances en rafale aidées par un cache SLC. Sous écritures soutenues, ils s’effondrent. Vous ne le remarquez pas pendant des benchmarks de 30 secondes ; vous le remarquez à 02:00 quand vos sauvegardes et réplications durent 90 minutes.

La thermique est l’autre tueur silencieux. Les contrôleurs NVMe réduisent la vitesse pour se protéger, et votre « stockage rapide » devient « stockage bien réglé ». Cela produit le graphique opérationnel le plus agaçant : une belle scie en dents de scie de performance quand le périphérique chauffe puis refroidit.

Blague #2 : J’ai vu plus d’énigmes de performance résolues par un ventilateur que par un doctorat, ce qui est à la fois humble et bruyant.

9) Mentalité fiabilité : une idée à garder

Idée paraphrasée (avec attribution) : Gene Kim a souvent poussé le principe opérationnel selon lequel améliorer le flux requiert de réduire le travail en cours et le délai de rétroaction, pas juste d’ajouter de la puissance.

Les problèmes de performance de stockage sont fréquemment des problèmes de flux : trop de tâches d’arrière-plan concurrentes, trop de mise en file, et trop peu de visibilité sur la latence.

Trois mini-histoires d’entreprise tirées du réel

Mini-histoire 1 : L’incident causé par une fausse hypothèse (« NVMe rend le sync bon marché »)

Une entreprise SaaS de taille moyenne a migré quelques VM PostgreSQL critiques vers un nouveau cluster Proxmox. Le pitch était simple : miroirs NVMe locaux, ZFS pour les snapshots, et réplication Proxmox pour la reprise rapide. La première semaine fut calme. La seconde semaine a vu une panne au ralenti lors d’un pic de routine.

La couche applicative a commencé à timeouter. Pas partout — juste assez pour être confuse. Le CPU allait bien. Le réseau allait bien. Depuis la VM base de données, iostat montrait de vilains waits d’écriture. L’équipe a d’abord voulu blâmer le système de fichiers invité et modifier les options de montage. Cela n’a rien fait.

Sur l’hôte, c’est devenu évident : les écritures sync s’empilaient derrière d’autres écritures, et les NVMe affichaient une longue latence tail sous charge mixte soutenue. La fausse hypothèse était que NVMe rend fsync pratiquement gratuit. Ce n’est pas vrai. NVMe rend possible la vitesse — si votre périphérique et votre configuration supportent des commits durables basse latence.

La correction fut ennuyeuse : ajouter des dispositifs SLOG correctement protégés contre la perte d’alimentation, réduire la fréquence des snapshots sur les zvols de la base, et planifier la réplication en dehors des pics. L’histoire « NVMe est rapide » est devenue « la durabilité a un coût, payez-le explicitement ».

Mini-histoire 2 : L’optimisation qui s’est retournée contre eux (« activer discard partout »)

Une DSI a standardisé des templates Proxmox. Ils ont activé discard=on pour chaque disque VM et ont mis les systèmes de fichiers invités en discard continu parce que cela semblait propre sur le papier : meilleur nivellement d’usure SSD, meilleure récupération d’espace, moins de surprises. Le déploiement fut progressif, accompagné d’un sentiment de maturité.

Puis le support a commencé à recevoir des signalements de « freezes aléatoires » dans les VMs. Pas des blocages complets. Juste des pauses périodiques de plusieurs secondes. C’était pire sur des Windows terminal servers et quelques Linux avec beaucoup d’activité dans /tmp. Les utilisateurs décrivaient « le clavier s’arrête une seconde ». Les ingénieurs appelaient ça « non reproductible », ce qui veut dire « pas encore ».

Les métriques hôtes ont fini par corréler les pauses avec des rafales de discard. Certains modèles NVMe l’ont géré ; d’autres ont transformé discard en cycles de GC internes avec des pics de latence notables. Sous virtualisation, ces pics ont été amplifiés parce que plusieurs invités faisaient la même « optimisation » en même temps.

Le rollback fut chirurgical : désactiver le discard continu dans les guests, conserver un fstrim périodique, et n’activer discard=on que pour les volumes ayant vraiment besoin d’une reclamation en ligne. L’optimisation n’a pas échoué parce que discard est mauvais ; elle a échoué parce que « partout, toujours » n’est pas une stratégie de performance.

Mini-histoire 3 : La pratique ennuyeuse qui a sauvé la mise (« mesurer la latence tail et isoler les sauvegardes »)

Une équipe de services financiers utilisait Proxmox pour des outils internes et quelques services sensibles à la latence. Rien de glamoureux. Ils avaient une règle simple : les sauvegardes ne doivent pas partager le même pool que les bases de données en écriture intensive, sauf si un budget I/O mesuré et appliqué existe.

Ils ont mis en place un stockage séparé : un pool pour les disques VM et un second pour les cibles de sauvegarde. Ils ont aussi maintenu un petit tableau de bord axé sur la latence disque au 95e/99e percentile sur les hôtes pendant les heures de bureau. Pas seulement des moyennes. La latence tail. Le métrique qui correspond aux plaintes humaines.

Un mardi, un nouveau service a été déployé avec des logs bavards et une rétention agressive locale. Il écrivait constamment. Le tableau de bord de latence s’est allumé en quelques minutes, et parce que les sauvegardes étaient isolées, le rayon d’impact est resté petit. Ils ont throttlé la VM bruyante, ajusté le logging, et la vie a continué.

Pas de revue d’incident héroïque. Pas de drame « NVMe cassé ». Juste des garde-fous qui supposaient que quelqu’un, un jour, ferait quelque chose d’enthousiaste avec des écritures disque. Ils avaient raison.

Erreurs courantes : symptôme → cause → correctif

  • Symptôme : La VM semble lente, les installations de paquets pausent, les bases remontent un fsync élevé.

    Cause : Latence d’écriture sync sur ZFS sans SLOG approprié ou sur NVMe grand public sous charge mixte soutenue.

    Fix : Ajouter un SLOG PLP ou NVMe entreprise ; réduire le churn des snapshots ; isoler les écrivains bruyants ; conserver sync=standard pour la correction.

  • Symptôme : Pauses aléatoires de plusieurs secondes sur plusieurs VMs à des moments étranges.

    Cause : Rafales de discard/TRIM ou maintenance en arrière-plan (fstrim, GC du disque) provoquant des pics de latence.

    Fix : Préférer fstrim périodique plutôt que discard continu ; tester discard=on de façon sélective ; vérifier thermiques et firmware NVMe.

  • Symptôme : Forte utilisation disque sur l’hôte, mais les VMs individuelles montrent un faible débit ; tout est « juste lent ».

    Cause : Files d’attente/charges concurrentes (sauvegarde, réplication, scrub, autre VM) saturant le périphérique avec de petites écritures et des flushes.

    Fix : Déplacer les sauvegardes hors du pool ; planifier les jobs lourds ; ajouter des limites I/O ; séparer les pools selon classes de latence.

  • Symptôme : Une VM seule avec plusieurs vCPU n’atteint que des IOPS modestes ; la latence augmente quand des jobs parallèles tournent.

    Cause : virtio-scsi-single single-queue ou iothread manquant.

    Fix : Utiliser virtio-scsi-pci et activer iothread ; envisager multiqueue si supporté ; retester avec fio dans le guest.

  • Symptôme : La performance est excellente 30–60 secondes, puis s’effondre pendant de longues écritures.

    Cause : Épuisement du cache SLC NVMe et bridage en écriture soutenue.

    Fix : Choisir des disques conçus pour writes soutenus ; surprovisionner ; améliorer le refroidissement ; séparer sauvegardes/ingest.

  • Symptôme : Après activation de la compression/dedup « pour l’efficacité », la latence empire.

    Cause : Surcharge CPU et amplification ; la dedup est particulièrement pénible sans mémoire et charges adaptées.

    Fix : Utiliser la compression avec discernement (souvent oui) ; éviter la dedup pour les disques VM sauf cas prouvé ; mesurer l’impact CPU et latence.

  • Symptôme : « NVMe est rapide » mais l’hôte swape ; les VMs se bloquent sous pression mémoire.

    Cause : Sur-engagement mémoire hôte ; swapping et reclaim bloquent l’I/O et l’ordonnancement CPU.

    Fix : Ajuster la taille RAM, le ballooning et les limites ARC ZFS ; arrêter le swapping sur les hyperviseurs sauf si vous savez pourquoi vous le voulez.

  • Symptôme : Les benchmarks stockage semblent bons, mais les applications réelles sont lentes.

    Cause : Les benchmarks testent le débit séquentiel ou la profondeur de file ; votre appli est sync-intensive en faible QD.

    Fix : Benchmarquez la bonne chose : random low-QD read/write, latence fsync et percentiles tail — dans le guest et sur l’hôte.

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

Étape par étape : diagnostiquer une VM lente sans faire exploser tout le système

  1. Confirmez que le problème est cohérent. Obtenez une fenêtre temporelle et corrélez avec sauvegardes, scrubs, réplication et déploiements.
  2. Dans le guest : vérifiez iostat -x et vmstat 1. Si iowait est élevé, continuez. Si le swap est actif, corrigez la mémoire d’abord.
  3. Sur l’hôte : lancez iostat -x pour le périphérique NVMe. Cherchez un await élevé, un avgqu-sz élevé et un %util à fond.
  4. Trouvez l’écrivain : pidstat -d et corrélez aux PIDs qemu-system-x86 ou aux outils de sauvegarde.
  5. Identifiez le backend : pvesm status et qm config. ZFS ? LVM-thin ? Ceph ? Des playbooks différents s’appliquent.
  6. Validez le modèle de périphérique VM : virtio-scsi-single vs virtio-scsi-pci, iothread activé, mode de cache approprié.
  7. Vérifiez la réalité NVMe : nvme smart-log (thermiques), lspci -vv (largeur lanes), et assurez-vous qu’il ne throttlle pas.
  8. Faites un changement à la fois. Retestez l’opération utilisateur d’origine (pas seulement un benchmark synthétique).

Checklist : « faire ça, éviter ça » pour la performance de stockage Proxmox

  • Faire : surveiller les percentiles de latence disque sur les hôtes. Éviter : se fier aux graphiques de débit moyen.
  • Faire : isoler le trafic de sauvegarde. Éviter : lancer des sauvegardes lourdes sur le même pool que des bases basse-latence pendant les heures de pointe.
  • Faire : utiliser des dispositifs PLP pour accélérer le sync. Éviter : utiliser des disques grand public pour des attentes de durabilité de WAL.
  • Faire : garder des politiques de snapshot intentionnelles. Éviter : snapshots très fréquents sur des volumes à fort churn sans mesurer l’impact.
  • Faire : choisir virtio et le queueing délibérément. Éviter : conserver les défauts quand vous avez des preuves qu’ils bottleneckent.
  • Faire : traiter le discard comme un outil. Éviter : activer discard continu partout parce que ça « sonne propre ».

FAQ

1) Pourquoi ma VM est-elle lente alors que le NVMe fait des gigaoctets par seconde en benchmark ?

Parce que votre charge dépend probablement de la latence synchrone à faible profondeur de file (fsync/flush), pas du débit séquentiel. Mesurez await et les temps fsync, pas seulement les MB/s.

2) Dois-je mettre ZFS sync=disabled pour corriger la latence ?

Seulement si vous acceptez de perdre des écritures reconnues lors d’un crash. Pour les bases de données et la plupart des services état, c’est un mauvais compromis. Corrigez le chemin sync avec du matériel adapté (SLOG PLP / NVMe entreprise) ou isolez la charge.

3) cache=none est-il toujours le meilleur choix dans Proxmox ?

Non. C’est souvent un bon défaut pour la prévisibilité et éviter le double-caching, mais le « meilleur » dépend du backend et des exigences de durabilité. Traitez le mode cache comme une partie du contrat de correction.

4) Qu’y a-t-il de mal avec virtio-scsi-single ?

Rien — jusqu’à ce que vous ayez besoin de parallélisme. Il utilise une seule queue, qui peut bottlenecker des charges I/O multithread. Si vous voyez contention CPU/locks et IOPS limités, envisagez virtio-scsi-pci avec queues et iothreads.

5) Les snapshots sont-ils intrinsèquement lents ?

Les snapshots ne sont pas intrinsèquement lents, mais les snapshots fréquents sur des volumes à fort churn augmentent le coût CoW et la fragmentation. La douleur apparaît souvent lors des merges, sauvegardes et écritures aléatoires soutenues.

6) Activer discard améliore-t-il la performance ?

Ça peut améliorer le comportement en état stable et la récupération d’espace, mais cela peut aussi introduire des pics de latence. Beaucoup d’environnements font mieux avec un fstrim périodique plutôt qu’un discard continu, surtout sur de nombreuses VMs.

7) Comment savoir si le NVMe throttlle ?

Vérifiez la température via nvme smart-log et corrélez les chutes de performance avec la montée thermique. Surveillez aussi les motifs en scie des latences et du débit sous écritures soutenues.

8) Dois-je changer l’ordonnanceur I/O Linux pour NVMe ?

Parfois. none peut réduire la surcharge, tandis que mq-deadline ou kyber améliorent l’équité de latence sous contention. Choisissez selon les latences tail mesurées, pas selon une idéologie.

9) Pourquoi les sauvegardes rendent-elles les VMs interactives lentes même si les sauvegardes sont « lecture-intensive » ?

Les lectures peuvent évincer les caches et augmenter l’ordonnancement des queues périphériques, et les sauvegardes basées sur snapshots peuvent déclencher du travail métadonnée supplémentaire. Si les sauvegardes concourent pour le même pool, les charges sensibles à la latence le ressentiront.

10) Quel est le correctif le plus efficace pour « VMs lentes sur stockage rapide » ?

Isolation. Séparez les pools (ou au moins appliquez des limites I/O strictes) par classes de latence, et arrêtez de mélanger les tempêtes backup/scrub/replication avec les charges transactionnelles interactives.

Étapes pratiques suivantes

Si vous voulez que la VM cesse de paraître lente, faites ceci dans l’ordre :

  1. Mesurez la latence, pas le débit. Capturez iostat -x sur le guest et l’hôte pendant la fenêtre de plainte.
  2. Identifiez le backend. ZFS vs LVM-thin vs Ceph change ce qui est « normal » et ce à quoi ressemble un « fix ».
  3. Trouvez la contention. Les sauvegardes et le churn de snapshots sont des récidivistes. Confirmez avec pidstat -d et la corrélation temporelle.
  4. Corrigez honnêtement le chemin de durabilité. Si vous avez besoin d’écritures sync rapides, utilisez du matériel qui peut les fournir en toute sécurité (SLOG PLP / NVMe entreprise) ou acceptez la latence comme coût de la correction.
  5. Tunez le queueing VM délibérément. Si vous êtes sur virtio-scsi-single et que la charge est parallèle, basculez vers un modèle adapté et validez avec des tests réels.
  6. Arrêtez d’« optimiser » globalement. Discard, snapshots agressifs et caches trop astucieux sont d’excellentes façons de générer du jitter à l’échelle. Faites des changements selon la classe de charge.

Le gain n’est pas seulement des VMs plus rapides. C’est moins de tickets mystérieux, moins de parties de blâme nocturnes, et une pile de stockage qui se comporte comme un système — pas comme une rumeur.

← Précédent
Résolveurs DNS : mise en cache négative — le paramètre qui prolonge les pannes
Suivant →
Installation de Rocky Linux 10 : compatible RHEL sans les contraintes d’abonnement

Laisser un commentaire