Ubuntu 24.04 : disque « bloqué » sous charge — réglages de timeout qui évitent les blocages complets (cas n°90)

Cet article vous a aidé ?

Quand un disque ralentit, votre système ne doit pas se lancer dans des considérations philosophiques. Pourtant, sous forte I/O, des machines Ubuntu 24.04 peuvent sembler « bloquées » alors que le CPU est au repos et la mémoire OK — parce que le noyau attend poliment un stockage qui a cessé d’être coopératif.

Ce n’est pas juste une question de « performance ». C’est une question de vivacité. La différence entre un pic de latence et un blocage complet de service tient souvent à quelques timeouts, comportements de mise en file et chemins de récupération que vous avez configurés — ou hérités par accident.

À quoi ressemble réellement un « blocage disque » sur Ubuntu 24.04

« Blocage » est un mot vague, précisons. Dans ce cas, la machine n’est pas plantée. Elle est coincée en attente de la fin d’une I/O. Cela signifie :

  • La connexion SSH fonctionne, mais des commandes comme ls ou df se figent lorsqu’elles touchent des montages affectés.
  • La charge (load average) monte, mais l’utilisation CPU semble ennuyeuse. Ce sont des tâches prêtes qui attendent une I/O bloquée, pas une tempête de calcul.
  • Les unités systemd cessent de répondre aux stop/restart. Elles sont coincées en sommeil non interruptible (état D).
  • Les logs du noyau mentionnent des timeouts, des resets, « blocked for more than 120 seconds », ou des attentes du journal de système de fichiers.

L’objectif n’est pas que les disques ne ralentissent jamais. L’objectif est : quand les disques ralentissent ou disparaissent, que le système récupère rapidement, échoue vite les requêtes et ne se coince pas en tentant d’être trop serviable.

Une vérité opérationnelle : le noyau peut attendre plus longtemps que votre business ne le peut. Votre travail est d’aligner ces horloges.

Feuille de diagnostic rapide

Quand la production craque, ne commencez pas par éditer des sysctls. Commencez par répondre à trois questions : qu’est-ce qui est bloqué, où est-ce bloqué, et pourquoi la récupération ne se produit-elle pas.

Première étape : confirmer que c’est de l’attente I/O et identifier le périphérique

  • Vérifiez iowait et les tâches bloquées.
  • Trouvez quel(s) montage(s) et quel(s) périphérique(s) bloc sont impliqués.
  • Cherchez des messages évidents du noyau à propos de resets/timeouts.

Deuxième étape : décider si vous êtes en « pic de latence » ou en « panne de chemin/périphérique »

  • Pic de latence : l’I/O se termine éventuellement ; les files s’allongent ; les timeouts peuvent ne pas se déclencher.
  • Panne : les commandes se figent indéfiniment ; multipath peut mettre en file indéfiniment ; le pilote peut retenter pendant des minutes.

Troisième étape : vérifier quelle politique aggrave le blocage

  • Multipath : queue_if_no_path peut transformer un clignotement SAN transitoire en gel applicatif.
  • Timeouts de périphérique : les timeouts SCSI ou NVMe déterminent combien de temps le noyau retente avant d’errer ou de réinitialiser.
  • Comportement du système de fichiers : les commits de journal et les opérations metadata peuvent se sérialiser et bloquer du travail non lié.
  • Timeouts de service : systemd peut attendre trop longtemps avant de déclarer une erreur ou redémarrer.

Obtenez rapidement les faits, puis changez le bon réglage. Sous pression, les gens aiment tourner des boutons au hasard. C’est comme ça qu’on finit avec un système qui échoue plus vite qu’il ne récupère.

Faits et contexte qui changent la manière de déboguer

Voici quelques points concrets — certains historiques — qui expliquent pourquoi les problèmes de « blocage disque » se comportent ainsi :

  1. Le I/O bloc au niveau bloc Linux peut rester en sommeil non interruptible (état D), ce qui signifie que les signaux ne tuent pas le processus. C’est pourquoi kill -9 semble impuissant.
  2. La gestion d’erreurs SCSI est volontairement patiente. Elle tente de récupérer sans perte de données, ce qui est excellent — jusqu’à ce que vos applis aient besoin d’un échec rapide.
  3. Le seuil d’avertissement « blocked task » (souvent 120s) n’est pas un timeout ; c’est une alerte. Le travail peut rester bloqué bien après cet avertissement.
  4. Multipath a été conçu pour survivre aux fabrics instables. Des fonctionnalités comme « queue when no paths » visaient à préserver les écritures lors d’une perte de chemin, mais elles peuvent geler l’espace utilisateur.
  5. NCQ et files profondes (SATA/SAS) ont amélioré le débit, mais de grandes files peuvent amplifier la latence en queue sous contention. Une commande lente peut se retrouver devant beaucoup d’autres.
  6. NVMe a apporté un reporting d’erreurs et des resets de contrôleur plus rapides comparé aux anciens comportements SATA, mais la politique de reset/reconnexion reste importante, en particulier avec des quirks PCIe.
  7. Le journal ext4 existe pour garder les métadonnées cohérentes. Sous des blocages de stockage, les commits du journal peuvent bloquer des opérations apparemment sans lien, comme créer un fichier dans un autre répertoire.
  8. Les politiques de writeback caching ont été un champ de bataille pour la fiabilité pendant des décennies : les caches rapides masquent la latence jusqu’à ce qu’ils ne le fassent plus, exposant alors de gigantesques pics.
  9. La virtualisation a ajouté des couches de mise en file (couche bloc du guest, files virtio, files HBA de l’hôte, files de l’array). La latence en queue finale se cumule à travers les couches.

