Dépannage du retard de réplication MongoDB : causes et solutions

Apprenez à diagnostiquer et résoudre le retard de réplication dans les ensembles de réplicas MongoDB. Ce guide couvre les causes courantes, notamment les charges d'écriture élevées, les goulots d'étranglement matériels et les problèmes réseau. Découvrez des techniques de surveillance exploitables utilisant `rs.printReplicationInfo()` et des solutions pratiques pour maintenir la synchronisation des données, garantissant une haute disponibilité et une cohérence de lecture sur tous vos nœuds de base de données.

Dépannage du retard de réplication MongoDB : causes et solutions

Le retard de réplication MongoDB commence généralement comme une petite gêne opérationnelle. Un graphique commence à monter. Un secondaire prend du retard de 15 secondes, puis de 2 minutes. Quelqu'un demande si les lectures sont obsolètes. Quelqu'un d'autre suggère de redémarrer le nœud. Avant de faire cela, ralentissez et déterminez quelle partie de la réplication perd du terrain.

Les secondaires MongoDB copient les opérations de l'oplog du primaire et les appliquent localement. Un retard de réplication signifie qu'un secondaire n'a pas appliqué les opérations aussi récemment que le primaire. Cela peut affecter les lectures secondaires, les sauvegardes effectuées à partir des secondaires, les tâches d'analyse et le basculement. Cela peut également cacher un risque plus important : si le secondaire prend trop de retard par rapport à la fenêtre de l'oplog, il pourrait ne pas être en mesure de rattraper son retard à partir de l'oplog du tout.

Le chemin de dépannage le plus rapide consiste à répondre à trois questions :

  • Est-ce que chaque secondaire est en retard, ou un seul ?
  • Le retard est-il temporaire, stable ou croissant ?
  • Le secondaire est-il toujours dans la fenêtre de l'oplog ?

Ces réponses déterminent ce que vous faites ensuite.

Mesurer le retard sans deviner

Commencez dans mongosh :

rs.status()

Trouvez le primaire et comparez son optimeDate avec celui de chaque secondaire. Recherchez également les membres malsains, les messages de pulsation et les membres bloqués dans des états tels que RECOVERING ou STARTUP2.

Pour un résumé plus convivial, exécutez :

rs.printSecondaryReplicationInfo()

Certains documents plus anciens utilisent rs.printSlaveReplicationInfo(). Si vous maintenez des systèmes plus anciens, vous pouvez encore voir cette aide. Le terme moderne est "secondary".

Ensuite, vérifiez la fenêtre de l'oplog :

rs.printReplicationInfo()

La fenêtre de l'oplog est la quantité d'historique actuellement conservée dans l'oplog. Si votre secondaire a 40 minutes de retard et que la fenêtre de l'oplog est de plusieurs jours, vous avez de la marge pour dépanner. Si votre secondaire a 40 minutes de retard et que la fenêtre de l'oplog est d'une heure pendant les heures de pointe, vous êtes proche d'une situation de reconstruction.

Ne vous fiez pas uniquement aux valeurs de type SecondsBehind provenant d'un seul outil. Le décalage horaire, les membres retardés et les brèves rafales peuvent rendre un nombre trompeur. Comparez la sortie de l'état avec les graphiques de surveillance pour le volume d'écriture, la latence du disque, le processeur et le débit réseau.

Si tous les secondaires sont en retard

Lorsque chaque secondaire prend du retard à peu près au même moment, la cause est généralement en amont d'un secondaire particulier. Examinez d'abord la charge de travail d'écriture du primaire.

Les déclencheurs courants incluent :

  • Importations en masse ou reconstitutions.
  • Opérations volumineuses updateMany ou deleteMany.
  • Nettoyage TTL après une période d'arriéré.
  • Déploiements d'applications qui ont modifié le volume d'écriture.
  • Constructions d'index ou maintenance de schéma.
  • Une augmentation soudaine des petites écritures qui créent de nombreuses entrées d'oplog.

