À 02:13, la sonnerie ne se soucie pas du logo affiché sur votre base. Elle veut juste que le paiement ne timeout pas, que les répliques
ne prennent pas de retard, et que quelqu’un n’ait pas « augmenté max_connections » parce que ça semblait utile.
MariaDB et Percona Server promettent tous deux de la performance. Parfois elles la tiennent. Parfois le « réglage » est une fonctionnalité
que vous aviez déjà, un bouton qu’il ne fallait pas toucher, ou une instrumentation qui est excellente — jusqu’à ce qu’elle devienne la charge.
Séparons les véritables gains de la brochure, et faisons-le comme on gère réellement des systèmes en production.
Ce que vous choisissez vraiment (ce n’est pas un benchmark)
Le débat MariaDB vs Percona Server est généralement posé comme une course de vitesse : lequel est le plus rapide ? C’est la mauvaise question.
En production, vous choisissez un ensemble de valeurs par défaut, d’outils opérationnels, d’un niveau de compatibilité et la nature de la douleur
que vous rencontrerez à grande échelle.
MariaDB et Percona Server ont tous deux commencé comme « MySQL, mais en mieux ». Aujourd’hui, ce sont des écosystèmes différents. Percona Server (pour MySQL)
reste proche du comportement MySQL upstream et suit les versions majeures de MySQL. MariaDB a sa propre ligne de versions et a divergé plus
significativement au fil du temps — parfois de façons réellement utiles, parfois de façons qui surprennent des équipes supposant « c’est
essentiellement MySQL ».
Si vous exécutez des charges OLTP déjà correctement réglées, les grands gains de performance ne viennent que rarement de la « marque du serveur ».
Ils proviennent de :
- l’hygiène des requêtes et des index (oui, encore)
- le dimensionnement du buffer pool et le contrôle du turnover des pages
- le comportement redo/undo et les paramètres de flush alignés sur votre stockage
- la gestion des connexions et l’ordonnancement des threads sous charge en rafales
- la topologie de réplication et les choix de durabilité qui correspondent au business
- l’observabilité qui ne se transforme pas en charge
Le fork que vous choisissez importe surtout lorsque vous avez besoin d’une fonctionnalité spécifique (thread pool, instrumentation, intégration des outils de sauvegarde),
que vous souhaitez réduire le risque opérationnel, ou que vous devez préserver la compatibilité MySQL pour des applications vendors. « Il était 12% plus rapide
dans un benchmark de blog » est rarement une bonne raison, car le goulot d’étranglement se situe généralement ailleurs.
Faits historiques et contexte intéressant (version courte)
Un peu de contexte aide à décoder le marketing :
- MariaDB a été créée en 2009 après l’acquisition de Sun par Oracle (et donc de MySQL). Le nom rend hommage à la fille de Monty Widenius, comme « MySQL » l’était pour « My ».
- Percona a bâti une activité sur la résolution de problèmes de performance MySQL avant de publier Percona Server comme distribution avec des patches pratiques et des outils.
- Percona Server a historiquement livré « XtraDB » (une variante InnoDB axée performance) avant que l’InnoDB de MySQL ne rattrape de nombreuses fonctionnalités ; la marque subsiste, mais les améliorations upstream ont réduit l’écart.
- Mariabackup existe parce que XtraBackup de Percona est devenu le standard pour les sauvegardes physiques à chaud dans l’écosystème MySQL ; MariaDB a ensuite fourni un équivalent aligné sur sa base de code.
- L’optimiseur et l’ensemble de fonctionnalités de MariaDB ont divergé sensiblement au fil des années ; la compatibilité avec MySQL n’est pas une promesse statique, c’est une cible mouvante.
- Performance Schema est passé d’« overhead optionnel » à « réalité par défaut » dans les distributions MySQL ; la question opérationnelle est devenue « comment échantillonner judicieusement », pas « s’instrumenter ou non ».
- L’ordonnancement par thread pool a été un thème récurrent parce que le modèle connexion-par-thread se comporte mal lors d’orage de connexions ; le pooling thread est une solution pratique quand les applications ne se comportent pas.
- Les SSD modernes et le NVMe ont changé la feuille de route de tuning d’InnoDB : les IOPS aléatoires sont devenues relativement bon marché, mais le comportement fsync et l’amplification d’écriture restent problématiques, surtout avec les réglages de durabilité et le doublewrite.
Revendications de performance : vrai, marketing, ou conditionnel
1) « Meilleure performance dès l’installation »
Parfois vrai, mais souvent dénué de sens. « Dès l’installation » dépend des valeurs par défaut de l’OS, du système de fichiers, des limites de cgroup,
de l’échelle de fréquence CPU, et si votre distribution livre des configs conservatrices.
Ce qui peut être réel :
- Des valeurs par défaut plus sensées pour la production (buffer pool, IO threads, méthode de flush) peuvent faire une différence notable pour des équipes n’ayant jamais bien réglé MySQL.
- La disponibilité d’un thread pool (selon édition/version) peut stabiliser la performance quand le nombre de connexions est élevé.
- Des contrôles d’observabilité supplémentaires peuvent réduire les « inconnues » lors d’incidents.
Ce qui relève du marketing :
- des benchmarks qui cachent le véritable goulot (stockage, réseau, app pool starvation)
- des affirmations qui ignorent les réglages de durabilité (rapide parce qu’il fsync moins)
- des gains de débit en single-client qui ne se traduisent pas sur la latence tail en concurrence
2) « InnoDB/XtraDB amélioré signifie écritures plus rapides »
Historiquement, les patches XtraDB de Percona faisaient la différence. Aujourd’hui, InnoDB upstream de MySQL a intégré beaucoup d’améliorations.
Les différences restantes concernent surtout l’instrumentation, les réglages et le comportement opérationnel en périphérie.
Des gains réels existent encore, mais ils sont conditionnels :
- Les charges orientées écriture peuvent tirer profit d’un meilleur comportement de flush et d’un dimensionnement sain des redo logs — quel que soit le fork.
- Les charges liées à l’IO bénéficient davantage d’un réglage correct de la capacité IO et d’éviter le double-buffering que du choix du fork.
- Les environnements à forte réplication se préoccupent de l’efficacité du diagnostic, du throttling et de la récupération — l’outillage compte.
3) « Le thread pool corrige la concurrence »
Les thread pools sont réels. Ils peuvent transformer un orage de connexions de « spirale de mort du serveur » en « plus lent mais vivant ». Mais ce n’est pas
magique. C’est du contrôle d’admission. Ils ne corrigent pas les requêtes lentes, les mauvais index, ou une seule ligne « chaude » que tout le monde met à jour.
Le thread pool est surtout utile quand :
- votre application ouvre trop de connexions
- vous ne pouvez pas corriger rapidement l’application (logiciel vendor, nombreux microservices, pools legacy)
- vous avez du trafic en rafales et devez protéger la latence tail
4) « Meilleure instrumentation »
L’écosystème Percona a historiquement mis l’accent sur la visibilité : analyse des slow queries, digests de requêtes, et valeurs par défaut opérationnelles plus sûres.
MariaDB possède sa propre instrumentation et ses compteurs d’état, et dans certains environnements c’est parfaitement adéquat.
Le piège est de penser que « plus de métriques » équivaut à « plus de performance ». L’instrumentation peut ajouter du coût, surtout le traçage au niveau des statements ou des waits
sous un QPS élevé. Activez-la avec intention. Échantillonnez. Faites tourner. Automatisez.
Une idée paraphrasée de Jim Gray (pionnier de la fiabilité et du traitement transactionnel) : traiter les pannes comme normales ; concevoir pour que le système reste correct lorsqu’elles se produisent.
Un tuning de performance qui compromet la correction n’est qu’une panne au ralenti.
5) « Remplacement sans effort » (drop-in)
C’est là que les deux forks divergent en pratique. Percona Server est généralement plus proche du comportement MySQL upstream. MariaDB a introduit
des fonctionnalités et des changements qui peuvent surprendre les applications dépendantes de MySQL — surtout celles qui se reposent sur des modes SQL spécifiques,
des cas limites de l’optimiseur, la sémantique de réplication ou les tables système.
Si vous exécutez une application vendor déclarant « MySQL 8.0 supporté », choisir MariaDB parce que « c’est MySQL-ish » peut devenir un test de personnalité très coûteux.
Si vous contrôlez l’application et testez correctement, MariaDB peut être un excellent choix.
Blague n°1 : Les benchmarks sont comme un tableau de bord dans une voiture de location — on peut se sentir rapide en descendant une pente moteur éteint.
Playbook de diagnostic rapide (premier/deuxième/troisième)
Quand la latence pique ou que le débit s’effondre, vous ne commencez pas par changer de fork de base. Vous commencez par identifier la ressource limitante
et le type d’attente dominant. Voici le chemin le plus court que je connaisse et qui fonctionne sous stress.
Premier : est-ce CPU, IO, verrous, ou ordonnancement des connexions ?
- Limité par CPU : CPU user élevé, faible IO wait, requêtes qui brûlent des cycles, mauvais index, tris lourds, mauvais joins.
- Limité par IO : IO wait élevé, latence fsync élevée, churn du buffer pool, blocages sur pages dirty, pression redo.
- Limité par verrous : beaucoup de threads « Waiting for lock », lignes chaudes, transactions longues, verrous metadata.
- Limité par connexions : trop de connexions actives, context switching, effondrement de l’ordonnancement des threads, backlog de la file d’acceptation.
Deuxième : la douleur vient-elle de la charge principale ou des « aides » ?
- threads de réplication (SQL/appliquer) à la traîne
- jobs de sauvegarde et snapshots qui martèlent l’IO
- monitoring qui scrape trop agressivement
- opérations DDL ou changement de schéma en ligne mal throttlées
Troisième : qu’est-ce qui a changé ?
- déploiements (changement de forme des requêtes)
- changements de config (paramètres de flush, tailles de buffers, concurrence des threads)
- croissance des données (index qui ne tient plus en mémoire)
- événements d’infrastructure (voisin bruyant, firmware de stockage étrange)
Votre objectif dans les dix premières minutes n’est pas de « réparer pour toujours ». C’est classifier le goulot, arrêter l’hémorragie, et éviter une défaillance en cascade
(lag de réplication, tempêtes de retry, accumulation de connexions).
Tâches pratiques à exécuter aujourd’hui (commandes, sorties, décisions)
Ce ne sont pas des théories. Ce sont les commandes que vous exécutez quand il faut décider si l’on règle InnoDB, kill une requête, réduire la charge du monitoring,
ou arrêter de blâmer la base pour un problème de stockage.
Hypothèses : hôte Linux, systemd, et client local. Ajustez les noms de service si votre packaging diffère.
Mission 1 : Confirmer ce que vous exécutez réellement
cr0x@server:~$ mysql -e "SELECT VERSION() AS version, @@version_comment AS comment, @@version_compile_machine AS arch;"
+-------------------------+------------------------------+------+
| version | comment | arch |
+-------------------------+------------------------------+------+
| 8.0.36-28 | Percona Server (GPL), Release 28 | x86_64 |
+-------------------------+------------------------------+------+
Ce que cela signifie : Vous connaissez maintenant le fork exact et la ligne de build. Beaucoup de guides de « tuning » sont spécifiques à une version.
Décision : Alignez vos attentes de tuning et de fonctionnalités sur cette version. N’appliquez pas des knobs réservés à MariaDB sur Percona, ou inversement.
Mission 2 : Vérifier si vous êtes limité par le CPU ou par l’IO (vue rapide)
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 521240 81232 8123456 0 0 12 55 980 2100 22 6 69 3 0
6 3 0 498120 79012 8011200 0 0 820 2400 1250 9900 28 9 41 22 0
Ce que cela signifie : « wa » (IO wait) qui saute à 22% suggère une pression IO, pas purement du CPU.
Décision : Investiguer flush/fsync, throttling des pages dirty, et la latence de stockage avant de courir après des micro-optimisations CPU des requêtes.
Mission 3 : Mesurer la latence stockage depuis l’OS
cr0x@server:~$ iostat -x 1 3
avg-cpu: %user %nice %system %iowait %steal %idle
18.21 0.00 6.11 19.44 0.00 56.24
Device r/s w/s r_await w_await aqu-sz %util
nvme0n1 120.0 980.0 1.20 9.80 3.40 92.0
Ce que cela signifie : Les écritures attendent ~10ms et l’utilisation est élevée. C’est un vrai goulot si votre charge est orientée écriture.
Décision : Examinez le comportement de flush et des redo logs d’InnoDB, et vérifiez que vous n’avez pas de double-buffering (système de fichiers + InnoDB) inutile.
Mission 4 : Vérifier les threads actifs et les principaux waits dans MySQL/MariaDB
cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_running'; SHOW GLOBAL STATUS LIKE 'Threads_connected';"
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| Threads_running | 184 |
+-----------------+-------+
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_connected | 620 |
+-------------------+-------+
Ce que cela signifie : 184 threads en exécution, c’est beaucoup pour la plupart des machines. Si le CPU n’est pas saturé, vous pouvez être bloqué par des verrous/IO ou en thrashing.
Décision : Envisagez un thread pool (si disponible) ou corrigez le pooling applicatif. Pendant ce temps, identifiez les plus gros blocages.
Mission 5 : Trouver les pires requêtes par temps (slow log digest)
cr0x@server:~$ pt-query-digest /var/log/mysql/mysql-slow.log --limit=3
# 1 45% 120s 0.2s 600x SELECT orders ... WHERE user_id = ?
# 2 22% 60s 1.0s 60x UPDATE inventory ... WHERE sku = ?
# 3 15% 40s 0.1s 400x SELECT cart_items ... JOIN products ...
Ce que cela signifie : La requête n°1 n’est pas lente par exécution, elle est lourde par volume. La n°2 est lente par exécution et probablement source de contention.
Décision : Corriger par impact : réduire la fréquence d’abord (cache/modèle de lecture), puis améliorer la lenteur par exécution (index, périmètre de transaction).
Mission 6 : Confirmer le dimensionnement du buffer pool et un proxy de hit rate
cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads'; SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';"
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| innodb_buffer_pool_size | 25769803776|
+-------------------------+------------+
+--------------------------+----------+
| Variable_name | Value |
+--------------------------+----------+
| Innodb_buffer_pool_reads | 18422012 |
+--------------------------+----------+
+----------------------------------+------------+
| Variable_name | Value |
+----------------------------------+------------+
| Innodb_buffer_pool_read_requests | 9871120031 |
+----------------------------------+------------+
Ce que cela signifie : Des lectures depuis le disque existent, mais il faut une cadence dans le temps pour juger. Si les lectures montent rapidement pendant les pics, vous manquez de cache.
Décision : Si le working set ne tient pas, ajoutez de la RAM, réduisez le dataset, ou changez les patterns d’accès (index, archivage). Le choix du fork ne changera pas la physique.
Mission 7 : Vérifier la pression des redo logs et le comportement des checkpoints
cr0x@server:~$ mysql -e "SHOW ENGINE INNODB STATUS\G" | sed -n '1,120p'
Log sequence number 812345678901
Log flushed up to 812345670000
Last checkpoint at 812300000000
0 pending log flushes, 0 pending chkp writes
Ce que cela signifie : Si « Log flushed up to » est loin derrière le LSN sous charge, le fsync est en retard. Si le checkpoint prend du retard massivement, vous pouvez staller sur les pages dirty.
Décision : Réglez prudemment la taille du redo log et les paramètres de flush ; validez la latence du stockage. Vérifiez aussi le pourcentage de pages dirty et le flushing.
Mission 8 : Identifier les waits de verrou et les statements bloquants
cr0x@server:~$ mysql -e "SHOW PROCESSLIST;" | head -n 15
Id User Host db Command Time State Info
91 app 10.0.2.5 shop Query 42 Waiting for table metadata lock ALTER TABLE orders ADD COLUMN ...
104 app 10.0.2.9 shop Query 41 Updating UPDATE inventory SET qty=qty-1 WHERE sku='X'
Ce que cela signifie : Un DDL détient ou attend des verrous metadata et peut bloquer des requêtes applicatives selon le timing.
Décision : Arrêtez d’exécuter des DDL surprises sur les primaires pendant les pics. Utilisez des outils de changement de schéma en ligne et planifiez des fenêtres de maintenance avec throttling adapté à la charge.
Mission 9 : Confirmer la santé de la réplication (primaire/réplica)
cr0x@server:~$ mysql -e "SHOW REPLICA STATUS\G" | egrep 'Seconds_Behind_Source|Replica_IO_Running|Replica_SQL_Running|Last_SQL_Error'
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Seconds_Behind_Source: 187
Last_SQL_Error:
Ce que cela signifie : La réplique est saine mais en retard. C’est une question de capacité ou d’efficacité d’application, pas un tuyau cassé.
Décision : Vérifiez l’IO/CPU de la réplique, les réglages de réplication parallèle, et si des transactions longues sur le primaire créent des rafales d’application.
Mission 10 : Vérifier les tempêtes de connexions et l’abus de max_connections
cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'max_connections'; SHOW GLOBAL STATUS LIKE 'Max_used_connections'; SHOW GLOBAL STATUS LIKE 'Aborted_connects';"
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 2000 |
+-----------------+-------+
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| Max_used_connections | 1987 |
+----------------------+-------+
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| Aborted_connects | 9321 |
+------------------+-------+
Ce que cela signifie : Vous atteignez le plafond. Augmenter max_connections rend généralement le crash plus bruyant, pas moins fréquent.
Décision : Corrigez le pooling et les timeouts dans l’application. Envisagez le thread pool. Appliquez de la backpressure en périphérie. Traitez 2000 connexions comme un signal d’alerte.
Mission 11 : Vérifier les réglages de durabilité (et si « performance » c’est juste moins de fsync)
cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit'; SHOW VARIABLES LIKE 'sync_binlog';"
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| innodb_flush_log_at_trx_commit | 2 |
+------------------------------+-------+
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog | 0 |
+---------------+-------+
Ce que cela signifie : C’est « plus rapide » parce que c’est moins durable. En cas de crash, vous pouvez perdre des transactions et des événements binlog.
Décision : Décidez en connaissance de cause : si vous avez besoin d’une durabilité forte, mettez 1/1 (ou un compromis documenté) et achetez le stockage pour le supporter.
Mission 12 : Repérer la pression de tables temporaires et de tris (IO disque cachée)
cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables'; SHOW GLOBAL STATUS LIKE 'Created_tmp_tables'; SHOW GLOBAL STATUS LIKE 'Sort_merge_passes';"
+-------------------------+--------+
| Variable_name | Value |
+-------------------------+--------+
| Created_tmp_disk_tables | 120322 |
+-------------------------+--------+
+---------------------+--------+
| Variable_name | Value |
+---------------------+--------+
| Created_tmp_tables | 890441 |
+---------------------+--------+
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Sort_merge_passes | 9921 |
+-------------------+-------+
Ce que cela signifie : Beaucoup de tables temporaires débordent sur disque, et les tris effectuent des passes de merge. C’est du CPU et de l’IO non budgétés.
Décision : Optimisez d’abord les requêtes et les index. Ensuite révisez tmp_table_size/max_heap_table_size et les buffers de tri avec prudence (gros buffers × nombreux threads = explosion RAM).
Mission 13 : Vérifier si vous souffrez de throttling des pages dirty
cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty'; SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_total';"
+--------------------------------+--------+
| Variable_name | Value |
+--------------------------------+--------+
| Innodb_buffer_pool_pages_dirty | 412000 |
+--------------------------------+--------+
+-------------------------------+--------+
| Variable_name | Value |
+-------------------------------+--------+
| Innodb_buffer_pool_pages_total| 1572864|
+-------------------------------+--------+
Ce que cela signifie : Environ 26% de pages dirty. Si vous voyez des stalls et que ce ratio grimpe vers le maximum configuré, vous pouvez déclencher des vagues de flushing.
Décision : Vérifiez innodb_max_dirty_pages_pct et les réglages de capacité IO. Si le stockage ne suit pas, le tuning ne fait que déplacer la souffrance.
Mission 14 : Confirmer binlog et GTID pour la sanity opérationnelle
cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'gtid_mode'; SHOW VARIABLES LIKE 'enforce_gtid_consistency'; SHOW VARIABLES LIKE 'log_bin';"
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| gtid_mode | ON |
+--------------------------+-------+
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| enforce_gtid_consistency | ON |
+--------------------------+-------+
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
Ce que cela signifie : Vous avez les prérequis pour des workflows de bascule de réplication sains.
Décision : Si vous êtes dépourvu de ces options, n’allez pas chasser des micro-optimisations — réglez d’abord l’opérabilité, car une panne coûte souvent plus que 5% de débit.
Mission 15 : Vérifier si vous swappez (tueur silencieux de performance)
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 64Gi 58Gi 1.2Gi 1.0Gi 4.8Gi 2.0Gi
Swap: 8Gi 1.5Gi 6.5Gi
Ce que cela signifie : Le swap est utilisé. Sous charge de base de données, cela peut se traduire par des pics de latence aléatoires qui ressemblent à « MySQL est lent ».
Décision : Réduisez la pression mémoire (buffers, connexions, mémoire par thread) et envisagez de désactiver le swap uniquement si vous avez une discipline OOM et capacité solide.
Mission 16 : Comparer les deltas de config clés entre deux serveurs (sanity migration)
cr0x@server:~$ mysql -e "SHOW VARIABLES" | egrep '^(innodb_flush_method|innodb_io_capacity|innodb_log_file_size|max_connections|thread_handling)\s'
innodb_flush_method O_DIRECT
innodb_io_capacity 2000
innodb_log_file_size 1073741824
max_connections 2000
thread_handling one-thread-per-connection
Ce que cela signifie : Vous avez fait remonter les knobs les plus susceptibles de changer les caractéristiques de performance et les modes de défaillance entre hôtes.
Décision : Standardisez les configs quand possible, puis testez les différences intentionnellement. Évitez les bases « snowflake ».
Où les réglages de performance échouent en production
Le choix du fork ne vous sauvera pas de la physique IO
La mathématique de l’IO est cruelle et cohérente. Si vous avez une charge orientée écriture avec des commits durables (fsync au commit, sync du binlog),
la latence de votre stockage fixe le plancher de la latence de commit. Un « fork plus rapide » peut réduire le coût CPU, mais il ne peut pas transformer
un fsync à 10ms en 1ms.
Le levier réel est d’aligner durabilité et stockage :
- NVMe avec une latence fsync prévisible
- volumes séparés (ou au moins domaines de contention séparés) pour données et logs quand c’est utile
- méthode de flush appropriée pour éviter le double caching
- taille de redo log adaptée pour réduire le thrash des checkpoints
Le thread pool peut stabiliser, mais aussi masquer la pourriture
Le thread pool est une ceinture de sécurité. Utile quand la voiture percute quelque chose. Pas un substitut à savoir conduire.
Avec le thread pooling, les mauvaises requêtes peuvent devenir « moins manifestement mauvaises » parce que moins s’exécutent en parallèle, et le système cesse de fondre.
C’est gagnant opérationnellement, mais cela peut retarder les corrections de requêtes nécessaires. Votre backlog devient une queue plutôt qu’un crash.
L’instrumentation n’est utile que si vous pouvez la financer
Beaucoup d’incidents productifs sont une « dette d’observabilité » cumulée : personne n’avait activé les slow logs, personne ne conservait les digests de requêtes,
et maintenant tout le monde veut l’échantillonnage complet des statements pendant l’incendie. Tout activer pendant le feu peut devenir le feu lui-même.
Position pratique :
- gardez le slow query logging disponible et tournant par rotation
- autorisez l’instrumentation de performance à un niveau soutenable
- sachez comment augmenter l’échantillonnage temporairement et le revenir en arrière
Les problèmes de compatibilité apparaissent souvent comme des « problèmes de performance »
Quand une appli suppose la sémantique MySQL et que vous êtes sur MariaDB, vous pouvez obtenir des changements de plan subtils, des décisions d’optimiseur différentes,
ou des différences sur des variables système. Cela se manifeste comme « des requêtes sont devenues lentes » après une migration. Ce n’est pas toujours un problème de tuning ;
parfois c’est un décalage sémantique.
Blague n°2 : « On a activé toutes les options de performance » est l’équivalent base de données de « on a résolu le bruit en enlevant le détecteur de fumée ».
Trois mini-histoires d’entreprise (anonymisées, douloureusement plausibles)
Mini-histoire 1 : L’incident causé par une mauvaise hypothèse
Une entreprise SaaS de taille moyenne exécutait une application vendor « certifiée pour MySQL ». Ils étaient sur un ancien MySQL communautaire et souhaitaient
une meilleure observabilité et du support. Quelqu’un a proposé MariaDB comme « remplacement sans effort ». L’installation s’est passée proprement, la réplication
est montée, les dashboards semblaient normaux, et la migration a été déclarée succès.
Deux semaines plus tard, après un pic de trafic, la latence a grimpé sur un endpoint spécifique qui avait toujours été limite. Le plan de requête
a changé. Pas de façon dramatique — juste assez pour inverser l’ordre d’un join et qu’un index secondaire ne soit plus utilisé de la même manière.
L’équipe a fait ce que font les équipes : augmenté le buffer pool, augmenté les tailles de tmp table, et ajouté du CPU. Les pics sont devenus plus rares, mais la tail s’est empirée.
Le vrai problème était l’hypothèse : « si ça tourne, c’est compatible ». La matrice de support du vendor portait sur la ligne majeure MySQL. MariaDB n’était pas « mauvaise » ;
elle était « différente ». Avec certaines distributions de données, le choix de l’optimiseur a régressé la requête.
La correction a été ennuyeuse : ils sont revenus à une compatibilité de type MySQL en passant à Percona Server dans la version majeure supportée,
ont épinglé la requête problématique avec un index plus sûr, et ajouté des tests de régression utilisant des distributions de données proches de la production.
La migration de retour leur a coûté une semaine et beaucoup de réunions, mais ils ont récupéré la prévisibilité — qui est la vraie monnaie.
Mini-histoire 2 : L’optimisation qui a mal tourné
Une équipe fintech voulait réduire la latence de commit. Ils avaient du NVMe correct, mais leurs écritures p99 restaient pénibles pendant les pics.
Un ingénieur bien intentionné a changé les réglages de durabilité : a mis innodb_flush_log_at_trx_commit=2 et sync_binlog=0.
Les benchmarks étaient beaux. Les graphiques aussi. Tout le monde est rentré chez soi.
Un mois plus tard, un kernel panic survient pendant une maintenance de routine. Le primaire revient, les réplicas se reconnectent, et l’appli fonctionne en grande partie — sauf qu’un sous-ensemble de transactions a disparu.
Pas « rollback ». Parties. Le binlog ne les avait pas, le redo log avait accusé des commits sans les avoir persistés aussi fortement que le business le supposait, et la réconciliation est devenue un week-end de misère contrôlée.
Le postmortem a été honnête : l’optimisation n’était pas « fausse ». C’était un risque non documenté. Ils avaient changé le contrat produit (durabilité) sans prévenir le métier.
Leur amélioration de performance était réelle, tout comme la perte de données.
La correction à long terme a été aussi ennuyeuse : restaurer des réglages durables, améliorer le stockage pour obtenir une latence fsync prévisible, et introduire une approche en couches
où les workloads non critiques peuvent utiliser une durabilité relâchée tandis que les paiements ne le peuvent pas. La performance est venue de l’architecture et du stockage, pas d’un paramètre magique.
Mini-histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la journée
Une place de marché exécutait Percona Server avec des réplicas inter-zones. Rien de fancy. Ils faisaient une chose banale et régulière : des tests hebdomadaires de restauration
depuis des backups physiques dans un environnement de staging, plus des vérifications périodiques que l’instance restaurée puisse rejoindre la réplication via GTID.
Un après-midi, un développeur déploie une migration qui crée un nouvel index sur une table massive. Le DDL utilisait une méthode en ligne, mais la charge était élevée et le throttling mal réglé.
L’IO a monté, les pages dirty ont augmenté, et le lag de réplication a grimpé. Le primaire a tenu, mais une réplique a tellement pris de retard qu’elle a commencé à osciller puis à corrompre son état local après redémarrages répétés.
L’équipe n’a pas tergiversé. Ils ont promu une réplique saine, isolé la réplique défectueuse, et l’ont reconstruite depuis la sauvegarde la plus récente. La procédure de rebuild
était documentée, répétée et suffisamment automatisée pour fonctionner sous pression. L’incident est devenu une leçon sur la performance plutôt qu’un événement catastrophique.
Voilà le point : les « réglages de performance » sont amusants, mais les pratiques opérationnelles gardent la lumière allumée quand un réglage tourne mal.
Erreurs courantes (symptôme → cause racine → correctif)
1) Symptom : pics de latence p99 toutes les quelques minutes
Cause racine : tempêtes de checkpoint/flush (les pages dirty s’accumulent, puis le flushing bloque le travail foreground), souvent amplifiées par un stockage lent ou des IO capacity mal réglés.
Fix : vérifier la latence du stockage ; ajuster innodb_io_capacity et innodb_io_capacity_max pour correspondre au device ; redimensionner les redo logs ; éviter les DDL lourds pendant les pics.
2) Symptom : le débit chute quand le trafic augmente, CPU non pleinement utilisé
Cause racine : contention de verrous (row locks, index chauds, verrous metadata), ou effondrement de l’ordonnancement des threads dû à trop de connexions.
Fix : identifier les bloqueurs via processlist/performance schema ; raccourcir les transactions ; ajouter/ajuster les index ; corriger le pooling ; envisager le thread pool pour contrôle d’admission.
3) Symptom : réplicas laguent de façon imprévisible après les heures de pointe
Cause racine : rafales de binlog dues à de longues transactions ; apply des réplicas limité par l’application single-threaded ou contention de ressources ; lectures lourdes sur la réplique qui privent l’apply.
Fix : réduire les transactions longues ; activer et régler la réplication parallèle si supportée ; isoler les workloads reporting ; s’assurer que la réplique a assez d’IO/CPU.
4) Symptom : « la base est lente » uniquement pendant les sauvegardes
Cause racine : contention IO des sauvegardes ou amplification de snapshot ; l’outil de backup concurrence le cache et la bande passante disque.
Fix : throttler la sauvegarde ; planifier hors-peak ; utiliser des réplicas pour les sauvegardes ; valider que la méthode de backup s’aligne avec le système de fichiers et le stockage.
5) Symptom : usage mémoire qui croît, puis OOM ou thrash de swap
Cause racine : mémoire par connexion multipliée par trop de sessions (sort buffers, tmp tables, join buffers), plus caches surdimensionnés.
Fix : limiter les connexions ; dimensionner correctement les buffers par thread ; utiliser un thread pool ; mesurer l’empreinte mémoire réelle ; éviter le réflexe « augmenter tmp_table_size » sans analyse.
6) Symptom : plans de requête régressent après migration
Cause racine : différences d’optimiseur, comportement des statistiques changé, valeurs par défaut différentes pour modes SQL ou réglages d’engine entre forks/versions.
Fix : exécuter des tests de régression explain sur des données réelles ; épingler des index si nécessaire ; aligner les SQL modes ; ne pas supposer « drop-in » sans tests de charge.
7) Symptom : fsync élevé, commits lents
Cause racine : latence d’écriture du stockage, configuration du sync_binlog, interactions doublewrite et journalisation du système de fichiers, ou contention IO par un voisin bruyant.
Fix : mesurer l’attente device ; assurer la méthode de flush appropriée (souvent O_DIRECT) ; séparer les logs si nécessaire ; upgrader le stockage ou changer la durabilité consciemment.
Listes de contrôle / plan étape par étape
Checklist A : Choisir entre MariaDB et Percona Server pour la production
- Exigence de compatibilité : si un vendor spécifie un support d’une version MySQL, penchez vers Percona Server dans cette ligne majeure MySQL.
- Outillage opérationnel : si vous utilisez déjà les flows Percona toolkit (digests, analyse) et voulez un minimum de dérive de comportement, Percona Server est le chemin à friction réduite.
- Besoin fonctionnel : si des fonctionnalités spécifiques à MariaDB sont requises (modes de réplication précis, options d’engine), acceptez le compromis de compatibilité et testez plus intensément.
- Compétence de l’équipe : si votre équipe débugge avec Performance Schema et connaissance MySQL upstream, Percona Server se mappe plus directement. Si votre équipe exécute déjà MariaDB à grande échelle, ne changez pas pour de l’idéologie.
- Chemin de montée de version : choisissez le fork dont vous pouvez suivre le cadence de mise à jour. Les bases stagnantes sont l’endroit où les « réglages de performance » viennent mourir.
Checklist B : Tuning de performance sûr dans n’importe quel fork (faire dans l’ordre)
- Activer le slow query logging avec des seuils sensés, faire tourner les logs, et construire une habitude de digest hebdomadaire.
- Confirmer le dimensionnement du buffer pool et vérifier que le working set tient ; ne pas deviner — mesurer le churn de lectures dans le temps.
- Valider la latence et l’utilisation du stockage sous charge ; réparer l’IO avant de « tuner la base ».
- Définir la durabilité intentionnellement ; documenter tout compromis et l’aligner avec le risque business.
- Corriger les requêtes principales par temps total, pas par ego. Les requêtes fréquentes « rapides » peuvent être votre vrai centre de coût.
- Éliminer les transactions longues et les DDL surprises pendant les pics. Ils causent des pathologies de verrous et de réplication.
- Contrôler les connexions : pooling, timeouts, circuit breakers ; envisager le thread pooling comme stabilisateur.
- Tester la charge avec des distributions de données proches de la production ; le comportement de l’optimiseur change avec le skew.
Checklist C : Plan de migration (MariaDB ↔ Percona Server) sans jouer la roulette
- Inventaire des dépendances : modes SQL, plugins d’authentification, réglages de réplication, outillage de backup, et exigences vendors.
- Diff des configs : extraire
SHOW VARIABLESdes deux ; identifier les knobs spécifiques au fork ; éliminer les inconnus. - Rejouer la charge : utiliser un staging avec copie du schéma de production + données représentatives ; rejouer les workloads capturés si possible.
- Plan de rollback : procédure de restore testée ou chemin de promotion de réplique ; chronométrez-la, documentez-la, répétez-la.
- Cutover via réplication : établir une réplique sur le nouvel engine, valider les checksums, puis basculer le trafic dans une fenêtre contrôlée.
- Garde-fous post-cutover : serrer max connections, activer slow logs, vérifier la réplication, et surveiller la latence de commit et les waits de verrous.
FAQ
1) Lequel est plus rapide : MariaDB ou Percona Server ?
Aucun de façon fiable, dans le sens que la plupart des gens veulent. Pour de nombreuses charges OLTP, le goulot est l’IO, les verrous ou de mauvaises requêtes, pas le fork.
Choisissez selon la compatibilité, l’opérabilité, et les fonctionnalités que vous utiliserez réellement.
2) Percona Server n’est-il que « MySQL avec des patches » ?
Pratiquement, oui : il vise à rester proche de MySQL upstream tout en ajoutant des améliorations opérationnelles. Cette proximité est souvent l’avantage majeur si vous valorisez
un comportement prévisible et la compatibilité.
3) MariaDB est-elle toujours un remplacement « drop-in » pour MySQL ?
Parfois, pour des applications simples et un appairage de versions soigné. Mais plus le temps passe, plus la divergence pèse.
Considérez « drop-in » comme une hypothèse à tester avec des données réelles et des tests de régression explain, pas comme une promesse.
4) Le thread pool résoudra-t-il mon problème de max_connections élevé ?
Il peut atténuer le meltdown côté serveur en contrôlant la concurrence, mais il ne résoudra pas le comportement applicatif sous-jacent.
Vous avez toujours besoin d’un pooling correct, de timeouts sensés, et de backpressure pour éviter des tempêtes de retry.
5) Les « réglages de performance » concernent-ils majoritairement InnoDB ?
Le meilleur ROI vient généralement du travail sur les requêtes/index et la discipline des connexions. Les réglages InnoDB comptent, mais ils sont d’ordre secondaire
sauf si vous êtes déjà discipliné sur les basiques.
6) Comment savoir si les gains viennent d’une durabilité réduite ?
Vérifiez innodb_flush_log_at_trx_commit et sync_binlog. S’ils sont relaxés, votre benchmark peut sembler excellent parce que vous ne payez pas la persistance à chaque commit.
7) Dois-je activer tous les instruments Performance Schema pour le debug ?
Pas par défaut. Activez ce dont vous avez besoin, échantillonnez de façon responsable, et connaissez l’overhead. Une bonne pratique est une configuration baseline toujours activée,
plus un « mode incident » documenté à activer brièvement.
8) Quelle est la façon la plus simple d’améliorer le lag de réplication ?
Supprimez les transactions longues sur le primaire, réduisez les rafales d’écriture, et donnez suffisamment d’IO/CPU aux réplicas. Ensuite, réglez l’application parallèle si votre
version la supporte et si votre workload peut en tirer parti.
9) Si je suis IO bound, changer de fork est-il inutile ?
Pour la plupart, oui. Les différences de fork ne changent pas la latence de votre device. Investissez dans l’agencement du stockage, le comportement de flush, le checkpointing,
et les patterns d’écriture du workload. Le fork aide pour l’outillage et les garde-fous, pas pour les limites IO de base.
10) Que dois-je standardiser entre environnements pour éviter « c’était plus rapide en staging » ?
La ligne de version MySQL/MariaDB, les variables de config, le schéma et les index, la forme du dataset, et la classe de stockage. Surtout la classe de stockage.
Staging sur NVMe local rapide et production sur disques en réseau est une façon classique d’apprendre l’humilité.
Étapes suivantes réalisables cette semaine
- Exécutez le playbook de diagnostic rapide une fois pendant un pic normal et capturez des bases : vmstat, iostat, lignes clés d’InnoDB status, et digest des slow queries.
- Choisissez les 3 requêtes principales par temps total dans les slow logs et corrigez-les avec des index ou en réduisant la fréquence. Déployez ces changements avant de toucher aux knobs exotiques.
- Auditez les réglages de durabilité et consignez la décision métier. Si vous tournez en durabilité relâchée par accident, vous vivez sur du temps emprunté.
- Limiter et contrôler les connexions : alignez les pools applicatifs avec les cœurs CPU et le budget IO ; arrêtez de traiter
max_connectionscomme stratégie d’échelle. - Décidez du fork selon contraintes : compatibilité vendor et cadence de mise à jour d’abord ; les affirmations « plus rapide » ensuite.
- Répétez une restauration depuis vos sauvegardes. Si vous ne pouvez pas restaurer calmement, vous n’avez pas de sauvegardes — vous avez un espoir coûteux.
Si vous voulez une recommandation franche : choisissez Percona Server quand vous avez besoin de compatibilité upstream MySQL et de prévisibilité opérationnelle.
Choisissez MariaDB quand vous voulez explicitement l’écosystème/fonctionnalités de MariaDB et que vous êtes prêt à tester et assumer la divergence.
Dans les deux cas, la base la plus rapide est celle avec moins de mauvaises requêtes, moins de transactions surprises, et un stockage qui ne ment pas sur sa latence.