MySQL vs MariaDB sur NVMe vs SSD SATA : pourquoi votre base reste lente (et comment le prouver)

Cet article vous a aidé ?

Vous avez acheté du NVMe. Vous avez migré le répertoire de données. Vous avez posté le message « on est moderne maintenant » dans le canal d’équipe.
Et l’application se bloque toujours à 9h05 comme si elle tournait sur un disque d’ordinateur portable de 2007.

Voici la vérité inconfortable : les mises à niveau de stockage ne résolvent pas les problèmes de performance des bases de données à moins que vous ne compreniez
quel type d’E/S vous réalisez réellement.
« NVMe c’est rapide » n’est pas un diagnostic. C’est un bon de commande.

Ce qui est vraiment lent : latence, fsync, CPU, verrous, ou la requête

Quand quelqu’un dit « la base est lente », il veut généralement dire « l’utilisateur attend ».
L’attente peut être causée par le disque, bien sûr. Mais c’est tout autant souvent :

  • CPU (mauvais plan, index manquant, ou tout simplement trop de requêtes concurrentes)
  • Verrous/transactions (verrous de ligne, gap locks, verrous de métadonnées, ou transactions longues)
  • Latence du chemin de commit (fsync, vidage du redo log, comportement de doublewrite)
  • Amplification de lecture (lectures aléatoires parce que votre jeu de travail ne tient pas en mémoire)
  • Amplification d’écriture (petites écritures déclenchant un gros travail en arrière-plan)
  • Réseau et problèmes DNS (oui, ça arrive encore)

NVMe peut fournir un débit incroyable. Mais les bases n’achètent pas du débit ; elles achètent de la latence prévisible.
Un seul pic de fsync au 99,9e percentile peut ruiner vos graphiques de latence p95 pour toute la matinée.

Ma règle opérationnelle : si vous n’avez pas mesuré où le temps passe, vous ne faites pas de dépannage ; vous racontez une histoire.

Une citation à garder en tête pendant que vous mesurez : « L’espoir n’est pas une stratégie. » — Général Gordon R. Sullivan.

MySQL vs MariaDB : où le comportement diverge en conditions réelles

Ce sont des cousins, pas des jumeaux

Pour la plupart des équipes applicatives, MySQL et MariaDB « se sentent » identiques jusqu’au moment où vous êtes appelé à 02:00 et devez interpréter
un dump de threads, un retard de réplication ou une régression de performance après une mise à jour mineure.
Sur le stockage, tous deux reposent fortement sur la même physique : caches de pages, writeback, comportement de fsync et la forme de votre charge.
Mais leurs valeurs par défaut, fonctionnalités et comportements limites peuvent suffire à déplacer votre goulot d’étranglement.

Comportement de commit et de vidage : le truc ennuyeux qui vous ralentit

Le chemin de commit est l’endroit où NVMe attire le plus d’attention : écritures et vidages de logs.
Le piège est que le comportement de flush du système est une négociation à trois volets entre :
paramètres InnoDB, votre système de fichiers + options de montage, et le firmware/contrôleur du disque.

  • innodb_flush_log_at_trx_commit décide quand le redo est flushé au commit (durabilité vs latence).
  • sync_binlog influence la fréquence des fsync sur le binlog (sécurité de réplication vs latence d’écriture).
  • innodb_flush_method (souvent O_DIRECT) affecte le double caching et les schémas d’écriture.
  • Taille du redo log et pression des checkpoints peuvent transformer un bon dispositif en générateur de jitter.

Différences d’instrumentation de performance que vous remarquerez

MySQL moderne a une histoire Performance Schema solide et un gros écosystème autour. MariaDB dispose aussi d’une bonne instrumentation,
mais vous trouverez des différences dans les noms de tables, compteurs, et les types de waits exposés.
Ne choisissez pas une base parce qu’un blog vous a dit qu’elle est « plus rapide ». Choisissez en fonction de :
clarté opérationnelle, comportement de réplication acceptable, et capacité de votre équipe à la déboguer sous pression.

Conseil d’opinion : si vous ne pouvez pas répondre à « quel est le principal événement d’attente au pic » en 60 secondes, vous naviguez à l’aveugle quelle que soit la marque.

NVMe vs SSD SATA : les éléments importants pour les bases

NVMe n’est pas juste un « SSD plus rapide »

Les performances des SSD SATA étaient façonnées par l’interface AHCI : profondeur de file limitée, overhead plus élevé, et un design qui avait du sens quand
le stockage faisait semblant d’être un disque rotatif. NVMe est un autre modèle : beaucoup de files parallèles, overhead réduit, et beaucoup plus
de IOPS potentiels.