Demandez ce qui a changé au moment où le retard a commencé. Un pic qui commence exactement lorsqu'un travail nocturne démarre est rarement un mystère MongoDB.

Sur le primaire, inspectez les opérations actives :

db.currentOp({ active: true })

Si vous trouvez un travail par lots, envisagez de le limiter au lieu de le laisser se terminer à vitesse maximale. Par exemple, traitez les documents par plages _id, mettez en pause entre les lots et surveillez le retard. Ceci est particulièrement utile pour les travaux de nettoyage où terminer en 30 minutes est moins important que de maintenir l'ensemble de réplicas en bonne santé.

Si le volume d'écriture soutenu est simplement plus élevé que ce que l'ensemble de réplicas peut gérer, vous avez besoin d'un changement de capacité ou d'architecture. De meilleurs disques, plus de processeur, une classe d'instance différente, une optimisation du chemin d'écriture ou un sharding peuvent être la bonne réponse. Changer la préférence de lecture ne résoudra pas un primaire qui produit plus de travail que l'ensemble ne peut en appliquer.

Si un seul secondaire est en retard

Un seul secondaire en retard indique généralement un problème local. Connectez-vous à cet hôte et vérifiez les bases :

iostat -xz 1
vmstat 1
top

À l'intérieur de MongoDB, utilisez :

mongostat --host secondary.example.com:27017
mongotop --host secondary.example.com:27017

Le disque est un coupable courant. Un secondaire utilisant un stockage plus lent que le primaire peut fonctionner correctement pendant le trafic normal, puis prendre du retard pendant les rafales. Les volumes cloud peuvent également atteindre des plafonds de débit ou d'IOPS. Recherchez une utilisation élevée, des temps d'attente élevés et des files d'attente.

Le processeur peut être important lorsque la charge de travail comprend de nombreuses mises à jour, de la compression, du chiffrement ou un trafic de requêtes lourd sur le même membre. La pression mémoire est importante lorsque le secondaire ne peut pas conserver les données et les index chauds dans le cache tout en appliquant les écritures.

Vérifiez également ce qui s'exécute d'autre sur l'hôte. Les sauvegardes, les analyses antivirus, les instantanés du système de fichiers, la compression des journaux et les requêtes de rapport peuvent tous concurrencer la réplication. Si le nœud en retard est également le "lieu sûr" où tout le monde exécute des analyses ad-hoc, vous avez probablement trouvé le problème.

Les lectures sur les secondaires peuvent créer un retard

Les lectures secondaires ne sont pas gratuites. Elles utilisent le même cache, le même processeur et le même disque dont la réplication a besoin. Une seule agrégation qui analyse une grande collection peut suffire à faire prendre du retard à un secondaire pendant une période chargée.

Recherchez les lectures de longue durée :

db.currentOp({ active: true })

Si l'application envoie des lectures aux secondaires, examinez la préférence de lecture. secondary peut forcer les lectures vers des membres en retard. secondaryPreferred peut toujours renvoyer des données obsolètes. Pour les flux utilisateur qui doivent lire leurs propres écritures, utilisez le primaire. Pour les lectures éventuellement cohérentes, définissez maxStalenessSeconds afin que le pilote évite les secondaires trop en retard.

Pour les charges de travail de reporting, envisagez un secondaire caché ou un pipeline d'analyse séparé. Les membres cachés peuvent toujours se répliquer, mais les pilotes ne les choisiront pas pour les lectures normales. Cela en fait un meilleur endroit pour les sauvegardes ou les travaux de reporting contrôlés, à condition de les dimensionner correctement.

La taille de l'oplog est une marge de récupération, pas une solution de vitesse

Un oplog trop petit ne cause généralement pas de retard en soi. Il rend le retard dangereux. Si un secondaire prend du retard et que les entrées d'oplog nécessaires sont écrasées, il ne peut pas rattraper son retard normalement.