Réalité sèchement drôle : les disques ne « se bloquent ». Ils entrent dans une relation à long terme avec votre noyau, et votre noyau ne croit pas à l’abandon rapide.

Timeouts : le modèle à avoir en tête

Il n’y a pas un seul « timeout disque ». Il y a plusieurs minuteurs et politiques qui s’empilent, parfois de façon multiplicative :

  • Timeouts de commande au niveau périphérique (SCSI device_timeout / timeout par périphérique ; timeouts de contrôleur NVMe).
  • Récupération transport/lien (resets de lien SAS, événements de fabric FC, timeouts de session iSCSI, comportement de retransmission TCP).
  • Politique du mapper (comportement de queueing dm-multipath, fast_io_fail_tmo, dev_loss_tmo).
  • Comportement de la couche RAID (timeouts mdraid ; firmware du contrôleur ; write cache).
  • Timeouts système de fichiers / journal (pas toujours explicites, mais intervalles de commit et comportements de sync).
  • Timeouts applicatifs / de service (TimeoutStart/Stop systemd, timeouts de requêtes clients, timeouts de requêtes DB).

Quand le chemin disque est cassé, le noyau peut continuer à retenter, remapper et attendre. Cela peut être le bon choix par défaut pour l’intégrité des données. En production, vous devez décider : préférez-vous attendre ou échouer ? Pour un write de base de données, attendre peut être plus sûr. Pour un nœud API sans état, échouer vite et rescheduler peut être l’objectif.

Une citation à afficher sur chaque rotation on-call : « Hope is not a strategy. » — General Gordon R. Sullivan

L’astuce consiste à choisir des valeurs de timeout qui correspondent au temps de récupération de votre environnement. Si votre basculement SAN prend 15–30 secondes, ne configurez pas une politique qui bloque indéfiniment. Si votre firmware SSD a parfois besoin de 5 secondes pour récupérer, ne mettez pas de timeouts à 1 seconde et provoquez des resets constants.

Tâches pratiques (commandes, ce que signifie la sortie, et décisions)

Vous voulez des commandes réelles, pas des impressions. Ces tâches sont ordonnées du « sûr et rapide » vers « ça change le comportement ». Exécutez-les sur Ubuntu 24.04 ; la plupart demandent les droits root.

Tâche 1 : Confirmer un iowait élevé et pression de la file d’attente

cr0x@server:~$ mpstat -P ALL 1 5
Linux 6.8.0-xx-generic (server)  12/31/2025  _x86_64_  (16 CPU)

12:00:01 AM  CPU   %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
12:00:02 AM  all   2.10  0.00  1.20   41.30 0.00  0.20   0.00   0.00    0.00  55.00

Sens : un iowait à 40%+ suggère que les CPU sont inactifs parce qu’ils attendent le stockage, pas parce que le système est « occupé ».

Décision : Passez à l’identification du périphérique. Ne réglez pas le CPU. Ne poursuivez pas la « load average » pour l’instant.

Tâche 2 : Identifier les processus bloqués en état D

cr0x@server:~$ ps -eo pid,stat,comm,wchan:32 | awk '$2 ~ /D/ {print}'
23144 D    postgres  io_schedule
28901 D    rsync     ext4_sync_file

Sens : Ces processus sont bloqués dans des chemins d’attente I/O du noyau.

Décision : Mettez-les en correspondance avec les systèmes de fichiers / périphériques ; ne perdez pas de temps à tenter de les tuer.

Tâche 3 : Voir quel montage est lent en touchant les métadonnées

cr0x@server:~$ sudo timeout 3s stat /var/lib/postgresql || echo "stat timed out"
stat timed out

Sens : Même une opération metadata bloque. Cela indique un blocage au niveau du système de fichiers sur ce montage.

Décision : Identifiez quel périphérique bloc soutient ce montage.

Tâche 4 : Faire correspondre un montage à son périphérique bloc

cr0x@server:~$ findmnt -no SOURCE,TARGET,FSTYPE /var/lib/postgresql
/dev/mapper/mpatha /var/lib/postgresql ext4

Sens : Il s’agit d’un device dm-multipath, pas d’un simple /dev/sdX.

Décision : Vérifiez la politique multipath et la santé des chemins avant de toucher aux options ext4.

Tâche 5 : Rechercher des messages noyau de timeout/reset

cr0x@server:~$ dmesg -T | egrep -i 'tim(e|ed) out|abort|reset|blk_update_request|I/O error|blocked for more'
[Wed Dec 31 00:01:12 2025] sd 3:0:0:1: timing out command, waited 180s
[Wed Dec 31 00:01:12 2025] blk_update_request: I/O error, dev dm-2, sector 81234567 op 0x1:(WRITE)
[Wed Dec 31 00:03:14 2025] INFO: task jbd2/dm-2-8:123 blocked for more than 120 seconds.

Sens : Le noyau a attendu 180s avant de déclarer le timeout d’une commande ; le thread de journal ext4 est bloqué.

Décision : Votre budget de vivacité est consommé dans la couche SCSI/périphérique. Réglez les timeouts et/ou le comportement multipath.