Si votre charge est mono-thread, ou dominée par la latence fsync, ou bloquée par des verrous de ligne,
NVMe ne semblera pas magique. Ce sera comme avoir changé le moteur de votre voiture en tirant une remorque avec le frein à main serré.

Les bases se soucient des détails moches

  • Distribution de la latence (p99 compte plus que « jusqu’à 3.5GB/s »)
  • Comportement du cache d’écriture (cache volatile + protection contre la perte d’alimentation change tout)
  • Throttling thermique (les NVMe le font discrètement, comme un saboteur poli)
  • Profondeur de file et parallélisme (un seul thread occupé ne saturera pas NVMe)
  • Performance en régime permanent (après épuisement du cache SLC)

Blague #1 : Acheter du NVMe pour corriger une requête lente, c’est comme acheter un ascenseur plus rapide parce que vous avez oublié où vous avez garé.
La montée est plus fluide, mais vous êtes toujours perdu.

Quand le SATA peut être « suffisant »

Si votre jeu de données tient en mémoire, les lectures sont principalement servies par le buffer pool et les caches OS. Le stockage compte surtout pour :
écritures du redo log, écritures du binlog, et des vidages de page occasionnels.
Un bon SSD SATA peut gérer cela—jusqu’à ce que la concurrence augmente et que des tempêtes de fsync apparaissent.

NVMe tend à briller lorsque vous avez une forte concurrence d’E/S aléatoires, de grands jeux de travail,
et beaucoup de pression d’écriture—ou lorsque vous avez besoin d’une faible latence sous charge, pas seulement d’un débit maximal sur une diapositive marketing.

Faits historiques et contexte (ce que les gens oublient)

  1. MariaDB a démarré en 2009 comme fork après l’acquisition de Sun Microsystems par Oracle, propriétaire de MySQL.
  2. InnoDB est devenu le moteur par défaut pour MySQL il y a des années ; ce n’était pas toujours la norme—MyISAM était courant et avait un comportement d’E/S très différent.
  3. NVMe 1.0 est sorti en 2011, et le mythe « NVMe rend tout rapide » est arrivé peu après, souvent sans tests conscient de la profondeur de file.
  4. Les sémantiques de fsync varient selon le système de fichiers et les options de montage ; deux serveurs avec des SSD identiques peuvent afficher une latence de commit très différente.
  5. L’amplification d’écriture est réelle : un seul changement de page logique peut entraîner du redo logging, buffering doublewrite, flushs et merges d’arrière-plan.
  6. Les chiffres IOPS sont négociables : les fournisseurs les citent à des profondeurs de file et motifs d’accès spécifiques qui correspondent rarement au comportement OLTP.
  7. Les ordonnanceurs I/O Linux ont changé au fil du temps ; NVMe utilise souvent un ordonnanceur par défaut différent du SATA, impactant la latence sous charge.
  8. La protection contre la perte d’alimentation compte : les SSD « enterprise » ont souvent des condensateurs ; les SSD grand public souvent pas. Cela change le caching d’écriture sûr et la durabilité.
  9. La réplication dépend du fsync du binlog : pousser la durabilité sur des réglages « rapides » peut faire décrocher les réplicas de manière différente et déroutante.

Comment prouver le goulot d’étranglement : 12+ tâches pratiques avec commandes

Ce ne sont pas des « benchmarks pour se vanter ». Ce sont des sondes. Exécutez-les pendant une période lente et pendant une période normale.
Capturez la sortie. Prenez une décision basée sur des preuves.

Task 1: Confirm what storage you’re actually using (NVMe vs SATA) and how it’s connected

cr0x@server:~$ lsblk -d -o NAME,MODEL,TRAN,ROTA,SIZE
NAME  MODEL                 TRAN ROTA  SIZE
nvme0n1 Samsung SSD 990 PRO  nvme    0  1.8T
sda   Samsung SSD 860 EVO    sata    0  1.8T

Ce que ça signifie : TRAN vous indique l’interface. ROTA=0 signifie « non rotatif » (SSD).
Décision : si votre datadir est encore sur sda, votre achat NVMe est actuellement décoratif.

Task 2: Verify the MySQL/MariaDB datadir and which filesystem it lives on

cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'datadir';"
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| datadir       | /var/lib/mysql/ |
+---------------+-----------------+

cr0x@server:~$ df -Th /var/lib/mysql
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme0n1p2 ext4  1.8T  620G  1.1T  37% /var/lib/mysql

