Meilleures pratiques pour gérer et réduire l'utilisation de l'espace disque MongoDB
Optimisez votre utilisation du disque MongoDB avec ce guide complet des meilleures pratiques. Apprenez des stratégies efficaces pour compacter les collections et les index, identifier et supprimer les index inutiles, et tirer parti des fonctionnalités de compression de WiredTiger. Découvrez comment mettre en œuvre l'archivage des données, gérer la taille de l'oplog et surveiller de manière proactive l'espace disque pour éviter les pannes système et améliorer les performances. Cet article fournit des conseils pratiques et des exemples concrets pour maintenir vos déploiements MongoDB légers et efficaces.
Meilleures pratiques pour gérer et réduire l'utilisation de l'espace disque MongoDB
L'utilisation de l'espace disque MongoDB devient généralement urgente au pire moment : un traitement par lots prend plus de temps que prévu, les suppressions ne semblent pas libérer d'espace, ou un membre d'un jeu de réplicas commence à avertir que le volume est presque plein. La solution est rarement une commande magique. Vous devez savoir si l'espace est constitué de données actives, d'index, d'espace WiredTiger réutilisable, d'oplog, de journaux ou de sauvegardes locales.
L'approche la plus sûre est de mesurer d'abord, de réduire ce qui n'a plus besoin d'exister, et ensuite seulement d'exécuter une maintenance plus lourde comme la compaction ou la reconstruction de membres. Cet ordre vous évite de créer un long événement de maintenance qui libère peu d'espace.
Comprendre la consommation d'espace disque MongoDB
MongoDB utilise l'espace disque pour plusieurs composants :
- Fichiers de données : Stocke les documents BSON réels dans les collections.
- Fichiers d'index : Stocke les index B-tree créés pour prendre en charge l'exécution efficace des requêtes.
- Fichiers journal (WiredTiger) : Enregistre les opérations d'écriture avant qu'elles ne soient appliquées aux fichiers de données, assurant la durabilité des données. Ceux-ci sont pré-alloués.
- Oplog (Journal des opérations) : Une collection plafonnée spéciale dans les jeux de réplicas qui enregistre toutes les opérations d'écriture. Essentiel pour la réplication.
- Données de diagnostic : Journaux, fichiers de processus
mongodet autres informations liées au système.
Au fil du temps, en raison des mises à jour, des suppressions et de la croissance des documents (rembourrage), les collections et les index peuvent devenir fragmentés ou contenir de l'espace alloué inutilisé, ce qui entraîne une utilisation inefficace du disque. Cet "espace blanc" n'est pas immédiatement récupéré par le système d'exploitation, même si la base de données n'en a plus besoin pour les données actives.
Stratégies pour réduire l'espace disque MongoDB
1. Compacter les collections et les index
Les opérations de compaction aident à récupérer l'espace disque inutilisé en réécrivant les données et les fichiers d'index de manière plus efficace. Cela peut être particulièrement utile après des suppressions ou des mises à jour importantes de données.
Compacter les collections
Avec le moteur de stockage WiredTiger (par défaut depuis MongoDB 3.2), compact récupère principalement l'espace libre des documents supprimés et défragmente les collections. Il ne reconstruit pas le fichier de données de la collection à partir de zéro comme le faisait l'opération compact de MMAPv1.
db.runCommand({ compact: "myCollection" })
Considérations pour compact :
- Les opérations
compactpeuvent être gourmandes en ressources (CPU, E/S) et prendre beaucoup de temps, en particulier pour les grandes collections. Il est souvent préférable de les exécuter pendant les fenêtres de maintenance ou sur les membres secondaires d'un jeu de réplicas. - Les exigences de disque et le comportement de verrouillage varient selon la version de MongoDB, le moteur de stockage et la forme du déploiement. Consultez la documentation de votre version exacte avant de l'exécuter sur une grande collection de production.
- Pour les clusters fragmentés, exécutez
compactsur chaque fragment indépendamment.
Reconstruire les index
Les index peuvent également devenir fragmentés. La reconstruction d'un index peut récupérer de l'espace et potentiellement améliorer les performances des requêtes.
db.myCollection.reIndex()
Considérations pour reIndex() :
- Le comportement de
reIndex()a changé selon les versions de MongoDB, et il peut toujours être perturbateur sur les systèmes occupés. Consultez le manuel de votre version, testez sur un environnement de préproduction et privilégiez le travail progressif via les membres du jeu de réplicas lorsque cela est possible. - Comme pour
compact,reIndex()nécessite un espace disque supplémentaire pendant l'opération.
repairDatabase (Opération hors ligne)
En cas de fragmentation sévère ou de corruption de données, repairDatabase peut reconstruire tous les fichiers de données. Il s'agit d'une opération hors ligne qui nécessite l'arrêt de l'instance mongod.
mongod --repair
Avertissement : repairDatabase doit être utilisé en dernier recours pour la récupération d'espace car il s'agit d'une opération destructive si elle n'est pas manipulée avec soin et peut prendre beaucoup de temps. Ayez toujours une sauvegarde.
2. Optimiser les index
Les index sont cruciaux pour les performances mais peuvent consommer un espace disque important. Les index inutilisés ou redondants sont une pure surcharge.
Identifier et supprimer les index inutiles
Examinez régulièrement vos index pour vous assurer qu'ils sont toujours nécessaires.
- Listez tous les index d'une collection :
db.myCollection.getIndexes()
```
2. Surveillez l'utilisation des index : Utilisez $indexStats, les plans de requête, le profilage et l'historique de la charge de travail de votre application. Les statistiques de collection montrent la taille des index, mais elles ne prouvent pas si un index est utile.
3. Identifiez les index en double ou redondants : Par exemple, un index sur { a: 1, b: 1 } rend un index sur { a: 1 } redondant pour les requêtes qui peuvent utiliser l'index composé. Un index sur { a: 1, b: 1 } est également couvert par un index sur { a: 1, b: 1, c: 1 } pour les requêtes qui n'impliquent que a et b.
Une fois identifié, supprimez l'index inutilisé :
db.myCollection.dropIndex("indexName")
Astuce : Testez toujours l'impact de la suppression d'un index dans un environnement de préproduction avant de l'appliquer en production.
Utiliser des index partiels
Les index partiels n'indexent que les documents d'une collection qui satisfont une expression de filtre spécifiée. Cela réduit le nombre de documents indexés, économisant de l'espace disque et améliorant les performances d'écriture.
db.orders.createIndex(
{ customerId: 1, orderDate: -1 },
{ partialFilterExpression: { status: "active" } }
)
Cet index n'inclurait que les documents où status est "active", réduisant sa taille si la plupart des commandes sont historiques, annulées, archivées ou autrement hors du chemin chaud. La partie importante n'est pas le mot "active" ; c'est l'habitude d'indexer le sous-ensemble que votre application interroge réellement chaque jour.
Commencez par un triage de l'espace disque, pas par une commande de nettoyage
Lorsque l'espace disque MongoDB augmente, la première erreur est de sauter directement sur compact, repair ou la suppression des anciennes données. Ces actions peuvent aider, mais elles peuvent aussi créer une charge, prendre des verrous dans certaines situations, ou cacher le vrai problème pendant quelques semaines. Commencez par répondre à trois questions :
- Quel système de fichiers se remplit : le chemin de la base de données, le chemin du journal, le chemin des logs, ou le volume de sauvegarde ?
- Les données actives augmentent-elles, ou l'espace alloué mais inutilisé augmente-t-il après les suppressions et les mises à jour ?
- La croissance provient-elle des collections, des index, de l'oplog, des logs, des données de diagnostic ou des instantanés ?
Un premier passage rapide ressemble généralement à ceci :
df -h
du -h --max-depth=1 /var/lib/mongodb | sort -h
du -h --max-depth=1 /var/log/mongodb | sort -h
Ensuite, vérifiez MongoDB depuis le shell :
db.adminCommand({ listDatabases: 1 })
db.getSiblingDB("app").stats()
db.getSiblingDB("app").orders.stats()
storageSize, totalIndexSize et dataSize racontent des histoires différentes. Si dataSize augmente, vous avez probablement un problème de cycle de vie des données. Si storageSize est beaucoup plus grand que dataSize, vous regardez peut-être un espace interne réutilisable après des suppressions. Si totalIndexSize est grand par rapport à dataSize, la conception des index mérite attention avant de toucher à la compaction.
Comprenez ce que MongoDB peut et ne peut pas rendre
Avec WiredTiger, la suppression de documents rend généralement l'espace disponible pour une réutilisation par MongoDB. Cela ne rend pas toujours cet espace au système d'exploitation immédiatement. Ce comportement surprend les gens lors d'un nettoyage d'urgence : ils suppriment un gros lot, exécutent df -h et ne voient presque aucune amélioration.
Cela ne signifie pas que la suppression a échoué. Cela signifie que MongoDB peut souvent réutiliser cet espace pour de futures insertions et mises à jour. Si l'objectif est d'arrêter la croissance, la suppression ou l'archivage des anciennes données peut suffire. Si l'objectif est de réduire le système de fichiers parce que le volume est presque plein ou que l'hôte est réduit, vous aurez peut-être besoin d'une compaction, d'une resynchronisation d'un membre du jeu de réplicas, ou d'une reconstruction de type dump-and-restore.
Pour les systèmes de production, je sépare généralement le travail en deux pistes. La première piste est la sécurité immédiate : ajouter du disque, supprimer l'accumulation évidente de logs, mettre en pause les traitements par lots risqués, ou déplacer les sauvegardes hors du volume de la base de données. La deuxième piste est la réduction réelle : corriger la rétention, supprimer les index inutilisés, et reconstruire le stockage seulement après avoir su où sont allés les octets.
Corrigez la rétention des données avant de défragmenter quoi que ce soit
Si votre application conserve les logs de requêtes, les événements, les sessions, les notifications, les enregistrements de travaux ou les documents d'analyse pour toujours, l'utilisation du disque reviendra, peu importe avec quel soin vous compactez. MongoDB vous offre quelques options pratiques.
Pour les données qui expirent sur un simple horodatage, un index TTL est souvent la réponse la plus propre :
db.sessions.createIndex(
{ expiresAt: 1 },
{ expireAfterSeconds: 0 }
)
Cet index supprime les documents après la date stockée dans expiresAt. Il est utile pour les sessions, les jetons temporaires, les travaux d'importation de courte durée ou les réponses d'API mises en cache. Ce n'est pas un remplacement pour les règles de rétention métier. Le moniteur TTL s'exécute en arrière-plan, donc ne vous attendez pas à une suppression à la seconde près, et n'utilisez pas TTL sur des données qui nécessitent un flux de travail d'approbation avant la suppression.
Pour les enregistrements métier, archivez plutôt que de supprimer aveuglément. Un modèle courant est :
- Copier les documents plus anciens que la fenêtre de rétention vers un stockage moins cher ou une base de données d'archives.
- Vérifier les comptages et un échantillon des champs importants.
- Supprimer par petits lots de la collection principale.
- Surveiller le retard de réplication et les métriques de disque pendant l'exécution du travail.
Les petits lots sont importants. Une seule grande suppression peut créer une pression de réplication, remplir les logs et rendre la restauration plus difficile si quelqu'un se rend compte que le filtre était erroné. Un travail par lots plus sûr pourrait supprimer quelques milliers de documents à la fois, dormir brièvement et enregistrer la progression par _id ou horodatage.
while (true) {
const result = db.events.deleteMany({
createdAt: { $lt: ISODate("2025-01-01T00:00:00Z") },
archived: true
});
print(`deleted ${result.deletedCount}`);
if (result.deletedCount === 0) break;
sleep(500);
}
Dans un script de production réel, ajoutez un modèle de limite au lieu de deleteMany sur toute la plage, enregistrez chaque lot et arrêtez automatiquement si le retard de réplication ou les E/S disque dépassent votre seuil.
Soyez prudent avec les conseils sur les index qui semblent trop simples
Supprimer les index inutilisés est l'un des meilleurs moyens de réduire l'espace disque MongoDB, mais "inutilisé" a besoin de contexte. Un index peut sembler inutilisé pendant une semaine calme et être toujours critique pour les rapports de fin de mois, la réconciliation en arrière-plan ou un flux de travail rare de support client.
Utilisez $indexStats pour voir les modèles d'accès :
db.orders.aggregate([{ $indexStats: {} }])
Comparez ensuite le résultat avec le code de l'application, les travaux planifiés, les tableaux de bord et les requêtes de support. Si un index n'a pas été utilisé depuis le dernier redémarrage, c'est un signal, pas un verdict. Avant de le supprimer, vérifiez si le serveur a redémarré récemment et si l'échantillon de charge de travail inclut les travaux qui comptent.
Surveillez également les index composés qui se chevauchent. Si vous avez ceux-ci :
{ customerId: 1 }
{ customerId: 1, createdAt: -1 }
{ customerId: 1, createdAt: -1, status: 1 }
vous pourrez peut-être en supprimer un, mais seulement après avoir vérifié l'ordre de tri, les filtres de requête et si l'index plus court prend en charge un modèle d'accès différent. MongoDB peut utiliser le préfixe gauche d'un index composé, mais cela ne signifie pas que le plus grand index est toujours un remplacement gratuit. Les index plus grands coûtent plus de mémoire et d'E/S d'écriture, alors gardez celui qui correspond à la charge de travail, pas celui qui semble le plus complet.
Préférez la resynchronisation pour les grandes opérations de réduction sur les jeux de réplicas
Pour un grand jeu de réplicas, la façon la plus propre de récupérer l'espace disque du système d'exploitation est souvent de reconstruire un secondaire à la fois. L'idée de base est :
- Confirmez que vous avez une réplication saine et des sauvegardes actuelles.
- Supprimez ou arrêtez un secondaire.
- Effacez son répertoire de données local.
- Laissez-le se resynchroniser à partir du primaire ou d'un autre membre sain.
- Répétez pour le secondaire suivant.
- Rétrogradez le primaire pendant une fenêtre de maintenance et reconstruisez l'ancien primaire en dernier.
Cette approche est plus lente que l'exécution d'une commande, mais il est plus facile de raisonner car chaque membre reconstruit écrit des fichiers de stockage frais basés sur les données actuelles. Cela évite également d'essayer de compacter chaque collection sous le trafic de production. Ce n'est pas gratuit : la synchronisation initiale peut être lourde en réseau et en disque, et vous avez besoin d'assez de membres restants pour maintenir le jeu de réplicas en sécurité pendant qu'un membre est en reconstruction.
Pour un serveur MongoDB autonome, vous n'avez pas ce luxe. Dans ce cas, planifiez une fenêtre de maintenance, prenez une sauvegarde testée et envisagez mongodump/mongorestore ou une migration au niveau du système de fichiers vers un nouveau volume. Ne choisissez pas mongod --repair simplement parce que vous voulez un répertoire de données plus petit. Traitez la réparation comme un outil de récupération, pas comme une maintenance de routine.
Surveillez aussi l'oplog, les logs et les sauvegardes
Toute la pression sur le disque MongoDB ne provient pas des collections. Dans les jeux de réplicas, l'oplog est une collection plafonnée, donc il ne devrait pas croître indéfiniment, mais sa taille configurée compte toujours. S'il est trop petit, les secondaires peuvent décrocher pendant la maintenance. S'il est beaucoup plus grand que nécessaire sur un petit disque, il peut gaspiller de l'espace. Examinez-le délibérément :
db.getSiblingDB("local").oplog.rs.stats()
Les logs MongoDB peuvent également remplir un disque lorsque la journalisation des requêtes lentes, la verbosité de débogage ou une boucle d'erreur d'application devient bruyante. Utilisez la rotation des logs et gardez les logs de la base de données loin du même petit volume qui stocke les données lorsque cela est possible.
Les sauvegardes sont une autre surprise courante. Les équipes exécutent parfois mongodump sur le même hôte parce que c'est pratique, puis se demandent pourquoi les alertes de disque se déclenchent pendant la fenêtre de sauvegarde. Une sauvegarde stockée sur le même système de fichiers n'est pas vraiment une sauvegarde, et elle peut pousser MongoDB vers une panne pire pendant une opération déjà risquée. Diffusez les sauvegardes vers un stockage d'objets, un serveur de sauvegarde ou un volume monté séparé.
Un manuel pratique pour un disque MongoDB plein
Si le disque est déjà au-dessus de 90 %, ralentissez et travaillez dans cet ordre :
- Confirmez si MongoDB accepte toujours les écritures et si le jeu de réplicas est sain.
- Ajoutez une capacité de disque temporaire si la plateforme le permet. C'est souvent plus sûr qu'une suppression d'urgence.
- Déplacez ou faites pivoter les logs surdimensionnés et les fichiers de sauvegarde locaux.
- Arrêtez les traitements par lots non essentiels qui écrivent beaucoup.
- Identifiez les plus grandes collections et index avec
db.stats()et lesstats()de collection. - Archivez ou supprimez uniquement les données avec une règle de rétention claire.
- Planifiez la compaction, la resynchronisation ou la restauration après que le système soit stable.
La meilleure solution à long terme est ennuyeuse : règles de rétention, révisions des index, alertes de disque et procédures de reconstruction testées. MongoDB est à l'aise pour réutiliser l'espace libre interne, mais les opérateurs doivent toujours décider quelles données méritent de vivre sur un stockage rapide et ce qui peut être déplacé ailleurs.