Votre fenêtre d'oplog doit être plus longue que vos scénarios réalistes de panne et de maintenance. Si un secondaire peut être hors ligne pendant 6 heures lors d'une mise à jour corrective, une fenêtre d'oplog de 4 heures n'est pas suffisante. Si une importation trimestrielle épuise l'oplog en quelques heures, dimensionnez pour cette charge de travail ou modifiez la façon dont l'importation s'exécute.

Sur les versions prises en charge, redimensionnez avec replSetResizeOplog sur chaque membre qui a besoin d'un oplog plus grand :

use admin
db.adminCommand({ replSetResizeOplog: 1, size: 20480 })

Cet exemple demande environ 20 Go. Sur les plateformes gérées, utilisez la méthode de configuration gérée. Évitez les anciens conseils qui suppriment et recréent l'oplog, sauf si vous suivez une procédure de récupération soigneusement testée.

Après avoir augmenté l'oplog, continuez à dépanner le retard sous-jacent. Un oplog plus grand vous donne plus de temps ; il ne supprime pas la saturation du disque, les limites réseau ou les rafales d'écriture excessives.

Vérifications réseau qui aident réellement

Les problèmes réseau sont plus probables lorsque le retard affecte un secondaire distant, une zone de disponibilité ou un chemin de centre de données. Commencez simplement :

ping primary.example.com
traceroute primary.example.com

Ensuite, regardez au-delà de la latence. La réplication a besoin d'un débit fiable. La perte de paquets, l'inspection du pare-feu, les limites VPN, les plafonds de bande passante inter-régions ou les interfaces réseau surchargées peuvent créer un retard même lorsque le ping semble acceptable.

Si seul le membre inter-région est en retard, comparez-le avec un secondaire local sous la même charge d'écriture. Vous pouvez avoir besoin d'une topologie différente, d'une liaison plus grande ou d'une attente plus claire que les membres distants sont destinés à la reprise après sinistre plutôt qu'à des lectures fraîches.

Dérive des données et des index

Les membres de l'ensemble de réplicas doivent avoir les mêmes index. Si ce n'est pas le cas, l'application de l'oplog peut ralentir ou échouer. Cela provient généralement de modifications manuelles, d'une maintenance échouée ou d'un membre restauré à partir d'une source incohérente.

Comparez les index sur les collections chaudes :

db.orders.getIndexes()

Exécutez-le sur le primaire et sur le secondaire en retard. Si les définitions diffèrent, corrigez la dérive délibérément. La reconstruction d'un grand index peut ajouter plus de charge, alors planifiez-la soigneusement ou reconstruisez le membre à partir d'une source propre si les différences sont généralisées.

La divergence des données est plus grave. Si les erreurs de réplication montrent des enregistrements manquants ou des clés en double, le retard n'est plus le seul problème. Vous devez inspecter l'erreur, comparer les données et décider si une réparation au niveau de la table, une resynchronisation ou une reconstruction complète est la voie la plus sûre.

Soyez prudent avec les redémarrages et la synchronisation initiale

Redémarrer un secondaire en retard aide parfois si le processus est bloqué derrière un problème transitoire. Ce n'est pas une solution universelle. Si le membre est proche du bord de la fenêtre de l'oplog, un redémarrage peut coûter suffisamment de temps pour le pousser dans un état irrécupérable.

Avant de redémarrer, vérifiez :

  • Le retard actuel.
  • La fenêtre actuelle de l'oplog.
  • Si le membre est en cours de synchronisation.
  • Si d'autres secondaires sains existent.
  • Si l'ensemble de réplicas peut tolérer que le membre soit hors service.

La synchronisation initiale est la réponse propre lorsqu'un secondaire ne peut pas rattraper son retard ou que ses données ne sont pas fiables. Elle est également lourde. Elle copie les données, construit les index et consomme les ressources d'un autre membre. Reconstruisez un membre à la fois et assurez-vous que votre configuration de vote prend toujours en charge des élections sûres pendant la reconstruction du nœud.