Ce que ça signifie : vous êtes sur ext4 reposant sur la partition NVMe nvme0n1p2.
Décision : notez le type de système de fichiers ; il affecte les sémantiques de durabilité et les options de tuning.

Task 3: Check mount options that influence write barriers and latency

cr0x@server:~$ findmnt -no TARGET,SOURCE,FSTYPE,OPTIONS /var/lib/mysql
/var/lib/mysql /dev/nvme0n1p2 ext4 rw,relatime,errors=remount-ro

Ce que ça signifie : montage ext4 basique. Aucune option exotique affichée.
Décision : si vous voyez des bizarreries comme data=writeback ou des barrières désactivées, considérez-le comme une revue de risque, pas un « tweak de performance ».

Task 4: Confirm InnoDB flush method and commit durability knobs

cr0x@server:~$ mysql -e "SHOW VARIABLES WHERE Variable_name IN ('innodb_flush_method','innodb_flush_log_at_trx_commit','sync_binlog');"
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1     |
| innodb_flush_method            | O_DIRECT |
| sync_binlog                    | 1     |
+--------------------------------+-------+

Ce que ça signifie : durabilité complète : flush du redo à chaque commit ; fsync du binlog à chaque transaction.
Décision : si la latence vous pose problème et que vous pouvez tolérer un certain risque, vous pouvez envisager d’assouplir un paramètre—mais seulement après avoir mesuré les waits de fsync (Task 10).

Task 5: Measure device health and whether it’s throttling or erroring

cr0x@server:~$ sudo smartctl -a /dev/nvme0n1 | sed -n '1,25p'
smartctl 7.4 2023-08-01 r5530 [x86_64-linux-6.8.0] (local build)
=== START OF INFORMATION SECTION ===
Model Number:                       Samsung SSD 990 PRO
Serial Number:                      S7X...
Firmware Version:                   5B2QJXD7
PCI Vendor/Subsystem ID:            0x144d
IEEE OUI Identifier:                0x002538
Total NVM Capacity:                 2,000,398,934,016 [2.00 TB]
Unallocated NVM Capacity:           0
Controller ID:                      4
Number of Namespaces:               1
Namespace 1 Size/Capacity:          2,000,398,934,016 [2.00 TB]

Ce que ça signifie : le périphérique est reconnu et fournit des informations firmware.
Décision : si vous voyez des avertissements critiques, des erreurs média ou une température élevée, arrêtez de « tuner MySQL » et corrigez d’abord le chemin matériel.

Task 6: Check NVMe temperature and thermal throttling signals

cr0x@server:~$ sudo smartctl -a /dev/nvme0n1 | grep -E "Temperature:|Critical Warning|Thermal"
Critical Warning:                   0x00
Temperature:                        64 Celsius

Ce que ça signifie : 64°C est chaud mais pas catastrophique pour beaucoup de disques ; les seuils de throttling varient.
Décision : si les températures montent pendant les pics et que les pointes de latence correspondent, ajoutez du flux d’air/une dissipation ou déplacez le périphérique ; ne discutez pas avec la thermodynamique.

Task 7: Inspect the kernel’s view of I/O scheduler and queueing

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

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

Ce que ça signifie : mq-deadline est actif.
Décision : si vous chassez la latence de queue, le choix d’ordonnanceur peut importer. Mais changez-le seulement avec des preuves avant/après, pas sur des intuitions.

Task 8: Validate whether you’re CPU bound during “storage problems”

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

12:01:22 PM  CPU   %usr %nice %sys %iowait %irq %soft %steal %idle
12:01:23 PM  all   62.1  0.0   9.2    1.1   0.0   0.6    0.0  27.0

Ce que ça signifie : faible iowait, CPU utilisateur élevé. Ça crie « requêtes/compute » plus que « disque lent ».
Décision : déplacez l’attention vers les plans de requête, la contention et l’efficacité du buffer pool avant de remplacer les disques à nouveau.

Task 9: Confirm disk-level pressure and latency with iostat

