Seconds_Behind_Master n'est pas un health check de réplica
Pourquoi le seul retard de réplication peut dire qu'un réplica va bien alors que non, et comment vérifier les réplicas MySQL et MariaDB par GTID et checksum.

Le réplica depuis lequel vous restaureriez ne vaut quelque chose que s'il est à jour, cohérent et hors de portée d'un attaquant. La plupart des supervisions vérifient un seul chiffre, le retard de réplication, et ce chiffre peut afficher zéro sur un réplica qui a cessé de recevoir des changements il y a une heure. Voici comment vérifier un réplica MySQL ou MariaDB pour que la réponse veuille dire quelque chose.
Le problème du chiffre de retard
Seconds_Behind_Master (ou Seconds_Behind_Source sur les MySQL récents) est calculé par le thread SQL du réplica : la différence entre l'horodatage de l'événement qu'il applique et l'heure courante. Il ne sait rien des événements qu'il n'a pas reçus.
Donc si le thread I/O qui récupère les changements depuis le primaire est bloqué sur une connexion TCP semi-ouverte, le thread SQL termine tout ce qu'il a déjà et rapporte 0. Le réplica a l'air parfait. Pendant ce temps, il a cessé d'avancer. Le chiffre affiche aussi NULL quand la réplication est arrêtée, et beaucoup de vérifications traitent NULL comme « aucun retard ».
Vérification un : les deux threads, et les champs d'erreur
Le premier test est ennuyeux et attrape la plupart des problèmes :
SHOW SLAVE STATUS\G -- or SHOW REPLICA STATUS\G
Exigez Slave_IO_Running: Yes et Slave_SQL_Running: Yes (les noms en Replica_ sur les MySQL récents), et exigez que Last_IO_Error et Last_SQL_Error soient vides. Connecting sur le thread I/O n'est pas « en marche », c'est un réplica qui ne peut pas atteindre sa source.
Fixez aussi un slave_net_timeout court (ou replica_net_timeout) avec MASTER_HEARTBEAT_PERIOD sur le canal de réplication. Le primaire envoie alors des heartbeats quand il est inactif, et une connexion morte est détectée en quelques secondes au lieu d'attendre l'expiration du timeout réseau par défaut.
Vérification deux : comparez les positions, pas les horodatages
Avec la réplication GTID, chaque transaction validée a un identifiant, et vous pouvez comparer directement où en est le primaire et où en est le réplica.
Sur MariaDB :
-- on the primary
SELECT @@gtid_binlog_pos;
-- on the replica
SELECT @@gtid_slave_pos;
Sur MySQL, comparez @@gtid_executed des deux côtés, ou demandez directement au réplica s'il a rattrapé un ensemble :
SELECT WAIT_FOR_EXECUTED_GTID_SET('<primary gtid_executed>', 5);
Quand la position du primaire continue d'avancer et que celle du réplica non, vous avez un réplica bloqué, quoi que dise le chiffre de retard. Cette comparaison est aussi la façon dont vous terminez un réensemencement ou une bascule : les deux côtés doivent s'accorder sur la même transaction avant que quiconque ne déclare le travail fini.
Vérification trois : un heartbeat que vous écrivez vous-même
La mesure de retard la plus honnête est une ligne que le primaire met à jour avec sa propre horloge, relue sur le réplica. pt-heartbeat de Percona Toolkit fait exactement cela :
# on the primary, as a service
pt-heartbeat --update --database percona --create-table --daemonize
# on the replica, from monitoring
pt-heartbeat --check --database percona --master-server-id <id>
Parce que la mesure voyage à travers la réplication elle-même, un thread I/O cassé apparaît comme un retard qui croît régulièrement, ce que vous vouliez voir dès le départ. Une écriture de test sur le primaire suivie d'une lecture sur le réplica donne la même preuve à la main, et c'est la vérification d'acceptation la plus rapide pour un nouveau réplica.
Vérification quatre : les données sont-elles réellement les mêmes ?
La réplication peut tourner joyeusement par-dessus des données qui ont dérivé, après une instruction qui se comporte différemment de chaque côté, une écriture faite par erreur sur le réplica, ou un type de table qui ne se réplique pas sûrement. pt-table-checksum calcule des sommes de contrôle par morceaux sur le primaire et laisse la réplication les porter jusqu'au réplica, puis rapporte les tables qui diffèrent :
pt-table-checksum --replicate=percona.checksums --no-check-binlog-format h=<primary>
Lancez-le selon un calendrier adapté à votre volume d'écritures, en heures creuses. Mettez read_only = ON sur chaque réplica (et super_read_only = ON sur MySQL) pour que rien, pas même l'outil d'un administrateur, ne puisse y écrire par accident.
Vérification cinq : dans quel sens va la connexion
Celle-ci ne concerne pas du tout le retard. Un réplica est votre copie de reprise, donc il doit être le côté qui tend la main. Le réplica ouvre la connexion de réplication vers le primaire ; le primaire ne doit avoir aucun chemin réseau vers le réplica.
Testez-le plutôt que de le supposer. Depuis le primaire :
nc -vz -w 3 <replica-address> 3306
Cela doit expirer. Si cela se connecte, un attaquant qui possède votre serveur de production peut aussi atteindre la copie depuis laquelle vous comptez vous relever. Nous imposons la direction sur les appliances firewall, pas sur les hôtes, et nous le prouvons à chaque construction.
Alertez sur l'état, pas sur chaque échantillon
Rassemblez tout ce qui précède en un seul état par réplica : OK, LAGGING (au-dessus d'un seuil convenu), ou BROKEN (un thread arrêté, une erreur positionnée, ou la position GTID figée pendant que le primaire avance). Puis alertez seulement quand l'état change, y compris le retour à OK.
state=$(replica_state) # your check, returns OK, LAGGING or BROKEN
last=$(cat /var/lib/replcheck/state 2>/dev/null)
if [ "$state" != "$last" ]; then
notify "replica: $last -> $state"
echo "$state" > /var/lib/replcheck/state
fi
Lancez-le toutes les quelques minutes depuis un timer. Les ingénieurs reçoivent un message quand quelque chose change et un quand cela se rétablit, pas un flux qu'ils apprennent à ignorer. Le vrai risque avec les réplicas n'est pas le retard ; c'est un réplica arrêté depuis des semaines sans que personne ne s'en aperçoive.
Réensemencer sans tâtonner
Quand un réplica doit vraiment être reconstruit, le GTID supprime la chasse aux coordonnées du journal binaire. Un dump logique cohérent avec la position embarquée, ou une sauvegarde physique avec Mariabackup ou Percona XtraBackup, vous donne la transaction exacte d'où repartir. Sur MariaDB, le côté réplica se réduit à :
SET GLOBAL gtid_slave_pos = '<position from the dump or backup>';
CHANGE MASTER TO MASTER_HOST='<primary>', MASTER_USER='repl',
MASTER_PASSWORD='<secret>', MASTER_USE_GTID=slave_pos;
START SLAVE;
Puis relancez les vérifications un à trois et ne validez pas tant que les deux côtés ne rapportent pas le même GTID après une écriture de test.
Votre liste de contrôle
- Les deux threads de réplication en marche, champs d'erreur vides, une période de heartbeat fixée sur le canal.
- Positions GTID du primaire et du réplica comparées, pas seulement le chiffre de retard.
- Une ligne de heartbeat ou une écriture de test prouvant que les changements arrivent réellement.
- Des sommes de contrôle planifiées, et
read_onlysur chaque réplica. - Le primaire ne peut pas ouvrir de connexion vers le réplica, prouvé depuis le primaire.
- Des alertes sur les changements d'état, pour qu'un réplica bloqué soit un message en quelques minutes, pas une découverte le jour où vous en avez besoin.
Si vous souhaitez un second regard sur vos réplicas, c'est le genre de travail que nous aimons.
Related (rows[1])
Voir aussi : Réplication de bases de données et réplicas hors site · Bases de données en cluster avec Percona XtraDB Cluster · Migrations de datacenter infogérées, répétées
Publié le 8 octobre 2026.
Toutes les notes de terrain