Auto compact l'espace supprimé en mongodb?

le document mongodb dit que

pour compacter cet espace, exécutez db.repairDatabase () de la coquille de mongo (notez que cette opération va bloquer et est lente).

in http://www.mongodb.org/display/DOCS/Excessive+disque+Espace

je me demande comment faire l'espace disque supprimé libre de mongodb automatiquement ?

p. S. Nous stocké de nombreuses tâches de téléchargement en mongodb, jusqu'à 20 Go, et terminé en une demi-heure.

39
demandé sur Zealot Ke 2010-12-29 19:42:46

4 réponses

en général, si vous n'avez pas besoin de rétrécir vos fichiers de données, vous ne devriez pas les rétrécir du tout. Cela est dû au fait que la "croissance" de vos fichiers de données sur disque est une opération assez coûteuse et que plus MongoDB peut allouer d'espace dans les fichiers de données, moins vous aurez de fragmentation.

Donc, vous devriez essayer de fournir autant d'espace disque que possible de la base de données.

Toutefois si vous devez réduire la base de données, vous devriez garder les deux choses à l'esprit.

  1. MongoDB augmente ses fichiers de données par doublage pour que les fichiers de données puissent être 64MB, puis 128MB, etc jusqu'à 2GB (at à quel point il cesse de doubler conserver les fichiers jusqu'à 2 Go.)

  2. comme pour la plupart des bases de données ... de faire des opérations comme rétrécir vous nécessité de prévoir un emploi distinct pour le faire, il n'y a pas de "réduction automatique" dans MongoDB. En fait de noSQL majeur les bases de données (déteste ce nom) seulement Riak va réduction automatique. Ainsi, vous aurez besoin de créer un emploi en utilisant votre système D'exploitation programmeur pour diriger un psy. Vous pouvez utiliser un script bash, ou faire exécuter un script php, etc.

Server-Side Javascript

vous pouvez utiliser Javascript côté serveur pour faire le shrink et exécuter que JS via shell mongo sur une base régulière via un travail (comme cron ou la programmation windows service. )..

en supposant une collection appelée foo vous sauvegarderiez le javascript ci-dessous dans un fichier appelé barre.js et courir ...

$ mongo foo bar.js

le fichier javascript ressemblerait à quelque chose ...

// Get a the current collection size.
var storage = db.foo.storageSize();
var total = db.foo.totalSize();

print('Storage Size: ' + tojson(storage));

print('TotalSize: ' + tojson(total));

print('-----------------------');
print('Running db.repairDatabase()');
print('-----------------------');

// Run repair
db.repairDatabase()

// Get new collection sizes.
var storage_a = db.foo.storageSize();
var total_a = db.foo.totalSize();

print('Storage Size: ' + tojson(storage_a));
print('TotalSize: ' + tojson(total_a));

cela va courir et retourner quelque chose comme ...

MongoDB shell version: 1.6.4
connecting to: foo
Storage Size: 51351
TotalSize: 79152
-----------------------
Running db.repairDatabase()
-----------------------
Storage Size: 40960
TotalSize: 65153

exécutez ceci sur un horaire (pendant aucune Heure de pointe) et vous êtes bon à aller.

Collections Plafonnées

cependant, il y a une autre option, collections plafonnées .

Collections plafonnées sont de taille fixe collections qui ont un très haut performance auto-FIFO fonction de fin d'âge (l'âge est basé sur l'ordre d'insertion). Ils sont un peu comme le concept "RRD" si vous êtes familier avec.

en plus, collections plafonnées automatiquement, avec de hautes performances, maintenir l'ordre d'insertion pour le les objets de la collection; c'est très puissant pour certains cas d'utilisation comme l'exploitation forestière.

en gros, vous pouvez limiter la taille (ou le nombre de documents ) d'une collection pour dire .. 20 Go et une fois que cette limite est atteint MongoDB commencera à jeter les enregistrements les plus anciens et les remplacer par de nouvelles entrées comme ils viennent dans.

C'est un excellente façon de garder une grande quantité de données, en supprimant les données les plus anciennes comme le temps passe et en gardant la même quantité d'espace disque utilisé.

65
répondu Justin Jenkins 2010-12-31 06:51:42

j'ai une autre solution qui pourrait fonctionner mieux que faire db.repairDatabase () si vous n'avez pas les moyens de verrouiller le système, ou si vous n'avez pas le double du stockage.

vous devez utiliser une réplique.

ma pensée est une fois que vous avez enlevé toutes les données en excès qui engloutissent votre disque, arrêter une réplique secondaire, effacer son répertoire de données, le démarrer et le laisser resynchroniser avec le maître.

le processus est le temps la consommation, mais il ne devrait coûter que quelques secondes de temps d'arrêt, lorsque vous faites de la rs.stepDown ().

Aussi, cela ne peut pas être automatisé. Eh bien, ça pourrait, mais je ne pense pas que je suis prêt à essayer.

26
répondu Mojo 2012-11-13 21:49:47