cr0x@server:~$ iostat -x 1 5
Linux 6.8.0 (server)  12/29/2025  _x86_64_ (16 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          58.10    0.00    8.90    2.40    0.00   30.60

Device            r/s     rkB/s   rrqm/s  %rrqm  r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm  w_await wareq-sz  aqu-sz  %util
nvme0n1         520.0  68400.0     0.0    0.0    2.10   131.5     880.0  99200.0     0.0    0.0    8.70   112.7     8.3   78.0

Ce que ça signifie : write await ~8.7ms et util 78% indiquent une pression significative ; NVMe peut quand même être « occupé » si votre charge est axée sur les syncs.
Décision : corrélez avec les waits de log InnoDB et le temps de fsync ; si les await augmentent avec la latence de commit, optimisez le chemin log/checkpoint, pas le buffer pool.

Task 10: Identify MySQL/MariaDB wait classes (especially I/O and log)

cr0x@server:~$ mysql -e "SELECT EVENT_NAME, COUNT_STAR, SUM_TIMER_WAIT/1000000000000 AS seconds_waited
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE EVENT_NAME LIKE 'wait/io/file/%' OR EVENT_NAME LIKE 'wait/synch/%'
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;"
+------------------------------------------+------------+----------------+
| EVENT_NAME                               | COUNT_STAR | seconds_waited |
+------------------------------------------+------------+----------------+
| wait/io/file/innodb/innodb_log_file      | 1823345    | 913.42         |
| wait/io/file/innodb/innodb_data_file     | 937223     | 411.08         |
| wait/synch/mutex/innodb/log_sys_mutex    | 8234432    | 210.55         |
+------------------------------------------+------------+----------------+

Ce que ça signifie : les waits sur le fichier de log dominent. Cela correspond souvent à la latence fsync ou à la contention du log mutex.
Décision : concentrez-vous sur la taille du redo log, les réglages de flush et la concurrence de commit ; NVMe seul ne résoudra pas un goulot log sérialisé.

Task 11: Check InnoDB checkpoint pressure and dirty page behavior

cr0x@server:~$ mysql -e "SHOW ENGINE INNODB STATUS\G" | sed -n '1,120p'
...
Log sequence number          834992230144
Log flushed up to            834992229120
Last checkpoint at           834991100928
...
Modified db pages            214833
Pending writes: LRU 0, flush list 12, single page 0
...

Ce que ça signifie : des écritures en attente dans la liste de flush et beaucoup de pages modifiées peuvent indiquer que les flushs en arrière-plan peinent.
Décision : si l’âge du checkpoint reste élevé et que les écritures en attente augmentent au pic, envisagez des redo logs plus grands et révisez innodb_io_capacity après avoir mesuré la capacité réelle du périphérique.

Task 12: Verify buffer pool hit rate and whether reads are coming from disk

cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';"
+---------------------------------------+------------+
| Variable_name                         | Value      |
+---------------------------------------+------------+
| Innodb_buffer_pool_read_requests      | 9823344123 |
| Innodb_buffer_pool_reads              | 92233441   |
+---------------------------------------+------------+

Ce que ça signifie : beaucoup de lectures disque par rapport aux requêtes peut signifier que le jeu de travail ne tient pas en mémoire ou que les requêtes balayent trop.
Décision : si les lectures disque augmentent pendant les périodes lentes, ajoutez de la mémoire / redimensionnez le buffer pool ou corrigez les requêtes qui balayent.

Task 13: Confirm redo log sizing (and whether it’s absurdly small)

cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'innodb_redo_log_capacity'; SHOW VARIABLES LIKE 'innodb_log_file_size';"
+-------------------------+------------+
| Variable_name           | Value      |
+-------------------------+------------+
| innodb_redo_log_capacity| 2147483648 |
+-------------------------+------------+
+-------------------+-----------+
| Variable_name     | Value     |
+-------------------+-----------+
| innodb_log_file_size | 0      |
+-------------------+-----------+

Ce que ça signifie : utilisation d’un dimensionnement par capacité du redo (2GiB ici). Des logs trop petits peuvent forcer des checkpoints fréquents ; des logs énormes peuvent masquer des problèmes mais augmenter le temps de recovery.
Décision : si les waits de log dominent et que la pression des checkpoints est élevée, augmenter la capacité redo est souvent une victoire propre—vérifiez d’abord les objectifs de récupération.

Task 14: Validate that you’re not secretly limited by filesystem free space or fragmentation pressure

cr0x@server:~$ df -h /var/lib/mysql
Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p2  1.8T  1.6T  140G  92% /var/lib/mysql

Ce que ça signifie : 92% d’utilisation est un signal de performance. Les SSD et les systèmes de fichiers se comportent moins bien lorsqu’ils sont presque pleins ; MySQL peut aussi peiner avec le purge et l’espace temporaire.
Décision : l’espace libre, c’est de la performance. Budgetez-le comme vous budgétisez le CPU.

Task 15: Check temporary table spill behavior (often misdiagnosed as “disk is slow”)

cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Created_tmp%';"
+-------------------------+---------+
| Variable_name           | Value   |
+-------------------------+---------+
| Created_tmp_disk_tables | 184223  |
| Created_tmp_tables      | 231002  |
+-------------------------+---------+

Ce que ça signifie : beaucoup de tables temporaires vont sur disque. Cela peut pénaliser à la fois le SATA et le NVMe, surtout si tmpdir est sur un stockage plus lent.
Décision : identifiez les requêtes créant des tables temporaires ; ajustez les index ou la forme des requêtes d’abord, puis tunez la taille des tables temporaires avec précaution.

Task 16: Watch replication for I/O-induced lag (commit stalls can ripple)

cr0x@server:~$ mysql -e "SHOW SLAVE STATUS\G" | egrep "Seconds_Behind_Master|Slave_SQL_Running|Slave_IO_Running|Relay_Log_Space"
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 87
Relay_Log_Space: 2143027200

Ce que ça signifie : le retard et de larges relay logs peuvent être causés par un apply lent dû à la pression de fsync, un parallélisme insuffisant, ou des lectures lourdes.
Décision : si le retard augmente pendant les pics d’écriture, considérez le stockage et les réglages de durabilité comme partie intégrante de la performance de réplication.

Playbook de diagnostic rapide

Voici la version « j’ai 15 minutes et un manager qui me regarde par-dessus l’épaule ». Ne débattez pas l’architecture. Trouvez le goulot.

Première étape : confirmez si la base attend des E/S ou autre chose

  • Exécutez mpstat : si iowait est faible et que le CPU est élevé, ce n’est pas « le disque » (Task 8).
  • Exécutez iostat -x : regardez await et %util pour votre périphérique datadir (Task 9).
  • Vérifiez les principaux événements d’attente dans Performance Schema : si les fichiers de log dominent, vous êtes en difficulté sur le chemin de commit (Task 10).

Deuxième étape : déterminez s’il s’agit de pression de lecture, d’écriture, ou de latence de commit

  • Pression de lecture : lectures du buffer pool en hausse (Task 12), beaucoup de lectures disque dans iostat, requêtes lentes montrant des scans complets.
  • Pression d’écriture : pages modifiées + flushs en attente + retard de checkpoint dans InnoDB status (Task 11).
  • Latence de commit : waits sur fichiers de log et waits de mutex, plus des pics de latence visibles côté utilisateurs sur les endpoints d’écriture (Task 10 + Task 4).

Troisième étape : validez le chemin de stockage et éliminez l’hypothèse « NVMe donc c’est OK »

  • Confirmez que le datadir est réellement sur NVMe (Task 1–2).
  • Vérifiez la santé/température du périphérique (Task 5–6).
  • Confirmez que le système de fichiers/options de montage ne font pas quelque chose d’étonnant (Task 3).

Quatrième étape : décidez quoi changer (et quoi ne pas toucher)

  • Si les waits pointent vers des requêtes/verrous : corrigez requêtes, index, portée des transactions. Ne touchez pas aux flags du système de fichiers pour compenser des index manquants.
  • Si les waits pointent vers redo/binlog fsync : ajustez la taille des redo et la politique de commit en fonction d’exigences de durabilité claires.
  • Si le périphérique montre du throttling/erreurs : corrigez le matériel, le refroidissement, le firmware ou l’emplacement avant de toucher aux réglages DB.

Erreurs fréquentes : symptôme → cause racine → correction

1) « On est passés au NVMe mais les écritures restent saccadées »

