Diagnostiquer et résoudre les problèmes courants de latence de réplication MongoDB
Naviguez dans les complexités de la latence de réplication MongoDB avec ce guide complet. Apprenez à identifier, diagnostiquer et résoudre les problèmes courants qui compromettent la cohérence des données et la haute disponibilité de vos jeux de réplicas. L'article couvre tout, de la compréhension de l'oplog et de la détection de la latence avec `rs.status()` aux solutions pratiques pour une taille d'oplog insuffisante, des goulots d'étranglement réseau, des contraintes de ressources et des index manquants. Équipez-vous de stratégies actionnables et de meilleures pratiques pour maintenir un environnement MongoDB sain, performant et résilient.
Diagnostiquer et résoudre les problèmes courants de latence de réplication MongoDB
La latence de réplication MongoDB n'est pas qu'un simple chiffre sur un tableau de bord. Elle modifie le comportement de votre application. Un utilisateur met à jour un profil, une autre requête lit depuis un secondaire, et l'ancienne valeur revient. Un nœud échoue, mais le meilleur secondaire est encore en retard, donc le basculement prend plus de temps que prévu. Une requête de rapport atterrit sur le mauvais membre et soudainement le jeu de réplicas semble sain sauf pour un secondaire qui continue de s'éloigner du primaire.
La manière utile de penser à la latence de réplication est simple : le primaire produit des entrées d'oplog plus rapidement qu'un ou plusieurs secondaires ne peuvent les récupérer et les appliquer. La correction dépend du côté de cette phrase qui est vrai dans votre environnement. Parfois, le primaire écrit trop en rafales. Parfois, le secondaire est sous-alimenté. Parfois, le réseau est lent. Parfois, la latence est intentionnelle car le membre est configuré avec secondaryDelaySecs. Votre première tâche est de séparer ces cas avant d'apporter des modifications.
Commencez par la forme réelle de la latence
Ne commencez pas par redimensionner l'oplog ou redémarrer mongod. Découvrez d'abord si la latence est stable, en pics, limitée à un seul membre, ou affecte tous les secondaires.
Dans mongosh, commencez par :
rs.status()
Regardez les champs stateStr, optimeDate, lastHeartbeatMessage et health de chaque membre. Si un secondaire est en retard et que les autres sont à jour, vous avez probablement un problème spécifique au membre : disque, CPU, lectures locales, maintenance locale, ou un mauvais chemin réseau. Si tous les secondaires sont en retard, examinez plus attentivement le volume d'écriture du primaire, le débit réseau sortant du primaire, ou une opération inhabituellement volumineuse.
Pour une vérification rapide de la fenêtre d'oplog, exécutez :
rs.printReplicationInfo()
La fenêtre d'oplog vous indique combien de temps est couvert par l'oplog actuel. Cela ne signifie pas que la réplication est saine. Cela indique jusqu'à quel point un secondaire peut être en retard avant de risquer de nécessiter une synchronisation initiale. Si votre fenêtre d'oplog est de 6 heures et que vos fenêtres de maintenance prennent généralement 8 heures, vous avez un risque opérationnel réel même lorsque la latence actuelle est nulle.
Pour les secondaires, ceci est également utile :
rs.printSecondaryReplicationInfo()
Dans les exemples plus anciens, vous pouvez voir rs.printSlaveReplicationInfo(). La terminologie plus récente utilise "secondary", mais les anciens aides shell et les anciens articles de blog peuvent encore utiliser "slave". Les champs sont plus importants que le nom.
Si vous voulez un petit script pour un shell en direct, comparez l'optime du primaire avec chaque secondaire :
const status = rs.status();
const primary = status.members.find(m => m.stateStr === "PRIMARY");
status.members
.filter(m => m.stateStr === "SECONDARY")
.forEach(m => {
const lagSeconds = (primary.optimeDate - m.optimeDate) / 1000;
print(`${m.name}: ${lagSeconds}s behind primary`);
});
Considérez cela comme un instantané, pas un diagnostic. Un secondaire qui a 20 secondes de retard lors d'une importation par lots peut être acceptable s'il rattrape rapidement. Un secondaire qui a toujours 20 secondes de retard pendant un trafic normal mérite une attention particulière.
Vérifiez si la latence est intentionnelle
Avant de poursuivre un faux incident, inspectez la configuration du jeu de réplicas :
rs.conf()
Un membre retardé est configuré pour suivre le primaire par conception. Dans la configuration MongoDB moderne, recherchez secondaryDelaySecs sur un membre. Ce membre est utile pour certains scénarios de récupération car il peut préserver une vue plus ancienne des données pendant une courte période. Il ne doit pas être utilisé pour des lectures fraîches, et son retard attendu doit être exclu des alertes de latence normales.
L'erreur que je vois dans les opérations réelles est d'alerter sur chaque membre retardé comme s'il était cassé. Alertez sur le retard au-delà du retard configuré. Si un membre est retardé de 1 heure et affiche 1 heure et 5 minutes de latence, la latence réelle est d'environ 5 minutes.
Quand la fenêtre d'oplog est trop petite
L'oplog est une collection plafonnée dans la base de données local. Les secondaires la lisent et appliquent les opérations dans l'ordre. Si un secondaire prend suffisamment de retard pour que le primaire n'ait plus les entrées d'oplog nécessaires, le rattrapage ordinaire n'est plus possible. Le membre a généralement besoin d'une synchronisation initiale ou d'une restauration à partir d'une sauvegarde appropriée.
C'est pourquoi la fenêtre d'oplog est importante. Vous voulez qu'elle couvre plus que vos temps d'arrêt attendus, maintenance, interruption réseau et pics d'écriture. Il n'y a pas de taille d'oplog "correcte" universelle. Un cluster calme peut conserver des jours d'historique dans un petit oplog. Un cluster occupé avec des mises à jour lourdes peut brûler la même taille en peu de temps.
Si la fenêtre d'oplog rétrécit pendant les heures de pointe, augmentez-la avant la prochaine fenêtre de maintenance. Sur les versions MongoDB prises en charge, utilisez replSetResizeOplog plutôt que de supprimer et recréer local.oplog.rs. Supprimer l'oplog sur un membre d'un jeu de réplicas est une manœuvre de récupération à haut risque, pas une étape de réglage normale.
Exécutez la commande de redimensionnement sur le membre dont vous voulez redimensionner l'oplog :
use admin
db.adminCommand({ replSetResizeOplog: 1, size: 10240 })
La valeur size est en mégaoctets. Une valeur de 10240 signifie environ 10 Go. Redimensionnez chaque membre selon les besoins. Dans les environnements gérés comme MongoDB Atlas, utilisez le chemin de configuration pris en charge par la plateforme au lieu de supposer un contrôle direct du système de fichiers ou des processus.
Après le redimensionnement, vérifiez la nouvelle fenêtre sous charge d'écriture réelle. Un oplog plus grand réduit la probabilité de tomber de l'oplog, mais il ne fait pas appliquer les opérations plus rapidement par un secondaire lent.
Quand un secondaire est lent
Si un seul secondaire est en retard, connectez-vous à cet hôte et examinez les symptômes système ordinaires. MongoDB est souvent blâmé pour ce qui est en réalité une saturation du disque.
Utilisez des outils tels que :
iostat -xz 1
vmstat 1
top
mongostat --host secondary.example.com:27017
mongotop --host secondary.example.com:27017
Une utilisation élevée du disque, des temps d'attente élevés ou une longue file d'attente d'E/S signifient généralement que le secondaire ne peut pas écrire assez rapidement. Cela peut se produire lorsqu'un type d'instance moins cher est utilisé pour les secondaires, lorsque le stockage EBS ou réseau a un débit provisionné inférieur, ou lorsque les sauvegardes et les instantanés du système de fichiers s'exécutent en même temps que les écritures d'application de pointe.
Le CPU peut également être important, surtout avec la compression, le chiffrement, les déplacements de documents, la maintenance des index ou une charge de travail avec de nombreuses petites mises à jour. La pression mémoire se manifeste par des défauts de page, un renouvellement du cache et un secondaire qui continue de lire depuis le disque tout en essayant d'appliquer les entrées d'oplog.
La correction pratique est généralement ennuyeuse : donnez au secondaire un stockage et un CPU comparables à ceux du primaire, réduisez le travail concurrent sur cet hôte, ou déplacez les lectures lourdes ailleurs. Un membre d'un jeu de réplicas n'est pas une capacité de rapport gratuite. Il doit toujours suivre la réplication.
Quand les lectures sur les secondaires causent le problème
La mise à l'échelle des lectures avec les secondaires est utile, mais il est facile d'en faire trop. Une requête de tableau de bord qui scanne une grande collection peut concurrencer l'application de l'oplog. Le secondaire peut encore accepter des lectures, mais la réplication prend du retard car le même CPU, cache et disque sont utilisés pour les requêtes utilisateur.
Vérifiez le profileur et les opérations en cours sur le membre en retard :
db.currentOp({ active: true })
Si vous voyez de longues lectures, des travaux d'agrégation ou des scripts de maintenance, décidez si ce secondaire devrait vraiment servir cette charge de travail. Pour les rapports, un secondaire caché ou dédié peut être un meilleur choix. Pour les lectures d'application, définissez maxStalenessSeconds pour que le pilote évite les secondaires trop en retard.
Pour les chemins critiques en termes de cohérence, utilisez les lectures primaires. Les exemples incluent l'état de connexion, la confirmation de commande, les changements de mot de passe, les paramètres de compte et tout ce où un utilisateur s'attend à lire sa propre écriture immédiatement. Les lectures secondaires sont les meilleures pour les données où une brève obsolescence est acceptable.
Quand le primaire produit des rafales
Les grandes écritures peuvent faire paraître les secondaires sains comme cassés. Les importations en masse, les mises à jour larges de plusieurs documents, le nettoyage TTL, les grandes suppressions et les changements d'index peuvent produire une rafale d'activité d'oplog qui prend du temps à appliquer.
Recherchez les opérations récentes sur le primaire :
db.currentOp({ active: true })
Vérifiez également les déploiements d'application, les travaux de réparation de données, les remplissages et les tâches planifiées. La latence de réplication qui commence exactement à 02:00 n'est souvent pas mystérieuse. C'est un travail par lots.
Lorsque vous contrôlez le travail, divisez-le en morceaux plus petits. Par exemple, mettez à jour les documents par plages de _id, faites une pause entre les lots et surveillez la latence pendant que le travail s'exécute. Avec bulkWrite, les écritures non ordonnées peuvent améliorer le débit, mais la gestion des erreurs doit être explicite car les échecs peuvent être partiels. L'objectif n'est pas toujours de faire terminer le primaire aussi rapidement que possible. L'objectif est de permettre au jeu de réplicas d'absorber le travail sans perdre sa marge de récupération.
Index et application de l'oplog
Dans un jeu de réplicas normal, les index sont répliqués. Si les index diffèrent entre les membres en raison d'un travail manuel, d'une maintenance échouée ou d'un nœud restauré incorrectement, un secondaire peut devenir douloureusement lent à appliquer les mises à jour et les suppressions. L'opération d'oplog peut avoir besoin de trouver un document, et sans l'index attendu, le secondaire peut faire beaucoup plus de travail que le primaire.
Comparez les définitions d'index sur les collections affectées :
db.orders.getIndexes()
Exécutez la même commande sur le primaire et le secondaire en retard. S'ils diffèrent, découvrez pourquoi avant d'apporter d'autres modifications. Reconstruire un grand index peut lui-même créer de la charge, donc planifiez-le pendant une période calme ou reconstruisez le membre à partir d'une source fiable si la divergence est large.
N'utilisez pas de vieux conseils disant que les constructions d'index en arrière-plan résolvent tous les problèmes de réplication. Le comportement de construction d'index de MongoDB a changé selon les versions, et le choix opérationnel correct dépend de votre version et de votre topologie. Utilisez la documentation actuelle du serveur pour la version exacte que vous exécutez.
Les problèmes réseau sont généralement visibles ailleurs
La latence réseau a tendance à se manifester par des battements de cœur instables, des erreurs intermittentes ou un faible débit entre des hôtes ou régions spécifiques. Les vérifications de base aident toujours :
ping primary.example.com
traceroute primary.example.com
Mais une faible latence de ping ne prouve pas une bande passante suffisante. La réplication peut être limitée par le débit, la perte de paquets, l'inspection du pare-feu, les liens inter-régions ou un réseau partagé bruyant. Si la latence n'apparaît que pour un secondaire distant, comparez-la avec un secondaire dans la même région que le primaire. Si les membres de la même région sont corrects et que le membre distant est en retard, la topologie peut demander trop au lien.
Pour les jeux de réplicas inter-régions, soyez honnête sur le compromis. Ils peuvent aider à la reprise après sinistre, mais ils sont plus exposés aux limites de latence et de bande passante. Si le membre distant est destiné aux lectures, utilisez des contrôles d'obsolescence et testez le comportement de basculement au lieu de supposer qu'il se comportera comme un secondaire local.
Soyez prudent avec les conseils de redémarrage et de resynchronisation
Redémarrer mongod peut résoudre un problème transitoire, mais cela peut aussi aggraver un incident si le nœud était proche de tomber de l'oplog. Avant un redémarrage, vérifiez la fenêtre d'oplog et la latence actuelle. Si le nœud a besoin de deux heures pour rattraper et que la fenêtre d'oplog n'est que de trois heures pendant le trafic de pointe, un long redémarrage peut vous laisser avec une synchronisation initiale au lieu d'un rattrapage.
La synchronisation initiale est une option de réparation valide lorsqu'un secondaire est obsolète, corrompu ou manque de l'historique d'oplog nécessaire. Elle est également coûteuse. Elle copie les données, construit des index et consomme des ressources réseau et disque des sources de synchronisation. En production, préférez ajouter ou reconstruire un membre à la fois pour que le jeu de réplicas conserve suffisamment de membres votants et porteurs de données pour tolérer les pannes.
Si un membre est si loin derrière qu'il ne peut pas rattraper, prenez une nouvelle sauvegarde ou un chemin basé sur un instantané qui correspond à vos normes opérationnelles. Ne supprimez pas un répertoire de données parce qu'une liste de contrôle le dit. Confirmez que le membre est jetable, confirmez que le jeu de réplicas peut tolérer la reconstruction, et confirmez que vous avez suffisamment de fenêtre d'oplog ou une source de synchronisation initiale fiable.
Alertez sur ce qui importe aux utilisateurs et aux opérateurs
Une bonne alerte n'est pas "la latence de réplication est supérieure à 1 seconde" pour chaque système. Certaines applications peuvent tolérer 30 secondes sur les lectures d'analyse. D'autres ne peuvent pas tolérer des lectures obsolètes sur l'état du compte. Les seuils d'alerte doivent refléter le cas d'utilisation.
Les alertes utiles incluent :
- Latence de réplication au-dessus de la tolérance de l'application pendant une période soutenue.
- Fenêtre d'oplog en dessous de l'intervalle de maintenance ou de récupération le plus long attendu.
- Un secondaire dans un état
RECOVERING,STARTUP2ou malsain plus longtemps que prévu. - Saturation des E/S disque sur tout membre porteur de données.
- Échecs de battement de cœur ou erreurs réseau entre les membres.
Les tableaux de bord doivent montrer la latence à côté du volume d'écriture, de la latence disque, du CPU, de la pression mémoire et du débit réseau. La latence seule vous dit qu'il y a un problème. Les graphiques voisins vous disent généralement quel problème.
Un ordre de triage pratique
Lorsque vous êtes d'astreinte, utilisez cet ordre :
- Confirmez quels membres sont en retard avec
rs.status(). - Vérifiez si une latence est intentionnelle à cause de
secondaryDelaySecs. - Vérifiez la fenêtre d'oplog avec
rs.printReplicationInfo(). - Comparez la latence avec les pics d'écriture, les travaux par lots et les déploiements récents.
- Inspectez le disque, le CPU, la mémoire et la charge de requêtes locales du secondaire en retard.
- Vérifiez les erreurs réseau et la latence entre les membres affectés.
- Décidez si le membre peut rattraper, a besoin de retirer la charge, a besoin de plus de ressources, ou doit être reconstruit.
Le meilleur résultat n'est généralement pas une commande dramatique. C'est trouver le goulot d'étranglement et le supprimer sans créer de divergence de données. La latence de réplication MongoDB est gérable lorsque vous la traitez comme un signal de capacité et de topologie, et non comme un échec générique de MongoDB.