2010-12-29 11 views

Respuesta

65

En general, si no necesita reducir sus archivos de datos, no debe reducirlos en absoluto. Esto se debe a que "hacer crecer" sus archivos de datos en el disco es una operación bastante costosa y cuanto más espacio pueda asignar MongoDB en los archivos de datos, menos fragmentación tendrá.

Por lo tanto, debe intentar proporcionar la mayor cantidad de espacio de disco posible para la base de datos.

Sin embargo, si debe reducir la base de datos, debe tener en cuenta dos cosas.

  1. MongoDB crece es archivos de datos por duplicando así los archivos de datos pueden ser 64 MB, a continuación, 128MB, etc hasta 2 GB (en cuyo punto se deja doblar a mantener los archivos de hasta 2 GB.)

  2. Al igual que con la mayoría de las bases de datos ... a hacer operaciones como contraer necesita programar un trabajo por separado a , no hay "autoshrink" en MongoDB. De hecho, de las principales bases de datos noSQL (odio ese nombre), solo Riak se reescribirá automáticamente. Por lo tanto, necesitará crear un trabajo utilizando el planificador de su sistema operativo para ejecutar un encogimiento. Se podría utilizar un script bash, o tener un trabajo ejecutar un script php, etc.

Serverside Javascript

Puede utilizar el servidor Javascript para hacer el encogimiento y ejecutar de que JS a través de la concha de mongo en una base regular a través de un trabajo (como cron o el servicio de programación de windows) ...

Suponiendo una colección llamada foo que se ahorraría el Javascript a continuación en un archivo llamado bar.js y correr ...

$ mongo foo bar.js 

el archivo JavaScript sería algo como ...

// 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)); 

Esto ejecutará y devolver algo así como ...

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

Ejecutar este en un horario (en ninguno de pico horas) y eres bueno para ir.

con límite máximo Colecciones

Sin embargo hay otra opción, capped collections.

colecciones con límite máximo se fija un tamaño colecciones que tienen una característica muy alta edad de salida de auto-FIFO rendimiento (edad a cabo se basa en orden de inserción). Son un poco como el concepto "RRD" si está familiarizado con eso.

Además, colecciones capsulado automáticamente, con alto rendimiento, mantener el orden de inserción para el objetos de la colección; esto es muy potente para ciertos casos de uso , como el registro.

Básicamente se puede limitar el tamaño de (o número de documentos en) una colección decir .. 20 GB y una vez que se alcanza el límite de MongoDB comenzará a expulsar a los registros más antiguos y reemplazarlos con nuevas entradas como se entra.

Esta es una gran manera de mantener una gran cantidad de datos, descartando los datos anteriores con el paso del tiempo y manteniendo la misma cantidad de espacio de disco utilizado.

+0

Gracias por la gran publicación. si no reduzco los archivos de datos, el mongod siempre costará mucha memoria, ¿cómo podría solucionarlo? –

+0

@Zealot ... Ver mi respuesta sobre el uso de la memoria, podría ser útil. http://stackoverflow.com/questions/4468873/how-to-release-the-caching-which-is-used-by-mongodb/4482465#4482465 –

+0

Lo tengo, tenemos 16GB de memoria, y el mongodb cuesta 4GB . Entonces, puede que no me importe. Gracias por estas respuestas –

24

Tengo otra solución que podría funcionar mejor que hacer db.repairDatabase() si no puede permitirse que el sistema se bloquee, o no tiene el doble de almacenamiento.

Debe utilizar un conjunto de réplicas.

Mi idea es una vez que haya eliminado todos los datos en exceso que están engullendo su disco, detenga una réplica secundaria, limpie su directorio de datos, inicie y permita que vuelva a sincronizarse con el maestro.

El proceso lleva mucho tiempo, pero solo debería costar unos segundos de tiempo de inactividad, cuando lo hace rs.stepDown().

También esto no se puede automatizar. Bueno, podría, pero no creo que esté dispuesto a intentarlo.

+0

Gracias. Esto funciona increíble para conjuntos de réplicas y era exactamente lo que necesitábamos para un conjunto de réplicas que se quedaba sin espacio. – tcbcw