Symptôme : pics de latence p95 surtout sur les endpoints d’écriture ; le CPU semble correct.

Cause racine : le chemin de commit est sérialisé par le flush du redo log, fsync du binlog, ou la contention du log mutex ; le débit du périphérique n’aide pas.

Correction : mesurez les waits sur le log (Task 10), vérifiez les réglages de durabilité (Task 4), augmentez la capacité redo (Task 13), et assurez-vous que la politique de fsync du binlog correspond aux besoins métier.

2) « C’est lent seulement pendant les rapports »

Symptôme : la charge OLTP ralentit lorsque des requêtes analytiques/s rapports s’exécutent.

Cause racine : churn du buffer pool + scans longs + tables temporaires sur disque ; le stockage devient la victime, pas le coupable.

Correction : identifiez les requêtes qui balayent, ajoutez les bons index, déléguez les rapports à un réplique, et surveillez Created_tmp_disk_tables (Task 15).

3) « iowait est faible mais les utilisateurs se plaignent »

Symptôme : faible iowait système ; les timeouts applicatifs persistent.

Cause racine : contention de verrous, lignes chaudes, ou saturation CPU. Une mise à niveau de stockage ne changera rien.

Correction : inspectez les waits (Task 10), examinez le slow query log et la durée des transactions, réduisez la contention (batching, index, transactions plus courtes).