Quand vous ne devriez pas vous précipiter pour le réparer

Un certain retard est attendu pendant un travail contrôlé. Si vous exécutez une reconstitution planifiée, restaurez un secondaire ou importez des données historiques, la question utile est de savoir si le secondaire rattrape son retard à un rythme acceptable. Un graphique de retard qui augmente pendant 20 minutes puis diminue régulièrement peut ne pas nécessiter d'intervention. Un graphique de retard qui augmente chaque jour et ne revient jamais à la ligne de base, oui.

Cette distinction est importante car certaines solutions sont perturbatrices. Tuer un travail par lots peut laisser les données d'application à moitié mises à jour. Redémarrer un secondaire peut coûter la chaleur du cache et ralentir le rattrapage. Reconstruire un membre peut consommer plus de réseau et de disque que simplement le laisser appliquer l'arriéré.

Pour les travaux planifiés, définissez un budget de retard avant le début du travail. Par exemple, vous pouvez décider qu'une reconstitution de maintenance peut créer jusqu'à 10 minutes de retard sur un secondaire de rapport, mais pas sur un candidat au basculement. Surveillez le retard, la fenêtre de l'oplog et le taux d'écriture pendant l'exécution du travail. Si le travail approche du budget, mettez-le en pause ou réduisez la taille du lot.

Il est également utile de séparer les réplicas destinés aux utilisateurs des réplicas de maintenance. Un secondaire utilisé pour les lectures d'application doit avoir une tolérance de retard plus stricte qu'un membre caché utilisé pour les sauvegardes. Si chaque secondaire a un travail différent, les seuils d'alerte doivent refléter ces travaux au lieu d'utiliser un seul nombre pour l'ensemble.

Ce qu'il faut enregistrer lors d'un incident

Les incidents de réplication sont beaucoup plus faciles à comprendre après coup si vous enregistrez les bonnes preuves. Avant de modifier la configuration, capturez :

rs.status()
rs.conf()
rs.printReplicationInfo()
rs.printSecondaryReplicationInfo()

Enregistrez également les métriques au niveau de l'hôte du primaire et du secondaire en retard : latence du disque, processeur, mémoire et débit réseau. Si un travail par lots ou un déploiement était en cours, enregistrez son heure de début et sa commande ou version de version.

Ce n'est pas de la paperasse pour le plaisir. Sans chronologie, le prochain incident repart de zéro. Avec une chronologie, vous remarquerez peut-être que le retard suit toujours une exportation, une sauvegarde ou une tâche de nettoyage spécifique. Cela transforme un problème de base de données vague en un problème de capacité planifiable.

Une carte de solutions pratiques

Utilisez le symptôme pour choisir la prochaine action :

Symptôme Zone probable Action suivante
Tous les secondaires sont en retard pendant un travail par lots Rafale d'écriture Limiter ou diviser le travail
Un secondaire est toujours en retard Problème de ressource local Vérifier le disque, le processeur, la mémoire et les lectures locales
Le retard augmente uniquement sur le membre distant Réseau/topologie Vérifier le débit, la perte de paquets et la conception inter-régions
Le retard est proche de la fenêtre de l'oplog Risque de récupération Augmenter l'oplog et réduire la source de retard
Le secondaire sert des lectures obsolètes Préférence de lecture Utiliser le primaire pour les lectures fraîches ou définir maxStalenessSeconds
Le membre ne peut pas rattraper son retard après un temps d'arrêt Historique d'oplog manquant Reconstruire à partir d'une sauvegarde ou d'une synchronisation initiale

Un bon dépannage de la réplication MongoDB est principalement une observation disciplinée. Trouvez si le primaire produit trop de travail, si le secondaire applique trop lentement ou si le lien entre eux est contraint. Ensuite, modifiez ce qui limite réellement la réplication au lieu d'appliquer un redémarrage, une resynchronisation ou une modification de configuration générique.