Vous ne choisissez pas une base de données dans le vide. Vous la choisissez à 2h13 du matin, avec un téléphone d’astreinte qui vibre, une file d’attente qui s’allonge,
et quelqu’un qui demande pourquoi « la base de données » est lente comme si c’était un seul appareil que l’on peut redémarrer.
Si vous hésitez entre MySQL et TiDB, vous décidez en réalité entre un outil unique, familier et tranchant et
un système distribué qui promet de sembler familier. Les deux peuvent fonctionner. Les deux peuvent vous blesser. La différence est
la douleur que vous choisissez : le plafond de montée en charge et le travail manuel de partitionnement de MySQL,
ou la surface opérationnelle et les modes de défaillance distribués de TiDB.
La décision qui compte vraiment
La plupart des débats « MySQL vs TiDB » font comme si la question portait sur les fonctionnalités. Ce n’est pas le cas. Il s’agit de qui prend en charge
la complexité.
-
MySQL pousse la complexité vers le haut, dans votre application et votre équipe : stratégie de sharding, requêtes inter-shards,
écritures doubles, génération d’IDs, modifications de schéma avec temps d’indisponibilité minimal, gestion de topologie de réplication,
logique de répartition lecture/écriture, et la joie de découvrir que votre jointure « simple » est maintenant une jointure distribuée à travers des shards. -
TiDB tire la complexité vers le bas, dans la plateforme de base de données : règles de placement, réplication Raft,
splits/fusions de régions, ordonnancement PD, coordination des transactions distribuées, hotspots, et mises à jour multi-composants.
Votre code applicatif devient plus simple. Vos runbooks d’astreinte s’épaississent.
Voici l’heuristique pratique que j’utilise :
-
Si vous pouvez faire évoluer MySQL avec des réplicas, du caching, un indexage soigné et des montées en capacité occasionnelles — et que votre plus grande
douleur est la discipline opérationnelle — restez sur MySQL. C’est ennuyeux, éprouvé, et votre équipe sait déjà comment il échoue. -
Si vous avez atteint le point où le sharding est inévitable (ou déjà un bazar), et que vous avez besoin d’une forte cohérence sur
un grand jeu de données avec montée en charge horizontale élastique, TiDB est un pari raisonnable — mais seulement si vous pouvez le gérer comme une plateforme,
pas comme « un nœud de BD entre amis ».
Et oui, TiDB parle le protocole MySQL. C’est le début de la compatibilité, pas la ligne d’arrivée.
Faits et contexte historique qui modifient votre intuition
Quelques ancrages pour garder votre cerveau honnête. Ce ne sont pas des trivia ; ils expliquent pourquoi les systèmes se comportent ainsi.
-
La réplication de MySQL a commencé comme une réplication asynchrone basée sur les statements. Cet héritage explique pourquoi
« le lag de réplication » et les contournements « read-your-writes » sont devenus des connaissances culturelles courantes pour les équipes MySQL. - InnoDB est devenu le moteur de stockage par défaut dans MySQL 5.5. Avant cela, MyISAM était courant, et cette époque a ancré l’idée « MySQL est rapide mais pas sûr » dans la mémoire collective d’internet.
-
Percona et MariaDB sont apparus parce que les opérateurs voulaient une meilleure observabilité et des réglages opérationnels.
L’histoire de l’écosystème MySQL est essentiellement « les SRE ont demandé des outils et ont créé une industrie ». -
Spanner de Google (2012) a fixé des attentes pour « SQL + montée horizontale + forte cohérence ».
TiDB fait partie de la famille de systèmes qui a rendu ce rêve plus accessible sans nécessiter d’horloges atomiques. - La couche de stockage de TiDB (TiKV) est construite sur RocksDB et la réplication Raft. Cela signifie que performance et modes de défaillance ressemblent davantage à un magasin clé/valeur distribué qu’à un moteur B-tree mono-nœud.
- TiDB segmente les données en Régions (plages) et les ordonne via PD. Ce rebalancement de régions est à la fois une superpuissance et une source de moments « pourquoi ma latence a-t-elle sauté ? ».
- GTID et la réplication semi-synchrone de MySQL ont répondu à des douleurs réelles. Ils ont amélioré la fiabilité opérationnelle, mais ne transforment pas MySQL en base SQL distribuée ; ils réduisent juste le rayon d’action des erreurs humaines.
- Les outils de modification de schéma en ligne (gh-ost, pt-online-schema-change) sont devenus mainstream parce que les DDL de MySQL étaient historiquement perturbateurs. Dans TiDB, beaucoup de changements de schéma sont en ligne, mais vous payez encore en travail de cluster et en effets en aval.
- « Compatible MySQL » est une cible mouvante. MySQL lui-même a plusieurs versions majeures, des forks de vendeurs, et des différences de comportement. La compatibilité n’est pas binaire ; c’est une matrice.
MySQL en production : ce qui casse, ce qui scale, ce qui est mensonger
Ce en quoi MySQL est vraiment bon
MySQL est un bon choix quand la charge convient à un seul primaire (ou un petit nombre de primaires) avec des réplicas.
C’est simple à exploiter si vous gardez les choses simples : un seul writer, beaucoup de readers ; requêtes prévisibles ; schéma stable ;
configurations prudentes ; et une équipe qui respecte la base de données comme une ressource partagée, pas comme un distributeur infini.
Pour beaucoup d’entreprises, le « plafond » de MySQL est bien plus haut qu’elles ne le pensent — parce que le vrai goulot d’étranglement était des index manquants,
des transactions énormes, des ORMs bavards, ou une file de jobs qui parcourait des tables entières comme si c’était payé à la ligne.
Où MySQL vous fait payer
L’histoire de montée en charge de MySQL pour les charges d’écriture lourdes est essentiellement : monter en CPU/RAM, affiner, puis shard. Le sharding fonctionne,
mais c’est un engagement. Vous devrez réécrire des hypothèses :
- Les transactions cross-shard deviennent de la coordination applicative ou de la cohérence éventuelle.
- L’unicité globale nécessite des IDs qui ne se chevauchent pas entre shards.
- Les requêtes de reporting deviennent des jobs ETL ou des stores analytiques.
- Le travail opérationnel se déplace vers la gestion de nombreuses bases plus petites, les sauvegardes et les migrations de schéma.
Les modes de défaillance de MySQL sont bien compris : lag de réplication, contention sur les verrous, pression sur le buffer pool, blocages d’IO disque,
et « une requête a ruiné la journée de tout le monde ». L’avantage est que la plupart des ingénieurs ont déjà vu ça. Le désavantage est que les équipes normalisent souvent ces problèmes et cessent de remettre en question les choix d’architecture.
Juste une blague, comme promis : MySQL est comme un couteau de cuisine — excellent jusqu’à ce que quelqu’un décide que c’est aussi un tournevis.
TiDB en production : ce que vous gagnez, ce que vous héritez
Ce en quoi TiDB est vraiment bon
L’argument de TiDB est séduisant parce qu’il répond à la douleur classique de MySQL : monter sans sharding manuel tout en gardant
SQL et transactions. En pratique, les gains sont réels lorsque :
- Votre jeu de données et le débit d’écritures dépassent un seul primaire et vous voulez une montée horizontale.
- Vous avez besoin de sémantiques de cohérence forte sans construire votre propre logique cross-shard.
- Vous pouvez tolérer la surcharge opérationnelle de l’exploitation d’un système distribué.
- Vous devez augmenter la capacité en ajoutant des nœuds plutôt qu’en planifiant de grosses montées matérielles.
Ce que TiDB vous fait payer
TiDB n’est pas « MySQL, mais plus rapide ». C’est une base de données distribuée avec une interface compatible MySQL. Vous allez maintenant exécuter :
- TiDB couche SQL sans état (scale-out).
- TiKV couche de stockage avec état (répliquée par Raft, basée sur des régions).
- PD placement driver (le cerveau du cluster pour l’ordonnancement et les métadonnées).
- Souvent TiFlash pour l’accélération analytique et les workloads HTAP.
Chaque composant a ses propres points de saturation, métriques, chemins de mise à jour, et états « techniquement en bonne santé mais effectivement dégradés ».
TiDB facilite la montée en charge ; il ne simplifie pas les opérations. Il transfère la complexité du sharding applicatif vers l’ordonnancement et la coordination au niveau plateforme.
Vous optez aussi pour un autre type d’ajustement des performances : moins de « taille du buffer pool et nostalgie du query cache »,
plus de « hotspots de régions, tâches coprocessor et latence raftstore ».
Compatibilité MySQL : les détails qui mordent
La compatibilité de protocole n’est pas la compatibilité de comportement
Beaucoup de migrations commencent par « notre appli parle MySQL, donc TiDB devrait être plug-and-play ». C’est vrai jusqu’au moment où votre appli
dépend d’un comportement de coin de cas. La plupart des applis le font, elles ne le savent juste pas encore.
Les écarts de compatibilité apparaissent en quatre endroits pratiques :
-
Grammaire SQL et fonctions : certaines fonctions diffèrent, d’autres manquent, et certaines se comportent subtilement
différemment dans des cas limites. -
Transactions et sémantiques de verrouillage : les transactions distribuées ne se comportent pas exactement comme le verrouillage sur une seule instance
sous forte contention. - DDL et métadonnées : le « DDL en ligne » est super jusqu’à ce qu’il génère une charge en arrière-plan pour laquelle vous n’avez pas budgété.
- Hypothèses opérationnelles : dans MySQL, vous pouvez parfois « simplement redémarrer mysqld » pour débloquer un état. Dans TiDB, redémarrer un composant peut déclencher un rescheduling ou des élections de leader — c’est acceptable, mais pas gratuit.
Cohérence : la simplicité de MySQL vs la coordination de TiDB
MySQL avec un unique primaire fournit un modèle mental clair : le primaire décide. Les réplicas suivent. La cohérence forte est locale au primaire ; les lectures depuis les réplicas sont « peut-être obsolètes », et tout le monde apprend à vivre avec.
TiDB vise la cohérence forte sur un cluster distribué. Cela signifie :
- Les écritures doivent atteindre un quorum de réplicas pour les groupes Raft (Régions).
- Les transactions peuvent impliquer plusieurs Régions, potentiellement sur plusieurs nœuds.
- Les jitter réseau et les nœuds de stockage lents deviennent la latence des requêtes de façons nouvelles et créatives.
Surprises de performance : la « taxe distribuée »
Certaines requêtes deviennent plus rapides dans TiDB parce que vous pouvez étendre le calcul et le stockage. D’autres ralentissent parce qu’une requête qui
était une recherche locale d’index dans MySQL devient une opération distribuée impliquant plusieurs Régions.
C’est là que vous devez être brutalement honnête sur la forme de votre charge de travail :
- Recherches point par clé primaire peuvent être excellentes, mais des hotspots peuvent se former si de nombreux clients frappent la même plage de clés.
- Grands scans de plage peuvent être décents s’ils sont parallélisés, mais ils peuvent aussi déclencher une lourde charge coprocessor.
- Jointures sont l’endroit où il faut être attentif. La planification des jointures distribuées et la qualité des statistiques comptent davantage.
Complexité opérationnelle : ce que TiDB ajoute à votre pager
Vous exploitez une plateforme de base de données
Avec MySQL, l’unité d’exploitation est un serveur (ou un cluster avec un primaire). Avec TiDB, l’unité d’exploitation est un système. Vous allez gérer :
- Mises à niveau rolling à travers plusieurs composants
- Gestion de capacité entre calcul, stockage et réseau
- Domaines de défaillance (racks/AZ), règles de placement, et nombre de réplicas
- Détection et atténuation des hotspots
- Sauvegarde/restauration qui respecte la cohérence distribuée
- Modifications de schéma qui déclenchent une réorganisation des données en arrière-plan
L’observabilité n’est pas optionnelle
Dans MySQL, vous pouvez aller étonnamment loin avec les slow query logs, performance_schema, et des métriques basiques d’hôte. Dans TiDB,
vous avez besoin d’observabilité au niveau du cluster : santé PD, latence des stores TiKV, balance des régions, durée d’application raft, et saturation de la couche SQL.
Voici la vérité opérationnelle : si vous n’avez pas de bonnes métriques et des alertes, TiDB continuera de fonctionner — jusqu’à ce qu’il ne fonctionne plus — et
alors votre timeline d’incident ressemblera à de l’art abstrait.
Une citation (idée paraphrasée)
Idée paraphrasée : Si vous ne pouvez pas le mesurer, vous ne pouvez pas l’améliorer de façon fiable.
— attribuée à W. Edwards Deming
Juste une citation, parce que c’est ainsi que fonctionne la fiabilité : portée limitée, responsabilité claire.
Tâches pratiques avec commandes, sorties et décisions (hands-on)
La façon la plus rapide de comprendre la complexité opérationnelle est de la toucher. Ci‑dessous des tâches concrètes que j’attends d’un SRE ou DBRE lors de la planification d’une migration ou d’un incident. Chacune inclut : une commande, une sortie d’exemple, ce que ça signifie, et la décision que vous en tirez.
Task 1: Check MySQL replication lag (are reads trustworthy?)
cr0x@server:~$ mysql -h mysql-replica-01 -e "SHOW REPLICA STATUS\G" | egrep "Seconds_Behind_Source|Replica_IO_Running|Replica_SQL_Running"
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Seconds_Behind_Source: 37
Signification : le réplica est sain mais a ~37s de retard. Toute lecture « après écriture » depuis ce réplica peut être obsolète.
Décision : orientez les lectures critiques vers le primaire (ou un réplica à faible latence), ou corrigez le lag avant d’utiliser les réplicas pour des chemins sensibles à la cohérence.
Task 2: Find top MySQL wait events (is it locks, IO, or CPU?)
cr0x@server:~$ mysql -e "SELECT EVENT_NAME, SUM_TIMER_WAIT/1e12 AS seconds_waited FROM performance_schema.events_waits_summary_global_by_event_name ORDER BY SUM_TIMER_WAIT DESC LIMIT 5;"
EVENT_NAME seconds_waited
wait/io/file/innodb/innodb_data_file 1843.22
wait/synch/mutex/innodb/buf_pool_mutex 912.45
wait/lock/table/sql/handler 211.10
wait/io/file/sql/binlog 199.08
wait/synch/cond/sql/MYSQL_BIN_LOG::COND_done 133.57
Signification : IO fichier InnoDB lourd et contention sur le buffer pool. Vous n’êtes pas « CPU bound » ; vous attendez.
Décision : vérifiez la latence du stockage, la taille du buffer pool, et les tables chaudes. Si c’est chronique à votre échelle, TiDB peut aider — si votre workload se comporte comme des shards.
Task 3: Identify MySQL queries with worst 95th percentile latency
cr0x@server:~$ pt-query-digest /var/log/mysql/mysql-slow.log --limit 3
# 1.2s user time, 60ms system time, 22.18M rss, 221.20M vsz
# Rank Query ID Response time Calls R/Call V/M Item
# ==== ================== ============= ===== ====== ===== ====
# 1 0x8D7A... 521.7340 38.4% 120 4.3478 0.02 SELECT orders
# 2 0x44B1... 301.0092 22.1% 560 0.5375 0.01 UPDATE inventory
# 3 0xA1E3... 198.5521 14.6% 45 4.4123 0.00 SELECT users
Signification : deux SELECTs lents dominent le temps de réponse ; un UPDATE est également coûteux et fréquent.
Décision : optimisez schéma et requêtes d’abord. Migrer une requête lente vers TiDB la rendra simplement lente sur plus de serveurs.
Task 4: Inspect MySQL table/index size (are you IO-bound due to bloat?)
cr0x@server:~$ mysql -e "SELECT table_schema, table_name, ROUND((data_length+index_length)/1024/1024/1024,2) AS gb FROM information_schema.tables WHERE table_schema='app' ORDER BY (data_length+index_length) DESC LIMIT 5;"
table_schema table_name gb
app events 412.77
app orders 188.34
app order_items 141.02
app users 62.11
app inventory 51.89
Signification : vous avez quelques tables très volumineuses. Elles dominent l’IO et la pression sur le buffer pool.
Décision : envisagez le partitionnement, l’archivage, ou un stockage secondaire pour les données froides. Si l’accès est large et à fort débit d’écritures, le stockage horizontal de TiDB peut aider.
Task 5: Check TiDB cluster health (is the platform stable?)
cr0x@server:~$ tiup cluster display tidb-prod
Cluster type: tidb
Cluster name: tidb-prod
Cluster version: v7.5.1
ID Role Host Ports OS/Arch Status Data Dir
-- ---- ---- ----- ------- ------ --------
tidb-01 tidb 10.0.2.11 4000/10080 linux/x86_64 Up /tidb-data/tidb-4000
pd-01 pd 10.0.2.21 2379/2380 linux/x86_64 Up /tidb-data/pd-2379
tikv-01 tikv 10.0.3.31 20160/20180 linux/x86_64 Up /tidb-data/tikv-20160
tikv-02 tikv 10.0.3.32 20160/20180 linux/x86_64 Up /tidb-data/tikv-20160
tikv-03 tikv 10.0.3.33 20160/20180 linux/x86_64 Up /tidb-data/tikv-20160
Signification : tous les composants sont up. Cela n’assure pas la performance, mais écarte une panne de nœud comme problème primaire.
Décision : si un TiKV ou PD est down, arrêtez d’optimiser le SQL et rétablissez la santé du cluster en priorité.
Task 6: Verify PD health and leader (is the brain confused?)
cr0x@server:~$ tiup ctl:v7.5.1 pd -u http://10.0.2.21:2379 member
{
"members": [
{
"name": "pd-01",
"member_id": 1234567890,
"client_urls": ["http://10.0.2.21:2379"],
"peer_urls": ["http://10.0.2.21:2380"]
}
],
"leader": {
"name": "pd-01",
"member_id": 1234567890
}
}
Signification : PD est ici mono-membre ; c’est le leader. En production, on veut généralement plusieurs nœuds PD pour la HA.
Décision : si PD n’est pas HA, corrigez l’architecture avant de parier l’entreprise sur le cluster.
Task 7: Check TiKV store capacity and balance (are you about to fall off a cliff?)
cr0x@server:~$ tiup ctl:v7.5.1 pd -u http://10.0.2.21:2379 store
{
"count": 3,
"stores": [
{"store": {"id": 1, "address": "10.0.3.31:20160"}, "status": {"capacity": "3.6TiB", "available": "0.4TiB"}},
{"store": {"id": 2, "address": "10.0.3.32:20160"}, "status": {"capacity": "3.6TiB", "available": "0.3TiB"}},
{"store": {"id": 3, "address": "10.0.3.33:20160"}, "status": {"capacity": "3.6TiB", "available": "0.2TiB"}}
]
}
Signification : tous les stores manquent d’espace libre. La compaction, les snapshots et le rebalancing deviennent plus risqués près de disques pleins.
Décision : ajoutez de la capacité avant d’optimiser la performance. « Presque plein » dans le monde RocksDB est la façon dont vous planifiez votre propre coupure.
Task 8: Find TiDB slow queries quickly (are we dealing with plan regressions?)
cr0x@server:~$ mysql -h tidb-01 -P 4000 -e "SELECT time, query_time, digest, left(query,120) AS sample FROM information_schema.cluster_slow_query ORDER BY query_time DESC LIMIT 3;"
time query_time digest sample
2025-12-30T09:40:11Z 8.214 9f2d... SELECT * FROM orders WHERE user_id=... ORDER BY created_at DESC LIMIT 50
2025-12-30T09:41:02Z 6.882 2a11... SELECT COUNT(*) FROM events WHERE created_at BETWEEN ... AND ...
2025-12-30T09:41:33Z 5.477 0bd3... UPDATE inventory SET qty=qty-1 WHERE sku=...
Signification : vous avez des requêtes lentes similaires à MySQL, mais vous devez maintenant examiner l’exécution distribuée (tâches coprocessor, régions touchées, etc.).
Décision : récupérez les plans d’exécution et vérifiez la fraîcheur des statistiques. Si cela coïncide avec un changement de schéma ou de version, soupçonnez une régression de plan.
Task 9: Explain a TiDB query and spot distributed pain (Index? coprocessor? scatter?)
cr0x@server:~$ mysql -h tidb-01 -P 4000 -e "EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id=42 ORDER BY created_at DESC LIMIT 50\G"
*************************** 1. row ***************************
id: TopN_10
actRows: 50
task: root
execution info: time:1.2s, loops:2
operator info: order by:created_at, offset:0, count:50
*************************** 2. row ***************************
id: IndexLookUp_21
actRows: 5000
task: root
execution info: time:1.1s, loops:5
operator info: index:idx_user_created(user_id,created_at), table:orders
*************************** 3. row ***************************
id: IndexRangeScan_19
actRows: 5000
task: cop[tikv]
execution info: time:980ms, loops:8
operator info: range:[42,42], keep order:true
Signification : la majeure partie du temps est passée dans les tâches cop sur TiKV. Cela indique une latence de stockage, un hotspot, ou trop de régions impliquées.
Décision : inspectez la latence TiKV, la distribution des régions pour cette plage d’index, et si la charge crée un hotspot sur des clefs comme user_id=42.
Task 10: Check region hotspots (is one key range melting a store?)
cr0x@server:~$ tiup ctl:v7.5.1 pd -u http://10.0.2.21:2379 hot read
{
"as_peer": {
"stats": [
{"store_id": 3, "region_id": 918273, "hot_degree": 97, "flow_bytes": 125829120}
]
}
}
Signification : le store 3 sert une région très chaude en lecture. Cela peut dominer la latence tail.
Décision : atténuez le hotspot : ajoutez des nœuds TiDB pour l’échelle SQL, envisagez de splitter les régions, ajustez les patterns d’accès applicatifs, ou utilisez du caching pour cette plage de clefs chaude.
Task 11: Check TiKV latency via Prometheus text endpoint (is storage the bottleneck?)
cr0x@server:~$ curl -s http://10.0.3.33:20180/metrics | egrep "tikv_engine_write_stall|rocksdb_compaction_pending_bytes" | head
tikv_engine_write_stall 1
rocksdb_compaction_pending_bytes 2.184532e+10
Signification : write stall est actif et l’arriéré de compaction est énorme. RocksDB est en retard ; écritures et lectures vont en souffrir.
Décision : cessez de blâmer le SQL. Réparez le débit disque, réduisez l’amplification d’écriture, revoyez les options TiKV, et envisagez d’ajouter des stores pour répartir la charge de compaction.
Task 12: Validate time sync (distributed transactions hate sloppy clocks)
cr0x@server:~$ chronyc tracking
Reference ID : C0A80101 (ntp-01)
Stratum : 3
System time : 0.000143219 seconds slow of NTP time
Last offset : -0.000012034 seconds
RMS offset : 0.000084321 seconds
Frequency : 10.123 ppm slow
Residual freq : -0.002 ppm
Skew : 0.090 ppm
Root delay : 0.001234 seconds
Root dispersion : 0.001901 seconds
Update interval : 64.0 seconds
Leap status : Normal
Signification : l’horloge est bien synchronisée (décalages sous la milliseconde). Bien. Une mauvaise synchronisation crée des comportements bizarres de transactions et de timeouts dans les systèmes distribués.
Décision : si les offsets sont importants ou le leap status incorrect, corrigez NTP/chrony avant de courir après des pics de latence fantômes.
Task 13: Validate TiDB transaction conflicts (are you fighting contention?)
cr0x@server:~$ mysql -h tidb-01 -P 4000 -e "SHOW STATUS LIKE 'tikv_txn_mvcc_%conflict%';"
Variable_name Value
tikv_txn_mvcc_conflict_counter 18422
tikv_txn_mvcc_write_conflict_counter 12011
Signification : des conflits se produisent. Sous des workloads à lignes chaudes, TiDB se comportera comme tout système consistant : il force une sérialisation quelque part.
Décision : repensez les patterns de lignes chaudes (compteurs, mises à jour « last seen »), batcher les écritures, ou déplacez les primitives à forte contention vers un autre store.
Task 14: Check MySQL disk latency (is the host lying to you?)
cr0x@server:~$ iostat -x 1 3 | egrep "Device|nvme0n1"
Device r/s w/s r_await w_await aqu-sz %util
nvme0n1 210.4 980.2 3.12 18.44 9.87 99.10
nvme0n1 198.1 1050.6 2.88 21.77 11.22 99.54
nvme0n1 205.7 1012.3 3.05 19.90 10.45 99.33
Signification : %util saturé ; latence d’écriture ~20ms. C’est suffisant pour rendre la vie misérable à la fois à MySQL et à TiKV.
Décision : avant de migrer, réparez le stockage : isolez les workloads, mettez à jour les disques, vérifiez les réglages RAID/controlleur, et réduisez l’amplification d’écriture.
Task 15: Check network retransmits (distributed systems magnify network sins)
cr0x@server:~$ netstat -s | egrep "segments retransmited|packet receive errors" | head
13245 segments retransmited
0 packet receive errors
Signification : des retransmissions existent ; si c’est « mauvais » dépend de la baseline et de la fenêtre temporelle, mais dans TiDB cela peut se manifester comme une latence raft et des pics p99.
Décision : corrélez avec la fenêtre d’incident. Si les retransmissions montent, investigatez les drops NIC, la sursouscription, ou les voisins bruyants.
Task 16: Confirm TiDB node saturation (SQL layer scale-out is a lever)
cr0x@server:~$ top -b -n 1 | head -n 12
top - 09:45:11 up 34 days, 3:21, 1 user, load average: 24.12, 21.88, 19.05
Tasks: 312 total, 2 running, 310 sleeping, 0 stopped, 0 zombie
%Cpu(s): 92.1 us, 3.4 sy, 0.0 ni, 3.9 id, 0.0 wa, 0.0 hi, 0.6 si, 0.0 st
MiB Mem : 64384.0 total, 1200.3 free, 45210.8 used, 17972.9 buff/cache
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
22411 tidb 20 0 14.1g 3.2g 112m S 860.2 5.1 12:11.43 tidb-server
Signification : le nœud SQL TiDB est CPU-hot. Étant donné que la couche SQL de TiDB est sans état, vous pouvez souvent mettre à l’échelle horizontalement ce tier.
Décision : ajoutez des nœuds TiDB ou réduisez les requêtes coûteuses ; ne blâmez pas immédiatement TiKV si TiDB est déjà en train de fondre.
Playbook de diagnostic rapide (vérifs 1/2/3)
Quand la latence s’élève ou que le débit chute, vous voulez identifier le goulot d’étranglement sans réinventer la théorie des systèmes distribués sur un tableau blanc pendant un incident.
Premier : confirmez le rayon d’action et quelle couche est chaude
- Est-ce toutes les requêtes ou des endpoints spécifiques ? Si c’est un seul endpoint, soupçonnez un plan de requête, des stats, ou un hotspot de table — pas « le cluster ».
- Vérifiez la saturation de la couche SQL : CPU TiDB, nombre de connexions, threadpool. Dans MySQL, vérifiez le CPU du primaire et les threads actifs.
- Vérifiez les taux d’erreur/timeouts : les timeouts précèdent souvent les métriques de saturation visibles.
Second : vérifiez la latence de stockage et compaction/backpressure
- MySQL : iostat, longueur de la history list InnoDB, taux de hit du buffer pool, latence fsync.
- TiDB/TiKV : bytes en attente de compaction RocksDB, write stalls, durée d’application raftstore, utilisation disque des stores.
Troisième : vérifiez les pathologies de distribution
- Régions chaudes : une région unique domine les lectures/écritures.
- Déséquilibre des leaders : un store possède trop de leaders.
- Réseau : retransmissions, perte de paquets, ou latences inter-AZ surprenantes.
- Stats et régressions de plan : changements soudains de plan après un déploiement/DDL/analyze.
Si vous faites ces vérifications dans l’ordre, vous trouvez généralement le goulot rapidement. Si vous les faites dans le désordre, vous pouvez passer des heures à tuner le SQL pendant qu’un nœud de stockage est en train de s’étouffer.
Trois mini-récits d’entreprise issus du terrain
Mini-récit 1 : L’incident causé par une mauvaise hypothèse
Une entreprise SaaS de taille moyenne a migré un service lié aux paiements de MySQL vers TiDB. L’application utilisait le protocole MySQL et passait les tests d’intégration. Tout le monde a célébré. L’équipe a planifié la bascule un mardi parce que mardi « ce n’est pas une journée chargée », ce que les gens disent juste avant que le mardi ne devienne chargé.
La mauvaise hypothèse était simple : ils ont supposé que leur chemin de lecture était sûr en exécutant des transactions en REPEATABLE READ avec des transactions de longue durée. Dans MySQL, leur pattern était « ouvrir une transaction, lire quelques choses, appeler quelques services internes, puis écrire ». C’était lent, mais tenable sur un primaire et quelques réplicas.
Sur TiDB, le même pattern a créé un entassement de verrous de transaction et de conflits durant un pic de trafic. La coordination des transactions distribuées a amplifié ce qui était auparavant une contention légère en pics de latence p99 et timeouts de requêtes, ce qui a aggravé la contention à cause des retries. Une tempête de retries est une prophétie auto-réalisatrice avec un meilleur logging.
La correction n’a pas été exotique. Ils ont raccourci la portée des transactions, retiré les appels réseau depuis l’intérieur des transactions BD, et rendu la logique « lire puis écrire » idempotente avec des contraintes uniques appropriées. Après cela, TiDB a bien fonctionné. La compatibilité n’a jamais été le problème ; c’étaient leurs habitudes transactionnelles.
Mini-récit 2 : L’optimisation qui s’est retournée contre eux
Une autre entreprise faisait tourner MySQL sur NVMe haut de gamme et, lors d’une revue de performance, quelqu’un a suggéré « ajoutons plus d’index pour accélérer les lectures ». Ils ont ajouté plusieurs indexes composites sur une grande table d’événements. Les lectures se sont améliorées sur un dashboard. Tout le monde a hoché la tête. Puis le chemin d’écriture a commencé à glisser.
Le retour de bâton était classique : le pipeline d’ingestion était à forte écriture, et chaque index transformait chaque insert en une amplification d’écriture additionnelle. InnoDB passait plus de temps à maintenir les index secondaires qu’à faire le travail réel. Le binlog a grossi, le lag de réplication a augmenté, et l’équipe a commencé à router plus de lectures vers le primaire « temporairement », ce qui a rendu le primaire encore plus occupé. « Temporairement » est la façon dont les pannes deviennent des habitudes.
Ils ont tenté de « résoudre » le problème en migrant vers TiDB, en s’attendant à ce que la montée horizontale efface le problème. Ce ne fut pas le cas. TiDB a distribué l’amplification d’écriture sur les nœuds TiKV, mais a aussi augmenté la pression de compaction. Le cluster est resté en ligne, mais la latence tail a dérivé pendant les pics d’ingestion.
La solution finale fut ennuyeuse : supprimer les index à faible valeur, introduire des tables rollup pour les requêtes de dashboard, et déplacer certains workloads analytiques vers TiFlash. La leçon n’était pas « les index sont mauvais ». C’était : optimiser sans comprendre votre chemin d’écriture est du sabotage avec de bonnes intentions.
Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une troisième organisation utilisait TiDB pour une charge orientée client et MySQL pour plusieurs outils internes. Leur cluster TiDB avait une pratique stricte : des game days trimestriels et des exercices de restauration mensuels. Pas « on a restauré une fois en staging », mais « on peut restaurer un snapshot cohérent et démarrer l’appli dessus ».
Un matin, un déploiement a introduit un bug subtil : un job d’arrière-plan a écrit des données incorrectes dans une table critique. Le bug n’était pas immédiatement évident. Il passait les tests unitaires et ne se manifestait que sous certaines distributions de données. Au moment où il a été détecté, des écritures incorrectes avaient eu lieu pendant des heures.
Parce qu’ils s’étaient entraînés, l’équipe n’a pas paniqué en mutuant la production. Ils ont arrêté le job, pris un snapshot d’incident pour le forensics, et restauré un point-in-time connu bon depuis une sauvegarde dans un cluster parallèle. Ensuite, ils ont rejoué un sous-ensemble nettoyé d’écritures correctes. Le service est resté partiellement disponible, et l’impact client a été limité.
Personne n’a reçu d’applaudissements pour « on a fait des exercices de restauration ». Mais ça a marché parce que c’était ennuyeux. La fiabilité est rarement intelligente. C’est surtout répétition et refus de sauter les étapes agaçantes.
Erreurs courantes : symptôme → cause racine → correctif
1) Symptom: “TiDB is slow” only for one tenant or one user_id
Cause racine : hotspot sur une plage de clés étroite (une Région, un seul leader) dû à des IDs monotoniquement croissants ou des patterns d’accès par tenant.
Correctif : repensez les clés (préfixe de hachage, scatter), activez une stratégie de split de régions, ajoutez du caching, ou séparez les tenants chauds. Confirmez avec les sorties PD hot region.
2) Symptom: p99 latency spikes during peak writes; CPU looks fine
Cause racine : arriéré de compaction RocksDB et write stalls sur TiKV ; le stockage ne suit pas l’amplification d’écriture.
Correctif : augmentez le débit disque, ajoutez des nœuds TiKV, réduisez le nombre d’index, batcher les écritures, réexaminez les paramètres de compaction et les choix de compression.
3) Symptom: MySQL primary looks healthy but replicas lag unpredictably
Cause racine : grosses transactions, rafales d’écritures, ou réplicas limités par l’IO ; parfois l’application SQL mono-thread devient le goulot.
Correctif : éclatez les transactions, ajustez le parallélisme de réplication, réduisez le churn du binlog (indexes, row format), et validez la latence stockage sur les réplicas.
4) Symptom: Deadlocks or lock timeouts increase after moving to TiDB
Cause racine : longues transactions et lignes à forte contention deviennent plus coûteuses dans les chemins de commit distribués ; les retries amplifient la charge.
Correctif : raccourcissez les transactions, évitez les patterns « select puis update », utilisez des patterns de concurrence optimistes, et faites des retries avec jitter et limites.
5) Symptom: Schema change causes cluster-wide latency and elevated IO
Cause racine : le DDL en ligne déclenche toujours du travail en arrière-plan (backfill/reorg) et augmente la charge lecture/écriture sur TiKV.
Correctif : planifiez les DDL en période basse, limitez leur débit si possible, assurez-vous d’un headroom, et surveillez les métriques TiKV de compaction/raft apply pendant le DDL.
6) Symptom: After migration, some queries return different results
Cause racine : dépendance à des comportements spécifiques à MySQL : casts implicites, différences de collation, usage non déterministe de GROUP BY, ou tri non défini sans ORDER BY.
Correctif : explicitez le SQL : ORDER BY approprié, modes SQL stricts quand possible, casts explicites, vérifiez les collations, ajoutez des tests pour les requêtes cas limites.
7) Symptom: TiDB cluster “healthy” but throughput drops after a node failure
Cause racine : réélection de leaders et rebalancing ont changé la distribution des leaders ; les stores survivants sont surchargés.
Correctif : assurez-vous d’un headroom de capacité, utilisez des règles de placement alignées sur les domaines de défaillance, et rééquilibrez les leaders. Validez avec les sorties PD store et hot region.
8) Symptom: MySQL is “fine” until backups run, then everything crawls
Cause racine : contention IO liée aux sauvegardes et overhead des snapshots ; les outils de backup concurrencent l’IO de production et le cache.
Correctif : exécutez les sauvegardes depuis des réplicas, limitez l’IO des backups, planifiez hors pics, isolez le trafic/storage des backups, et vérifiez régulièrement la capacité de restauration.
Listes de contrôle / plan étape par étape
Checklist A: When you should stay on MySQL (and sleep better)
- Votre primaire tient dans une seule grosse machine et le write QPS n’explose pas.
- Vous pouvez utiliser des réplicas, du caching, et tuning des requêtes/index pour atteindre vos SLO.
- Vous n’avez pas besoin d’une cohérence forte entre plusieurs primaires.
- Votre équipe n’est pas dotée pour exploiter une base distribuée 24/7.
- Vous acceptez la staleness des réplicas pour les lectures non critiques.
Checklist B: When TiDB is a rational move (not a resume-driven one)
- Vous shardiez déjà MySQL ou êtes sur le point de le faire, et ça devient un risque produit.
- Vous avez besoin d’une montée horizontale avec sémantiques transactionnelles.
- Vous pouvez vous engager à fournir observabilité, formation d’astreinte, et discipline de mise à jour.
- Vous pouvez provisionner suffisamment de nœuds pour garder du headroom (calcul et stockage).
- Vous avez un plan pour les hotspots, pas seulement un espoir.
Step-by-step migration plan (pragmatic version)
- Inventaire des « MySQL-isms » dans votre appli : modes SQL, casts implicites, dépendance à un ordre non défini, fonctions non standard.
- Performance de référence : requêtes top par latence et par temps total ; tailles de transaction ; débit d’écriture de pointe.
- Concevez pour la contention : identifiez lignes chaudes, compteurs, et patterns « last updated » ; repensez avant la migration.
- Provisionnez TiDB avec headroom : ne commencez pas à « juste assez ». Les systèmes distribués punissent les marges serrées.
- Décidez placement et domaines de défaillance : réplicas à travers AZs/racks ; quorum PD ; nombre TiKV.
- Testez la charge avec des données et de la skew proches de la production : une charge synthétique uniforme est la façon dont vous manquez les hotspots.
- Exécutez des lectures duales avec prudence : comparez les résultats pour les requêtes critiques ; surveillez différences de collation/cast.
- Planifiez la bascule avec rollback : soit écritures duales avec vérification, soit fenêtre de gel contrôlée.
- Faites des exercices de restauration avant la mise en production : une sauvegarde sans restauration est du théâtre.
- Formez l’astreinte : « qu’est-ce qu’un hotspot de région » ne doit pas être découvert pendant un incident.
- Après la bascule, geler DDL et changements de tuning : observez un comportement stable avant d’« optimiser ».
- Définissez des alertes pilotées par SLO : latence et taux d’erreur d’abord, puis signaux de saturation (CPU, compaction, équilibre des leaders).
Deuxième et dernière blague : une base de données distribuée est comme une base de données normale, sauf qu’elle peut échouer à plusieurs endroits en même temps.
FAQ
1) Is TiDB really “drop-in” for MySQL applications?
Plug-and-play pour le protocole et de nombreux patterns SQL, oui. Plug-and-play pour le comportement, non. Supposez que vous trouverez des cas limites :
collations, casts implicites, patterns de portée de transaction, et différences de performance sous des workloads skewés.
2) If I’m not sharding today, should I still move to TiDB “to be safe”?
Généralement non. Si MySQL satisfait vos SLO avec des pratiques opérationnelles saines, restez. TiDB est un mouvement stratégique quand le sharding
ou les besoins multi-primaire deviennent un risque produit inévitable.
3) Will TiDB automatically fix my slow queries?
Il peut aider si votre goulot est la capacité d’une seule instance et que la requête se parallélise bien. Il ne réparera pas les index manquants, les mauvais patterns de requête, ou les transactions gigantesques. En fait, l’exécution distribuée peut rendre certaines mauvaises requêtes plus coûteuses.
4) What’s the most common TiDB performance failure mode in real life?
Hotspots et backpressure stockage. Les hotspots concentrent la charge sur quelques régions/stores. Le backpressure apparaît comme un arriéré de compaction RocksDB et des write stalls, qui se répercutent ensuite en latence de requête.
5) What’s the most common MySQL performance failure mode in real life?
Contention sur les verrous et stalls IO, souvent déclenchés par une requête « innocente » ou une migration exécutée au mauvais moment. Le lag de réplication est le second qui casse silencieusement des hypothèses de cohérence.
6) How do backups differ operationally?
Les sauvegardes MySQL sont conceptuellement plus simples : un dataset primaire, plus des réplicas. Les backups TiDB doivent capturer la cohérence distribuée à travers les stores. Dans les deux cas, le seul test significatif est la restauration et l’exécution de l’application dessus.
7) Can TiDB replace read replicas and read/write splitting?
TiDB peut faire monter les lectures en ajoutant des nœuds TiDB, et il peut aussi utiliser des followers dans certaines configurations. Mais vous devez toujours réfléchir à l’endroit où la charge atterrit : CPU couche SQL, hotspots TiKV, et réseau. Ce n’est pas « pas de splitting », c’est « un splitting différent ».
8) What about schema changes—easier in TiDB?
Souvent plus faciles du point de vue de la disponibilité applicative, parce que beaucoup de DDL sont en ligne. Mais ils génèrent toujours un travail en arrière-plan qui peut dégrader la performance si vous n’avez pas de headroom et une bonne observabilité.
9) Do I need a dedicated platform team to run TiDB?
Vous n’avez pas besoin d’une énorme équipe, mais vous avez besoin d’une responsabilité claire, de compétences d’astreinte, et d’une culture de répétition. Si votre organisation traite les bases comme des animaux choyés, TiDB deviendra un animal de compagnie coûteux avec des opinions.
10) What’s a reasonable pilot approach?
Commencez par un service avec des patterns d’accès clairs, une bonne couverture de tests, et du SQL peu « clever ». Miroitez le trafic pour les lectures, validez les résultats, puis migrez progressivement les chemins d’écriture avec un plan de rollback.
Conclusion : étapes pratiques suivantes
Si vous retenez une chose : MySQL et TiDB sont tous deux des bases sérieuses. La différence est l’endroit où la complexité vit
et comment elle échoue sous contrainte.
-
Si vous êtes sur MySQL : faites d’abord le travail ingrat — hygiène des index, discipline sur la portée des transactions,
monitoring du lag de réplica, et restaurations testées. Vous pouvez gagner des années sans migration. -
Si vous évaluez TiDB : lancez un pilote représentatif. Validez non seulement la correction fonctionnelle
mais la latence tail sous skew, le comportement des hotspots, et ce qui arrive lors d’une perte de nœud et de mises à jour rolling. - Si vous migrez déjà : supposez qu’il existe des écarts de compatibilité et chassez-les délibérément. Supprimez les longues transactions, explicitez le SQL, et construisez un playbook d’incident avant que la production n’en crée un pour vous.
Choisissez le système dont vous pouvez diagnostiquer rapidement les modes de défaillance, dont le travail opérationnel peut être honnêtement assumé par vos équipes, et dont l’histoire « simple » tient encore à pleine charge. C’est le choix d’adulte.