4) « Le retard de réplication est apparu après qu’on a ‘optimisé la durabilité’ »

Symptôme : les réplicas prennent du retard pendant les pics ; le master paraît rapide.

Cause racine : l’assouplissement des paramètres fsync a changé le profil de charge ; les réplicas gèrent maintenant les rafales différemment, ou le motif d’I/O du binlog/relay log s’est dégradé.

Correction : reverifiez sync_binlog et les politiques de commit ; mesurez la croissance du relay log et le comportement d’application (Task 16).

5) « NVMe est rapide, mais le serveur se fige pendant des secondes »

Symptôme : blocages périodiques ; les graphiques montrent des chutes de latence nettes.

Cause racine : throttling thermique, bizarreries firmware du périphérique, ou tempêtes de writeback quand le disque est presque plein.

Correction : vérifiez température et avertissements (Task 6), gardez de l’espace libre (Task 14), et vérifiez le comportement kernel/périphérique pendant les stalls.

6) « On a benchmarké 3GB/s, donc la production devrait aller »

Symptôme : le débit synthétique est excellent ; la production ne l’est pas.

Cause racine : mauvais indicateur. OLTP concerne les petites lectures/écritures aléatoires, la latence fsync, et le comportement de queue sous concurrence.

Correction : utilisez des tests modelés sur la charge réelle, focalisez-vous sur les p99 fsync et les waits sur les logs, comparez sous une concurrence réaliste (Task 9–11).

Trois mini-récits d’entreprise depuis le terrain

Mini-récit #1 : l’incident causé par une mauvaise hypothèse

Une entreprise SaaS de taille moyenne a migré sa base principale du SSD SATA vers NVMe pendant une fenêtre de maintenance planifiée.
Ils ont fait les bonnes étapes de base : copier les données, mettre à jour fstab, vérifier le datadir. La demande de changement disait « attendez-vous à une amélioration I/O de 3–5x ».
Le lendemain matin, le support a explosé : échecs aléatoires de checkout, pics étranges de latence de commande, et quelques deadlocks alarmants.

L’équipe on-call a supposé que le NVMe était défectueux parce que les symptômes semblaient « I/O ». Ils ont lancé un test d’écriture séquentielle rapide,
obtenu de grands chiffres, et conclu « le matériel est OK ». Puis ils ont passé des heures à changer des paramètres kernel et désactiver des choses qu’ils ne comprenaient pas.
La latence s’est empirée. Naturellement.

Le vrai problème n’était pas le périphérique. C’était une table chaude unique avec un schéma de transactions longues introduit la semaine précédente.
NVMe a rendu certaines parties plus rapides, ce qui a augmenté la concurrence, ce qui a augmenté la contention sur les verrous, ce qui a poussé la latence de queue.
Le changement de stockage a coïncidé avec l’incident, donc il a pris la faute. Les humains aiment une histoire simple.

Quand ils ont enfin vérifié les waits de Performance Schema, l’attente principale n’était pas l’I/O disque. C’était les waits de verrou et un wait de log mutex causé par
une forte contention de commits. Ils ont corrigé la portée des transactions applicatives, ajouté un index qui a supprimé un scan, et « l’incident NVMe » a disparu.
Le post-mortem n’a pas dit « ne pas acheter NVMe ». Il a dit « ne pas promouvoir la corrélation en causalité parce que ça tient dans un message Slack ».

Mini-récit #2 : l’optimisation qui a mal tourné

Une autre organisation avait un cluster MariaDB sur du bon NVMe, mais la latence de commit nuisait à leur API.
Quelqu’un a suggéré le mouvement classique : assouplir la durabilité. Ils ont changé innodb_flush_log_at_trx_commit et sync_binlog
pour réduire la fréquence des fsync. La latence d’écriture a chuté. Tout le monde a applaudi. Le changement a été déclaré « sûr » parce que « nous avons des réplicas ».

Deux semaines plus tard, un événement d’alimentation a touché un rack. Pas catastrophique—juste assez pour redémarrer plusieurs nœuds.
Un primaire est revenu avec des transactions manquantes qui avaient été reconnues aux clients. Les réplicas ne les avaient pas sauvegardées parce que ces transactions perdues
n’avaient jamais été écrites sur un média stable sur le primaire, et l’automatisation de bascule a promu le mauvais nœud.
Maintenant ils avaient un incident d’intégrité des données. Ceux-là font parler les gens à voix basse en réunion.