+2

esta debería ser la respuesta principal. es simple y funciona en una implementación en el mundo real. – Keeth

+0

Tenga en cuenta que la replicación desde cero no funciona, si el tamaño de oplog es demasiado pequeño (o si tiene una gran cantidad de datos). Entonces, la sincronización inicial tomará más tiempo ya que el lapso de tiempo del oplog y la replicación se detienen en algún punto intermedio. – scho

8

Ejecutar db.repairDatabase() requerirá que tenga espacio igual al tamaño actual de la base de datos disponible en el sistema de archivos. Esto puede ser molesto cuando sabe que las colecciones que quedan o los datos que necesita conservar en la base de datos usarían actualmente mucho menos espacio del que se asigna y no tiene suficiente espacio para realizar la reparación.

Como alternativa, si tiene pocas colecciones realmente necesita retener o solo desea un subconjunto de los datos, puede mover los datos que necesita para guardar en una nueva base de datos y descartar la anterior. Si necesita el mismo nombre de base de datos, puede moverlos de nuevo a un db nuevo con el mismo nombre. Solo asegúrate de recrear cualquier índice.

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(); 

Una operación de exportación/soltar/importar bases de datos con muchas colecciones probablemente lograría el mismo resultado pero no lo he probado.

También como política puede mantener colecciones permanentes en una base de datos separada de sus datos transitorios/de procesamiento y simplemente colocar la base de datos de procesamiento una vez que se completen sus trabajos.Como MongoDB no tiene esquemas, no se perderán nada, excepto los índices, y su db y colecciones se volverán a crear cuando las inserciones de los procesos se ejecuten a continuación. Solo asegúrese de que sus trabajos incluyan la creación de índices nessecary en el momento adecuado.

4

Si está utilizando replica sets, que no estaban disponibles cuando esta pregunta se escribió originalmente, puede configurar un proceso para reclamar espacio automáticamente sin incurrir en problemas significativos de interrupción o rendimiento.

Para hacerlo, aprovecha las capacidades de sincronización inicial automática de un secundario en un conjunto de réplicas. Explicar: si apaga un secundario, borra sus archivos de datos y lo reinicia, el secundario se volverá a sincronizar desde cero desde uno de los otros nodos del conjunto (de manera predeterminada selecciona el nodo más cercano mirando la respuesta de ping) veces). Cuando se produce esta resincronización, todos los datos se reescriben desde cero (incluidos los índices), efectivamente hacen lo mismo que una reparación y el espacio en disco que reclama.

Al ejecutar esto en secundarios (y luego abandonar el primario y repetir el proceso) puede reclamar efectivamente espacio en disco en todo el conjunto con una interrupción mínima. Debe tener cuidado si está leyendo desde secundarios, ya que esto hará que un secundario deje de girar durante un tiempo potencialmente prolongado. También querrá asegurarse de que su ventana oplog sea suficiente para hacer una resincronización exitosa, pero generalmente es algo que debería asegurarse de hacer esto o no.

Para automatizar este proceso, solo necesita ejecutar un script para realizar esta acción en días separados (o similares) para cada miembro de su conjunto, preferiblemente durante su tiempo de silencio o ventana de mantenimiento. Una versión muy ingenua de este script se parecería a esto en bash:

NOTA: esto es básicamente pseudo código - para fines ilustrativos - NO USAR PARA SISTEMAS DE PRODUCCIÓN SIN CAMBIOS SIGNIFICATIVOS

#!/bin/bash 

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

MONGO=/path/to/mongo 
MONGOHOST=$1 
MONGOPORT=$2 
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 [email protected]$MONGOHOST sudo service mongodb stop 

# Wipe the data files for that server 

ssh -t [email protected]$MONGOHOST sudo rm -rf $DBPATH 
ssh -t [email protected]$MONGOHOST sudo mkdir $DBPATH 
ssh -t [email protected]$MONGOHOST sudo chown mongodb:mongodb $DBPATH 

# Start up server again 
# similar to shutdown something like 
ssh -t [email protected]$MONGOHOST sudo service mongodb start 
Cuestiones relacionadas