Tâche 6 : Vérifier la queue par périphérique et les réglages du scheduler

cr0x@server:~$ lsblk -o NAME,TYPE,SIZE,MODEL,HCTL,STATE,SCHED,ROTA
NAME            TYPE  SIZE MODEL            HCTL       STATE SCHED    ROTA
sda             disk  1.8T ST2000NM000A      0:0:0:0    running mq-deadline    1
mpatha          mpath 2.0T                   -          running none           1

Sens : Le stockage rotatif + les choix de scheduler influencent la latence sous charge, mais ils ne résoudront pas une perte de chemin. Le mapper montre none car la couche dm délègue le scheduling.

Décision : Gardez cela en tête plus tard ; stabilisez d’abord le comportement de défaillance avec des timeouts.

Tâche 7 : Mesurer la latence et la profondeur de file

cr0x@server:~$ iostat -x 1 5
Device            r/s   w/s   rkB/s   wkB/s  await  aqu-sz  %util
sda              5.0  85.0    80.0  2400.0  180.0   32.0   99.8
dm-2             0.0  90.0     0.0  2400.0  185.0   31.5   99.9

Sens : await ~180ms avec une file d’environ 32 à quasi 100% d’utilisation. En cas de panne, vous pouvez voir await grimper à des secondes et ne jamais redescendre.

Décision : Si c’est un pic, améliorez le débit/la mise en file. Si c’est un blocage, focalisez-vous sur le basculement et les timeouts.

Tâche 8 : Confirmer l’état multipath et si la mise en file est active