Le retour de bâton n’était pas « les réglages de durabilité sont mauvais ». C’était le décalage entre les exigences métier et les choix techniques.
Si vous devez assouplir la durabilité, faites-le délibérément : avec des dispositifs protégés contre la perte d’alimentation, des procédures de récupération claires,
et un accord explicite sur ce que signifie « écriture reconnue ».

Ils ont rétabli les réglages, puis corrigé le goulot réel : contention du log et pression de checkpoint.
Ils ont redimensionné les redo logs, confirmé le refroidissement pour éviter le throttling, et séparé les binlogs sur un volume différent.
La latence API s’est améliorée à nouveau—sans tromper les utilisateurs sur la durabilité.

Mini-récit #3 : la pratique ennuyeuse mais correcte qui a sauvé la mise

Une équipe de services financiers faisait tourner MySQL sur NVMe, mais considérait le stockage comme un composant de fiabilité, pas un autocollant de performance.
Ils avaient une routine : vérifications hebdomadaires de la santé SMART, baselines de température sous pics, et un petit jeu de « commandes dorées » capturées dans des runbooks.
Ils suivaient aussi le p99 fsync comme métrique de première classe.

Un mardi, ils ont remarqué une légère augmentation de la latence d’écriture—rien de dramatique, juste assez pour faire remonter le p95 API.
Les habituelles théories « c’est le réseau » ont commencé à circuler. L’ingénieur on-call n’a pas argumenté ; il a sorti le runbook et exécuté les vérifications.
SMART montrait des températures en hausse, et iostat montrait w_await en hausse sous charge.

Ils ont trouvé un ventilateur défaillant dans le châssis. Le NVMe commençait à throttler pendant les pics.
Remplacez le ventilateur, restaurez le flux d’air, la latence revient à la normale. Pas d’incident, pas de maintenance d’urgence, pas de résumé exécutif plein de gesticulations.
La correction était ennuyeuse. Le résultat était beau.

Blague #2 : La meilleure optimisation de performance est parfois un ventilateur à 20 $—parce que les électrons préfèrent aussi ne pas être rôtis.

Checklists / plan étape par étape

Étape par étape : isoler « le stockage est lent » de « la base est lente »

  1. Vérifier l’emplacement : confirmez que datadir et tmpdir sont sur le périphérique prévu (Task 1–2).
  2. Confirmer la pression système : mpstat + iostat pendant une fenêtre lente (Task 8–9).
  3. Vérifier les waits DB : Performance Schema top waits et InnoDB status (Task 10–11).
  4. Classifier la charge :

    • Si les waits de log dominent : chemin commit/fsync.
    • Si les lectures sur fichiers de données dominent : problème de mémoire / plan de requête.
    • Si les waits mutex/verrous dominent : problème de contention / conception des transactions.
  5. Valider la santé hardware : avertissements SMART et température (Task 5–6).
  6. Faire un seul changement à la fois, avec capture avant/après et plan de rollback.

Checklist : préparation NVMe pour MySQL/MariaDB

  • Le disque dispose d’une protection contre la perte d’alimentation si vous comptez sur le caching d’écriture sûr pour la latence.
  • Les thermique sont surveillées ; le flux d’air du châssis est validé sous pic.
  • Le choix du système de fichiers et les options de montage sont standardisés sur la flotte.
  • Les réglages redo/binlog correspondent aux exigences métier de durabilité (pas seulement aux benchmarks).
  • Il existe une marge de capacité (ne pas tourner à 90%+ sauf si vous aimez les surprises).
  • Vous pouvez répondre : « Quel est l’événement d’attente principal au pic ? » et « p99 fsync time ? »

Checklist : points de décision MySQL vs MariaDB (édition pragmatique)

  • Compatibilité : confirmez la parité des fonctionnalités dont vous dépendez (mode de réplication, GTIDs, outils).
  • Observabilité : choisissez celui que votre équipe peut déboguer rapidement avec les compétences et tableaux de bord existants.
  • Discipline de mise à jour : optez pour l’écosystème où vous pouvez patcher régulièrement avec un comportement prévisible.
  • Outils opérationnels : sauvegardes, vérification, bascule, migrations de schéma—cela compte plus que les microbenchmarks.

FAQ

1) NVMe doit-il toujours surclasser un SSD SATA pour MySQL ?

Pas toujours de façons perceptibles. Si vous êtes CPU-bound, lock-bound, ou si votre jeu de travail tient en mémoire, NVMe ne changera pas grand-chose.
NVMe excelle sous forte concurrence d’E/S aléatoires et quand vous avez besoin d’une faible latence de queue sous charge soutenue d’écriture.

2) Pourquoi « %iowait » reste faible même quand les requêtes sont lentes ?