db en cours d'Exécution.repairDatabase () exigera que vous ayez l'espace égal à la taille actuelle de la base de données disponible sur le système de fichiers. Cela peut être gênant quand vous savez que les collections ou les données que vous devez conserver dans la base de données utiliseraient actuellement beaucoup moins d'espace que ce qui est alloué et vous n'avez pas assez d'espace pour faire la réparation.

comme alternative si vous avez peu de collections que vous avez réellement besoin de conserver ou seulement un sous-ensemble de la données, puis vous pouvez déplacer les données dont vous avez besoin pour garder dans une nouvelle base de données et laisser tomber l'ancienne. Si vous avez besoin du même nom de base de données, vous pouvez alors les déplacer de nouveau dans un db frais par le même nom. Assurez-vous simplement de recréer les index.

use cleanup_database
db.dropDatabase();

use oversize_database

db.collection.find({},{}).forEach(function(doc){
    db = db.getSiblingDB("cleanup_database");
    db.collection_subset.insert(doc);
});

use oversize_database
db.dropDatabase();

use cleanup_database

db.collection_subset.find({},{}).forEach(function(doc){
    db = db.getSiblingDB("oversize_database");
    db.collection.insert(doc);
});

use oversize_database

<add indexes>
db.collection.ensureIndex({field:1});

use cleanup_database
db.dropDatabase();

une opération export/drop/import pour des bases de données avec de nombreuses collections atteindrait probablement le même résultat mais je n'ai pas testé.

aussi comme une politique, vous pouvez garder les collections permanentes dans un base de données à partir de vos données transitoires/de traitement et il suffit de laisser tomber la base de données de traitement une fois vos travaux terminés. Étant donné que MongoDB est sans schéma, rien d'autre que des index serait perdu et votre base de données et vos collections seront recréées lorsque les inserts pour les processus s'exécuteront ensuite. Assurez-vous juste que vos travaux comprennent la création de n'importe quels index nessecary à un moment approprié.

8
répondu Robert Jobson 2013-01-14 16:56:53

si vous utilisez replica sets , qui n'étaient pas disponibles lorsque cette question a été écrite à l'origine, alors vous pouvez configurer un processus pour récupérer automatiquement de l'espace sans encourir de perturbations importantes ou des problèmes de performance.

pour ce faire, vous profitez des capacités de synchronisation initiale automatique d'un secondaire dans un jeu de répliques. Pour expliquer: si vous fermez un secondaire, essuyez ses fichiers de données et le redémarrez, le secondaire va re-sync from scratch from one of the other nodes in the set (par défaut, il choisit le noeud le plus proche en regardant les temps de réponse ping). Lorsque cette resync se produit, toutes les données sont réécrites à partir de zéro (y compris les index), effectivement faire la même chose qu'une réparation, et l'espace disque qu'il a récupéré.

en exécutant ceci sur secondaries (puis en retirant la Primaire et en répétant le processus) vous pouvez récupérer efficacement l'espace disque sur l'ensemble de l'ensemble avec un minimum de perturbation. Vous avez besoin d'être prudent si vous lisez des secondaires, car cela prendra un secondaire hors de rotation pour un temps potentiellement long. Vous voulez également vous assurer que votre fenêtre oplog est suffisante pour effectuer une resync réussie, mais c'est généralement quelque chose que vous voudriez vous assurer si vous faites ceci ou non.

pour automatiser ce processus, vous auriez simplement besoin d'un script lancé pour effectuer cette action sur des jours séparés (ou similaire) pour chaque membre de votre ensemble, de préférence pendant votre temps calme ou la fenêtre d'entretien. Une version très naïve de ce script ressemblerait à ceci dans bash :

NOTE: IL S'AGIT ESSENTIELLEMENT D'UN PSEUDO - CODE-À TITRE INDICATIF SEULEMENT - NE PAS UTILISER POUR LES SYSTÈMES DE PRODUCTION SANS MODIFICATIONS IMPORTANTES

#!/bin/bash 

# First arg is host MongoDB is running on, second arg is the MongoDB port

MONGO=/path/to/mongo
MONGOHOST=
MONGOPORT=
DBPATH = /path/to/dbpath

# make sure the node we are connecting to is not the primary
while (`$MONGO --quiet --host $MONGOHOST --port $MONGOPORT --eval 'db.isMaster().ismaster'`)
do
    `$MONGO --quiet --host $MONGOHOST --port $MONGOPORT --eval 'rs.stepDown()'`
    sleep 2
done    
echo "Node is no longer primary!\n"

# Now shut down that server 
# something like (assuming user is set up for key based auth and has password-less sudo access a la ec2-user in EC2)
ssh -t user@$MONGOHOST sudo service mongodb stop

# Wipe the data files for that server

ssh -t user@$MONGOHOST sudo rm -rf $DBPATH
ssh -t user@$MONGOHOST sudo mkdir $DBPATH
ssh -t user@$MONGOHOST sudo chown mongodb:mongodb $DBPATH

# Start up server again
# similar to shutdown something like 
ssh -t user@$MONGOHOST sudo service mongodb start 
4
répondu Adam Comerford 2014-10-23 15:21:57