cr0x@server:~$ sudo multipath -ll
mpatha (3600508b400105e210000900000490000) dm-2 HP,MSA2040
size=2.0T features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=1 status=active
| `- 3:0:0:1 sdb 8:16 active ready running
`-+- policy='service-time 0' prio=1 status=enabled
  `- 4:0:0:1 sdc 8:32 failed faulty running

Sens : queue_if_no_path est activé ; un chemin est en échec. Si tous les chemins tombent, l’I/O sera mise en file au lieu d’échouer.

Décision : Décidez si votre workload préfère des écritures en file (risque de blocage applicatif) ou un échec rapide (risque d’erreurs d’écriture mais meilleure vivacité de service).

Tâche 9 : Inspecter les timeouts dm-multipath (fast fail et perte de périphérique)

cr0x@server:~$ sudo cat /sys/block/dm-2/dm/uuid
mpath-3600508b400105e210000900000490000

cr0x@server:~$ sudo cat /sys/block/dm-2/queue/io_timeout
0

Sens : io_timeout à 0 signifie typiquement « utiliser la valeur par défaut / pas de timeout explicite ici », ce qui équivaut souvent à « attendre longtemps ailleurs ».

Décision : Préférez des politiques explicites : définissez des valeurs fast fail pour multipath et assurez-vous que les timeouts SCSI ne sont pas absurdes pour vos SLA.

Tâche 10 : Vérifier le timeout du périphérique SCSI en vigueur

cr0x@server:~$ sudo cat /sys/block/sdb/device/timeout
180

Sens : 180 secondes par commande, c’est une éternité dans le monde des requêtes. Une seule commande coincée peut bloquer la file.

Décision : Pour beaucoup d’environnements, 30–60 secondes est un plafond raisonnable, mais seulement si votre stockage peut réellement se récupérer dans cette fenêtre.

Tâche 11 : Identifier le transport (SAS/iSCSI/NVMe) pour choisir les bons réglages

cr0x@server:~$ lsblk -S -o NAME,TRAN,TYPE,MODEL,SERIAL
NAME TRAN TYPE MODEL            SERIAL
sdb  sas  disk HP LOGICAL VOLUME 600508b4...
sdc  sas  disk HP LOGICAL VOLUME 600508b4...

Sens : C’est du stockage SAS, probablement via un contrôleur RAID ou une baie SAN, pas du NVMe.

Décision : Le réglage des timeouts SCSI et les politiques multipath comptent plus que les options de reset NVMe ici.

Tâche 12 : Vérifier la douleur au niveau système de fichiers (erreurs ext4, journal, remounts)

cr0x@server:~$ sudo dmesg -T | egrep -i 'ext4|jbd2|remount|buffer i/o error' | tail -n 20
[Wed Dec 31 00:03:14 2025] INFO: task jbd2/dm-2-8:123 blocked for more than 120 seconds.
[Wed Dec 31 00:03:18 2025] EXT4-fs (dm-2): Delayed block allocation failed for inode 262145 at logical offset 0 with max blocks 16 with error 5

Sens : ext4 voit des erreurs I/O et le thread de journal est bloqué. Les opérations du système de fichiers vont basculer en chaîne.

Décision : Corrigez d’abord la récupération I/O sous-jacente. Le tuning du système de fichiers ne surpassera pas des blocs manquants.

Tâche 13 : Voir les timeouts systemd et le comportement stop-job (vivacité des services)

cr0x@server:~$ systemctl show postgresql --property=TimeoutStartUSec,TimeoutStopUSec,KillMode
TimeoutStartUSec=1min 30s
TimeoutStopUSec=1min 30s
KillMode=control-group

Sens : systemd attendra 90 secondes avant de déclarer un échec de start/stop. Mais si le processus est en état D, il peut ignorer les signaux de terminaison.

Décision : Vous ne pouvez pas « systemdiser » un problème d’attente I/O noyau. Mais vous pouvez préserver les services frontaux en isolant les unités dépendantes du stockage.

Tâche 14 : Confirmer si le noyau inonde d’avertissements de tâches bloquées

cr0x@server:~$ sudo sysctl kernel.hung_task_timeout_secs
kernel.hung_task_timeout_secs = 120

Sens : C’est du contrôle du bruit diagnostic, pas une correction. Le changer modifie quand vous recevez des avertissements, pas quand l’I/O revient.

Décision : Ne « réparez » pas l’incident en muant l’alarme. Servez-vous en pour corréler dans le temps les blocages et les problèmes de chemin.

Tâche 15 : Capturer une trace rapide des stacks des tâches bloquées

cr0x@server:~$ echo w | sudo tee /proc/sysrq-trigger
w

Sens : Le noyau va dumper les stacks des tâches bloquées dans dmesg/journal. C’est moche, mais cela indique quelle couche attend (dm, scsi, système de fichiers, etc.).

Décision : Utilisez ceci pour prouver si vous êtes coincé en queue multipath, EH SCSI, ou attentes du journal du système de fichiers.

Tâche 16 : Surveiller les attributs udev pour une configuration persistante des timeouts

cr0x@server:~$ udevadm info --query=all --name=/dev/sdb | egrep 'ID_MODEL=|ID_SERIAL=|ID_WWN=|DEVPATH='
E: DEVPATH=/devices/pci0000:00/0000:00:1f.2/host3/target3:0:0/3:0:0:1/block/sdb
E: ID_MODEL=LOGICAL_VOLUME
E: ID_SERIAL=600508b400105e210000900000490000
E: ID_WWN=0x600508b400105e210000900000490000

Sens : Vous pouvez matcher des périphériques précis (WWN) pour appliquer des règles udev qui définissent des timeouts de façon cohérente au redémarrage.

Décision : Si vous ajustez des timeouts, rendez-les persistants via udev ou la config multipath — pas des écritures sysfs manuelles temporaires.

Oui, cela fait beaucoup de commandes. Mais un on-call n’est pas le moment de « juste tenter un reboot ». Les reboots sont corrects ; le mystère coûte cher.

Réglages de timeout qui évitent les blocages complets

Nous allons voir les réglages qui déterminent si un disque lent cause « quelques erreurs » ou « le nœud entier cesse de répondre ». Le bon choix dépend si le stockage est local, RAID, SAN multipath, iSCSI, ou NVMe. Mais la forme du problème est la même : limitez combien de temps vous attendez avant d’échouer, et assurez-vous que le basculement se produit dans cette limite.

1) Timeout de commande SCSI : /sys/block/sdX/device/timeout

Pour les périphériques SCSI (ce qui inclut la plupart des SAS, FC, iSCSI et LUN SAN), chaque périphérique bloc expose un timeout en secondes.

cr0x@server:~$ sudo cat /sys/block/sdb/device/timeout
180

Ce que ça fait : durée pendant laquelle le noyau attend une commande avant de la déclarer timeout et d’entrer en error handling (EH). L’EH peut inclure des re-tentatives, des resets et la récupération du bus.

Pourquoi ça cause des blocages : si vous laissez une seule commande traîner 180 secondes, tout ce qui est derrière peut s’accumuler. Certains périphériques/chemins sérialisent certaines commandes ; on obtient un head-of-line blocking.

Que faire : choisissez une valeur plus longue que les jitter transitoires mais plus courte que « on a perdu la raison ». Pour beaucoup de SAN d’entreprise, 30–60 secondes est un plafond courant. Pour des SATA consumer instables ou des disques SMR soumis à forte écriture, vous pouvez avoir besoin de plus — mais c’est un signe que le disque est mal choisi.

cr0x@server:~$ echo 60 | sudo tee /sys/block/sdb/device/timeout
60

Décision opérationnelle : si réduire ceci provoque des erreurs en charge normale, votre stockage ne répond pas aux attentes. Ne « réparez » pas ça en augmentant les timeouts ; réparez le chemin de stockage ou la charge.

2) Rendre le tuning persistant avec des règles udev

Les écritures sysfs disparaissent au redémarrage ou lors d’un reprobe. Utilisez des règles udev pour définir les timeouts en fonction du WWN/serial/model.

cr0x@server:~$ sudo tee /etc/udev/rules.d/60-scsi-timeout.rules >/dev/null <<'EOF'
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd[a-z]*", ENV{ID_WWN}=="0x600508b400105e210000900000490000", ATTR{device/timeout}="60"
EOF
cr0x@server:~$ sudo udevadm control --reload-rules
cr0x@server:~$ sudo udevadm trigger --subsystem-match=block --action=change

Sens : les futurs add/change appliqueront le timeout automatiquement.

Décision : ne faites cela qu’après avoir prouvé que le nouveau timeout ne casse pas le comportement de basculement légitime.

3) dm-multipath : ne plus mettre en file indéfiniment quand les chemins sont partis

Multipath est l’accélérateur classique du « blocage disque sous charge ». Si tous les chemins échouent et que vous mettez en file l’I/O, les applications se bloquent. Elles n’échouent pas, elles ne retentent pas intelligemment, elles restent figées. Cela peut être acceptable pour certaines stacks ; c’est du poison pour des services sans état.

Concept clé : la mise en file masque les défaillances. Une défaillance masquée devient un blocage au niveau du nœud.

Regardez les fonctionnalités actuelles :

cr0x@server:~$ sudo multipath -ll | sed -n '1,4p'
mpatha (3600508b400105e210000900000490000) dm-2 HP,MSA2040
size=2.0T features='1 queue_if_no_path' hwhandler='0' wp=rw

Ce qu’il faut changer : Dans beaucoup d’environnements de production, vous voulez un échec rapide quand tous les chemins sont down, plus une fenêtre de retry bornée.

  • Désactiver la mise en file indéfinie (éviter queue_if_no_path sauf justification claire).
  • Utiliser fast_io_fail_tmo pour faire échouer rapidement l’I/O quand les chemins sont down.
  • Utiliser dev_loss_tmo pour décider combien de temps tenter de récupérer un chemin avant d’abandonner.

Exemple de snippet de configuration multipath (conceptuel ; ajustez pour votre environnement) :

cr0x@server:~$ sudo tee /etc/multipath.conf >/dev/null <<'EOF'
defaults {
    find_multipaths yes
    user_friendly_names yes
    flush_on_last_del yes
}

devices {
    device {
        vendor "HP"
        product "MSA"
        no_path_retry 12
        fast_io_fail_tmo 5
        dev_loss_tmo 30
        features "0"
    }
}
EOF
cr0x@server:~$ sudo systemctl restart multipathd

Sens : avec fast_io_fail_tmo 5, l’I/O peut échouer rapidement quand il n’y a pas de chemins (après 5 secondes). Avec dev_loss_tmo 30, les chemins sont considérés perdus après 30 secondes.

Décision : Si votre basculement de fabric prend 20–25 secondes, dev_loss_tmo 30 peut convenir. S’il prend 2 minutes, vous êtes soit mal configuré soit en situation dangereuse, et les timeouts doivent refléter la réalité.

Deuxième petite plaisanterie : la mise en file de multipath, c’est mettre les plaintes clients dans un tiroir « plus tard ». À la fin, il n’y a plus de tiroirs.

4) Spécificités iSCSI : récupération de session vs vivacité applicative

Si vos LUNs arrivent via iSCSI, vous avez des timeouts supplémentaires : retransmissions TCP, remplacement de session iSCSI, et multipath. iSCSI peut être solide, mais seulement si vous choisissez une position opérationnelle : échec rapide ou « tenir les écritures jusqu’à guérison ».

Vérifiez le statut de session :

cr0x@server:~$ sudo iscsiadm -m session
tcp: [1] 10.10.10.20:3260,1 iqn.2001-04.com.example:storage.lun1 (non-flash)

Sens : vous avez une session iSCSI active. Si les blocages de stockage se corrèlent avec des pertes/reconexions de session, réglez iSCSI et multipath ensemble.

Décision : Ne configurez pas multipath pour échouer en 5 secondes si iSCSI met 30 secondes à se rétablir et que vous voulez réellement tenir la charge.

5) NVMe : les resets de contrôleur sont rapides, mais pas magiques

Sur NVMe local, les blocages sont généralement différents : hiccups firmware, événements AER PCIe, thermal throttling, ou quirks d’alimentation. Vous n’avez pas de timeouts SCSI ; vous avez le comportement du contrôleur NVMe et la logique de reset du pilote.

Vérifiez les erreurs et resets NVMe :

cr0x@server:~$ sudo dmesg -T | egrep -i 'nvme|AER|reset|timeout' | tail -n 20
[Wed Dec 31 00:02:01 2025] nvme nvme0: I/O 123 QID 6 timeout, aborting
[Wed Dec 31 00:02:02 2025] nvme nvme0: reset controller

Sens : le pilote abat et réinitialise activement. C’est généralement mieux que d’attendre 180 secondes, mais les resets peuvent quand même bloquer le système de fichiers s’ils sont fréquents.

Décision : Si les resets sont fréquents, traitez d’abord comme un problème matériel/firmware. Le réglage des timeouts n’est pas un substitut à un périphérique stable.

6) Système de fichiers et options de montage : ne confondez pas symptômes et causes

Sous de vrais blocages de périphérique, les options système de fichiers sont secondaires. Pourtant, certains choix affectent la rapidité avec laquelle les applications ressentent la douleur :

  • intervalle de commit ext4 influence la fréquence à laquelle les metadata sont forcées sur disque. Un commit bas augmente la pression de sync ; un commit élevé augmente la fenêtre de récupération et les pics de latence.
  • barrières / write cache sont généralement bien gérés par les piles modernes, mais un cache mal reporté ou des flushs désactivés peuvent transformer des blocages en corruption.
  • noatime réduit les écritures metadata ; cela ne résoudra pas un blocage, mais peut diminuer la pression de fond.

Opinion : ne « montez » pas votre sortie d’une panne de chemin. Réparez le chemin. Puis optimisez.

7) Timeouts au niveau service : contenir le rayon d’action

Vous ne pouvez pas toujours empêcher le stockage de disparaître, surtout pour du stockage réseau. Vous pouvez l’empêcher de prendre en otage le nœud entier en concevant pour la défaillance partielle :

  • Gardez les services critiques hors des montages douteux (oui, même si ce ne sont « que des logs »).
  • Utilisez systemd TimeoutStopSec et les politiques Restart correctement, mais rappelez-vous que les processus en état D ne peuvent pas être tués proprement.
  • Privilégiez les timeouts de requête au niveau applicatif. Si un appel DB bloque indéfiniment, tout votre threadpool devient une vitrine muséale.

Trois mini-récits d’entreprise venus du terrain

1) L’incident causé par une mauvaise hypothèse : « Le SAN basculera instantanément »

Une entreprise de taille moyenne a migré des services stateful sur un nouveau cluster SAN. L’équipe stockage promettait des chemins redondants et un « failover automatique ». L’équipe plateforme a entendu « instantané ». C’était le mauvais mot à entendre.

Les nœuds Linux étaient configurés avec dm-multipath et, parce que quelqu’un avait lu un blog de bonnes pratiques d’une époque où la perte d’écriture était le fléau, les devices avaient queue_if_no_path. L’hypothèse était : si un chemin tombe, multipath reroutera et l’appli ne remarquera rien. Ils pensaient comme des ingénieurs stockage. L’application a agi comme une application : elle s’est bloquée.

Un switch top-of-rack a redémarré pendant une fenêtre de maintenance qui a duré plus longtemps que prévu. Les deux chemins actifs ont disparu brièvement — pas assez longtemps pour déclencher la panique côté SAN, mais assez pour que les nœuds Linux mettent une montagne d’écritures en file. Les processus DB sont passés en état D. La couche API, attendant des réponses DB, a rempli ses propres files. Les load balancers voyaient un « TCP sain », mais les requêtes expiraient côté client. Ça ressemblait à une panne applicative. C’était une panne de vivacité stockage.

La correction fut ennuyeuse et politiquement délicate : s’accorder sur un objectif de temps de récupération pour la perte de chemin stockage, puis configurer multipath pour faire échouer l’I/O dans cette fenêtre au lieu de mettre en file indéfiniment. Ils ont aussi ajouté des timeouts en amont pour que les requêtes utilisateurs n’attendent pas un noyau coincé indéfiniment. Le reboot du switch suivant a provoqué des erreurs, pas un blocage total — et le système a récupéré plus vite parce que la défaillance était visible et bornée.

2) L’optimisation qui a mal tourné : « Augmenter la profondeur de file pour booster le débit »

Une équipe analytics avait un batch nocturne qui martelait un ensemble RAID. Une optimisation de performance a augmenté la profondeur de file et permis plus d’I/O en cours. Les chiffres de débit en bench ont monté. L’équipe a fait la fête et est allée déjeuner. Classique.

Sous la charge réelle, les files plus profondes ont amplifié la latence tail. Quand la baie a lancé sa maintenance interne (GC, checks de parité, ou quel que soit le nom de sa crise de la mi-vie firmware), des opérations I/O individuelles sont devenues lentes. Avec une file profonde, les opérations lentes se sont accumulées. Quand le système s’en est rendu compte, des centaines de requêtes attendaient, et des processus non liés ont commencé à bloquer sur des opérations metadata. La machine n’était pas « lente ». Elle était intermittemment non réactive.

Ils ont essayé de « corriger » en augmentant les timeouts SCSI pour que le noyau n’erre plus. Cela a réduit les erreurs visibles mais augmenté la durée des blocages. Le batch a duré plus longtemps, les dashboards métiers ont pris du retard, et la rotation on-call a développé des opinions sur l’analytics.

La récupération fut contre-intuitive : réduire la profondeur de file, accepter un débit maximal un peu inférieur, et obtenir une latence prévisible. Ils ont aussi planifié la maintenance de la baie hors des fenêtres de batch. Le système a cessé de faire le « bon 50 minutes, mort 5 » — la pire des théâtres de fiabilité.

3) La pratique ennuyeuse mais correcte qui a sauvé la mise : « Rendre les timeouts explicites et tester le basculement »

Une société financière exploitait des nœuds Ubuntu avec LUN multipath pour un petit cluster critique. Rien de glamour — juste une I/O régulière, des SLA stricts, et une culture de méfiance envers les héroïques.

Ils avaient une pratique simple : les timeouts étaient de la configuration, pas du folklore. Pour chaque classe de stockage, ils documentaient les temps de basculement attendus et définissaient fast_io_fail_tmo, dev_loss_tmo, et SCSI device/timeout en conséquence. Ils faisaient aussi un exercice trimestriel : retirer un chemin, retirer brièvement tous les chemins, et vérifier que les services échouent vite ou tiennent — selon le contrat du service.

Un jour, un problème de fabric en amont a causé des drops de chemin intermittents. Sur des nœuds sans cette discipline, cela aurait été un désastre de mise en file silencieux. Ici, la couche multipath a échoué l’I/O assez vite pour que la logique de retry de l’application entre en jeu. Les erreurs ont piqué, mais le cluster est resté vivant. Les opérateurs avaient quelque chose à surveiller et une fenêtre pour rerouter le trafic.

Le postmortem fut délicieusement banal. Pas de mystère. Pas de « kernel hung ». Juste un mode d’échec connu qui est resté dans des limites connues. C’est ce que vous voulez : de l’ennui avec preuves.

Erreurs courantes (symptômes → cause → correction)

1) Symptomatique : SSH fonctionne, mais ls dans un répertoire se fige

Cause racine : le répertoire est sur un système de fichiers dont le périphérique bloc sous-jacent est bloqué ; les lectures de metadata attendent la fin d’une I/O.

Correction : identifiez le montage avec findmnt, inspectez les logs noyau et les timeouts périphérique. Si multipath, vérifiez la mise en file et la perte de chemins. Si disque local, cherchez des resets de contrôleur et des erreurs hardware.

2) Symptomatique : load average énorme, CPU majoritairement inactif

Cause racine : beaucoup de tâches sont bloquées en attente I/O (état D), comptées dans la load average.

Correction : utilisez ps avec wchan, iostat -x, et sysrq w pour dump les stacks. Visez la couche stockage, pas l’ordonnancement CPU.

3) Symptomatique : systemd ne peut pas arrêter un service ; le stop job reste bloqué

Cause racine : les processus sont en sommeil non interruptible ; les signaux ne les terminent pas tant que le noyau attend la fin d’une I/O.

Correction : corrigez le chemin I/O. Pour contenir, envisagez d’isoler le montage, de basculer, ou de redémarrer le nœud si la récupération est impossible. Ne perdez pas une heure à tuner les modes de kill systemd.

4) Symptomatique : pas d’erreurs, juste de longs blocages pendant les événements SAN

Cause racine : multipath met en file l’I/O lorsque les chemins disparaissent (queue_if_no_path), masquant les échecs aux applis.

Correction : désactivez la mise en file indéfinie et définissez fast_io_fail_tmo/dev_loss_tmo sur des valeurs bornées alignées avec le basculement du fabric.

5) Symptomatique : « EXT4-fs error » intermittent suivi d’un remount en lecture seule

Cause racine : le périphérique sous-jacent renvoie des erreurs I/O ou timeoute ; le système de fichiers se protège en remontant en lecture seule.

Correction : considérez le stockage comme défectueux. Vérifiez câblage, logs HBA, santé de l’array, SMART/NVMe. Ne « corrigez » pas avec des options de montage.

6) Symptomatique : avoir ajusté les timeouts « répare » les blocages mais vous voyez maintenant des erreurs I/O aléatoires

Cause racine : vous avez réduit les timeouts en dessous du temps dont votre stockage a besoin pour se récupérer ; maintenant les opérations lentes sont traitées comme des échecs.

Correction : mesurez réellement le temps de basculement/récupération, puis fixez les timeouts légèrement au-dessus de ça. Si la récupération est trop lente, réparez le chemin stockage plutôt que de masquer le problème.

7) Symptomatique : tout se bloque pendant la rotation des logs ou les backups

Cause racine : pression metadata synchrone (fsync storms), ou saturation d’un périphérique unique par des écritures ; la contention du journal bloque des opérations non liées.

Correction : limitez le débit des backups, déplacez les logs hors du volume critique, utilisez ionice, réduisez la concurrence, et vérifiez que le périphérique ne rencontre pas de GC interne ou des chutes d’écriture SMR.

8) Symptomatique : machine virtuelle bloquée, l’hôte semble OK

Cause racine : mise en file au niveau hyperviseur ou backend stockage ; le guest voit une I/O bloquée mais les métriques hôtes peuvent la masquer.

Correction : mesurez à chaque couche : iostat du guest, stats bloc de l’hôte, latence de l’array. Alignez les timeouts de bout en bout ; ne laissez pas le guest attendre plus longtemps que ce que l’hôte peut réellement récupérer.

Listes de contrôle / plan pas à pas

Étapes pas à pas : stabiliser un nœud qui « se bloque » sous charge disque

  1. Confirmer que c’est le stockage : vérifiez mpstat pour iowait et ps pour les tâches en état D.
  2. Cartographier la douleur : utilisez findmnt pour mapper les répertoires affectés aux périphériques.
  3. Lire l’histoire du noyau : dmesg pour timeouts, resets, échecs de chemins et messages système de fichiers.
  4. Décider de la classe : disque local vs SAN multipath vs iSCSI vs NVMe. N’appliquez pas des conseils SAN à NVMe, ou l’inverse.
  5. Mesurer latence et files : iostat -x pour voir si vous êtes saturé ou en échec.
  6. Vérifier la politique multipath : cherchez queue_if_no_path et l’état des chemins ; confirmez le timing d’attente attendu.
  7. Définir un comportement d’échec borné : ajustez multipath fast_io_fail_tmo/dev_loss_tmo et les timeouts SCSI en fonction du temps de récupération mesuré.
  8. Rendre persistant : règles udev pour timeout SCSI ; /etc/multipath.conf pour la politique dm.
  9. Contenir le rayon d’action : assurez-vous que les services critiques ont des timeouts de requête sensés ; déplacez les écritures non critiques (logs, temp) hors du volume critique si possible.
  10. Tester : simulez une perte de chemin en fenêtre de maintenance. Si vous n’avez pas testé le basculement, vous gérez une théorie.

Checklist : Valeurs à choisir (orientation, pas dogme)

  • Mesurez d’abord : combien de temps prend réellement un basculement de chemin chez vous ? Utilisez cela comme base.
  • SCSI device/timeout : souvent 30–60s pour des LUN SAN dans des fabrics stables ; plus long si votre array en a besoin (mais demandez pourquoi).
  • Multipath fast_io_fail_tmo : 5–15s si vous préférez l’erreur rapide ; plus long si vous voulez tenir la charge.
  • Multipath dev_loss_tmo : 30–120s selon les attentes de récupération de chemin.
  • Évitez la mise en file indéfinie sauf si votre pile applicative est explicitement conçue pour la tolérer.

Checklist : Ce qu’il faut éviter

  • Ne « résolvez » pas des blocages en augmentant aveuglément les timeouts. Vous risquez seulement d’augmenter la durée des incidents.
  • Ne désactivez pas des mécanismes de sécurité (flushes/barriers) pour améliorer des benchs.
  • Ne supposez pas que le basculement stockage est instantané. Il l’est rarement et souvent pas de façon consistante.
  • N’ignorez pas les processus en état D. Ils sont le noyau qui brandit un drapeau rouge, pas un bug applicatif.

FAQ

1) Pourquoi kill -9 ne termine-t-il pas un processus bloqué ?

Parce qu’il est en sommeil non interruptible (état D) en attente d’une I/O kernel. Le noyau ne le replanifie pas pour traiter le signal tant que l’I/O ne revient pas ou ne fait pas d’erreur.

2) kernel.hung_task_timeout_secs est-il un vrai timeout qui règle les blocages ?

Non. Il contrôle quand le noyau vous avertit des tâches bloquées. Utile pour la corrélation, pas pour la remédiation.

3) Dois-je désactiver queue_if_no_path dans multipath ?

Dans beaucoup d’installations de production : oui, sauf si vous avez une raison documentée de mettre en file indéfiniment (et un plan pour ce que fait l’application pendant le blocage). Préférez un échec borné avec des fenêtres de retry explicites.

4) Quelle est une valeur raisonnable de timeout SCSI ?

Raisonnable = « légèrement au-dessus du temps de récupération de stockage prouvé ». En pratique, beaucoup d’environnements SAN se positionnent entre 30–60s ; certains exigent plus. Si vous avez besoin de 180s, interrogez le scénario qui le justifie et si vos services peuvent l’accepter.

5) Si je baisse les timeouts, vais-je perdre des données ?

Des timeouts plus bas convertissent de longues attentes en erreurs I/O. Le risque pour les données dépend de l’application et du système de fichiers. Les bases de données préfèrent généralement des erreurs explicites plutôt que des blocages indéfinis, mais vous devez garantir que votre stack gère correctement les échecs d’écriture.

6) Mon système ne « se bloque » que pendant les sauvegardes. Est-ce un problème de timeout ?

Souvent c’est de la saturation et de la mise en file plutôt qu’une panne de chemin. Vérifiez iostat -x pour 100% util et un await élevé. Réduisez la concurrence des backups, appliquez ionice, ou déplacez les backups sur un chemin moins critique.

7) Comment savoir si c’est le disque, le contrôleur ou le SAN ?

Commencez par dmesg. Les resets du contrôleur, erreurs de lien et échecs de chemin laissent des empreintes. Corrélez ensuite avec multipath -ll (chemins), timeouts périphérique, et métriques de latence (iostat). Si le mapper a tous les chemins down et met en file, ce n’est pas la faute d’ext4.

8) Changer l’ordonnanceur I/O règle-t-il les blocages ?

Les schedulers peuvent améliorer l’équité et la latence sous charge, surtout sur du média rotatif. Ils ne résoudront pas un chemin manquant ou un périphérique qui cesse de répondre. Considérez le tuning du scheduler comme une phase deux.

9) Dois-je redémarrer un nœud qui a beaucoup de tâches en état D ?

Si la récupération du stockage ne se produit pas et que le nœud est effectivement bloqué, oui — un reboot peut être la façon la plus rapide de restaurer le service. Mais vous devez toujours corriger le comportement de timeout/basculement sous-jacent sinon le problème reviendra.

10) Les timeouts systemd peuvent-ils me protéger des blocages disque ?

Ils protègent des services qui se bloquent en espace utilisateur. Ils ne vous protègent pas de manière fiable contre l’attente I/O noyau. Utilisez-les pour l’hygiène, pas comme stratégie de fiabilité stockage.

Étapes à réaliser cette semaine

Si des machines Ubuntu 24.04 « se bloquent » sous charge disque, le noyau fait généralement exactement ce que vous lui avez dit : attendre. Votre travail est de définir explicitement des attentes — combien de temps attendre avant que la récupération ou l’échec ne se déclenche.

  1. Exécutez la feuille de diagnostic rapide sur un nœud affecté et capturez dmesg, iostat -x, multipath -ll, et un dump sysrq des tâches bloquées.
  2. Choisissez un budget de vivacité (en secondes, pas en minutes) pour la perte de chemin stockage et alignez les timeouts SCSI et les réglages de multipath sur ce budget.
  3. Rendez ces réglages persistants avec des règles udev et /etc/multipath.conf.
  4. Testez la défaillance : retirez un chemin, puis retirez brièvement tous les chemins dans une fenêtre contrôlée. Vérifiez que le comportement correspond à ce que vos services peuvent tolérer.
  5. Ce n’est qu’après que la vivacité est stable que vous optimisez la performance : profondeur de file, ordonnancement, et façonnage de la charge.

L’état final souhaité n’est pas « pas d’erreurs ». C’est « les erreurs arrivent rapidement, de façon prévisible et récupérable », sans transformer votre nœud en une application de méditation très chère.

← Précédent
ZFS canmount : le réglage qui évite les surprises au démarrage
Suivant →
Taux de cache ZFS : quand ils comptent et quand ils ne comptent pas

Laisser un commentaire