Parce que le processus peut attendre des verrous, l’ordonnancement CPU, des stalls mémoire, ou des mutex internes à MySQL.
De plus, iowait est une métrique de comptabilité CPU, pas une mesure directe de la latence disque. Utilisez iostat et les waits DB à la place.

3) innodb_flush_log_at_trx_commit=2 est-il sûr ?

C’est un compromis de durabilité. Cela peut entraîner la perte d’environ une seconde de transactions committées en cas de crash/perte d’alimentation.
« Sûr » dépend de votre contrat métier avec la réalité. Décidez explicitement, et ne cachez pas cela derrière un « tuning de performance ».

4) Mes waits de log dominent. Quel est le premier réglage à toucher ?

Mesurez d’abord. Ensuite envisagez la capacité du redo log (trop petit provoque du churn de checkpoint) et la fréquence de fsync du binlog.
Si la durabilité doit rester stricte (1/1), vous aurez probablement besoin de périphériques à faible latence, SSD avec PLP, ou de réduire la concurrence de commit côté appli.

5) Le choix du système de fichiers (ext4 vs XFS) compte-t-il pour la performance DB ?

Ça peut, surtout via le comportement de latence sous writeback et la gestion des métadonnées et de l’allocation.
Le plus grand gain est la cohérence et la mesurabilité entre hôtes. Choisissez-en un, standardisez les options de montage, et basez vos baselines sur le p99 fsync.

6) Quelle est la façon la plus simple de savoir si je suis lié en lecture ou en écriture ?

Regardez Innodb_buffer_pool_reads et iostat lectures vs écritures, puis recoupez avec Performance Schema.
Beaucoup de lectures disque et des waits sur les fichiers de données impliquent une pression de lecture. Beaucoup de waits de log et des flushs en attente impliquent une pression d’écriture/commit.

7) Comment un « disque plus rapide » peut-il aggraver la contention sur les verrous ?

En augmentant le débit de certaines opérations, vous pouvez augmenter la concurrence et la pression sur des hot-spots ailleurs.
Des commits plus rapides peuvent provoquer plus de collisions sur les mêmes lignes ou index, faisant remonter la contention en première ligne.

8) Les NVMe grand public conviennent-ils pour des bases en production ?

Parfois, pour des charges non critiques. Pour des systèmes sensibles à la durabilité, l’absence de protection contre la perte d’alimentation et la latence en régime permanent inconsistente
sont souvent rédhibitoires. Même quand ils sont « rapides », leurs modes de défaillance sont rarement polis.

9) MySQL vs MariaDB : lequel est plus rapide sur NVMe ?

Ça dépend de la version, de la charge, de la configuration et des fonctionnalités utilisées. En exploitation réelle, « plus rapide » compte moins que
« débogable de façon prévisible » et « se comporte bien en cas de panne ». Benchmarquez votre propre charge et comparez les profils de waits, pas seulement le QPS.

10) Quelle métrique unique dois-je alerter pour détecter tôt la douleur liée au stockage ?

Si vous ne pouvez en choisir qu’une, alertez sur la latence liée au commit ou le temps de wait du fichier de log (depuis l’instrumentation DB) plus la température du périphérique.
Ces deux métriques captent une étonnante quantité de douleur réelle.

Conclusion : étapes pratiques suivantes

NVMe est un excellent outil. Ce n’est pas un substitut à la compréhension du profil d’attente de votre base.
Si votre système MySQL ou MariaDB semble encore lent après être passé du SSD SATA au NVMe, ne partez d’aucune hypothèse et mesurez tout ce qui compte :
chemin de commit, pression de checkpoint, misses du buffer pool, et santé du périphérique.

  1. Exécutez le playbook de diagnostic rapide pendant une fenêtre lente et capturez les sorties.
  2. Classez le goulot (pression lecture vs pression écriture/commit vs contention/CPU).
  3. Corrigez la contrainte la plus efficace : plans/ verrous, redimensionnement des redo/checkpoints, ou thermiques/santé hardware.
  4. Faites un seul changement à la fois. Préparez un rollback. Basez-vous sur p95/p99 de latence, pas seulement le débit.

Votre objectif n’est pas « NVMe partout ». Votre objectif est une base qui se comporte de façon prévisible au pic, échoue honnêtement, et peut être déboguée rapidement par des humains fatigués.

← Précédent
Debian 13 Split DNS pour VPN et LAN : une configuration propre qui ne casse pas après un redémarrage
Suivant →
E-mail : les inclusions SPF sont un désordre — comment simplifier sans casser la délivrabilité

Laisser un commentaire