2010-12-29 10 views
39
documento

Il mongodb dice cheCompatta automaticamente lo spazio cancellato in mongodb?

compattare questo spazio, eseguire db.repairDatabase() dalla mongo shell (Nota Questa operazione blocca ed è lento).

in http://www.mongodb.org/display/DOCS/Excessive+Disk+Space

mi chiedo come fare la MongoDB libera cancellato lo spazio su disco automaticamente?

p.s. Abbiamo archiviato molte attività di download in mongodb, fino a 20 GB, e abbiamo terminato queste operazioni in mezz'ora.

risposta

65

In generale, se non è necessario ridurre i file di dati, non è necessario ridurli. Questo perché "far crescere" i propri file di dati su disco è un'operazione abbastanza costosa e più spazio sarà possibile da MongoDB nei file di dati, minore sarà la frammentazione che si avrà.

Quindi, si dovrebbe provare a fornire quanto più spazio sul disco possibile per il database.

Tuttavia se è necessario ridurre il database, è necessario tenere a mente due elementi.

  1. MongoDB cresce è i file di dati di raddoppiando così i file di dati possono essere 64 MB, quindi 128MB, ecc fino a 2GB (a quindi si arresta il raddoppio per mantenere i file fino a 2GB.)

  2. Come con la maggior parte dei database ... a fare operazioni come la riduzione di è necessario pianificare un lavoro separato per fare , non c'è "autoshrink" in MongoDB. Infatti i principali database noSQL (odio quel nome) solo Riak si autoshrink. Pertanto, è necessario creare utilizzando il programma di pianificazione del sistema operativo per eseguire una riduzione. È possibile utilizzare uno script bash, o di avere un lavoro eseguire uno script php, ecc

Serverside Javascript

È possibile utilizzare lato server Javascript per fare lo strizzacervelli ed eseguire che JS attraverso la shell di Mongo su un regolare basi tramite un lavoro (come cron o il servizio Windows scheduling) ...

assumendo una collezione chiamata foo si salva il javascript di seguito in un file chiamato bar.js ed eseguire ...

$ mongo foo bar.js 

il file JavaScript sarebbe simile ...

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

Questo farà eseguire e restituire qualcosa di simile ...

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

Esegui questo su un programma (durante il picco di nessuno ore) e sei a posto.

con Cap Collezioni

Tuttavia c'è un altra opzione, capped collections.

collezioni con Cap sono fisse dimensionati collezioni che hanno una caratteristica molto alte prestazioni auto-FIFO età-out (età out si basa su ordine di inserimento). Sono un po 'come il concetto "RRD" se si ha familiarità con quello.

Inoltre, collezioni capped automaticamente, con alte prestazioni, mantenere l'ordine di inserimento per i oggetti della collezione; questo è molto potente per determinati casi d'uso come la registrazione.

Fondamentalmente si può limitare la dimensione (o il numero di documenti in) una collezione da dire .. 20GB e una volta raggiunto tale limite MongoDB inizierà a buttare fuori i record più vecchi e sostituirli con le voci più recenti come hanno entrare.

Questo è un ottimo modo per mantenere una grande quantità di dati, scartando i vecchi dati col passare del tempo e mantenendo la stessa quantità di spazio su disco utilizzato.

+0

Grazie per il grande post. se non rimpicciolirai i file di dati, il mongod costerà sempre molta memoria, come potrei risolverlo? –

+0

@Zealot ... Vedere la mia risposta sull'uso della memoria, potrebbe essere utile. http://stackoverflow.com/questions/4468873/how-to-release-the-caching-which-is-used-by-mongodb/4482465#4482465 –

+0

Ho capito, abbiamo 16 GB di memoria, e il mongodb costa 4 GB . Quindi non mi interessa. Grazie per queste risposte. –

24

Ho un'altra soluzione che potrebbe funzionare meglio di fare db.repairDatabase() se non puoi permetterti che il sistema sia bloccato, o non abbia il doppio della memoria.

È necessario utilizzare un set di repliche.

Il mio pensiero è una volta che hai rimosso tutti i dati in eccesso che stanno inghiottendo il tuo disco, interrompi una replica secondaria, cancella la sua directory di dati, avviarla e lasciarla risincronizzare con il master.

Il processo richiede molto tempo, ma quando si esegue rs.stepDown() è necessario solo alcuni secondi di inattività.

Anche questo non può essere automatizzato. Beh, potrebbe, ma non penso di essere disposto a provare.

+0

Grazie. Questo funziona benissimo per i set di repliche ed era esattamente ciò di cui avevamo bisogno per un set di repliche che avesse esaurito lo spazio. – tcbcw

+2

questa dovrebbe essere la risposta migliore. è semplice e funziona in una distribuzione reale. – Keeth

+0

Attenzione, la replica da zero non funziona, se la dimensione del log è troppo piccola (o se hai molti dati). Quindi, la sincronizzazione iniziale richiederà più tempo poiché l'intervallo di tempo dell'oplog e la replica si interrompono da qualche parte nel mezzo. – scho

8

L'esecuzione di db.repairDatabase() richiede che si disponga di spazio uguale alla dimensione corrente del database disponibile nel file system. Questo può essere fastidioso quando si sa che le raccolte o i dati da conservare nel database utilizzerebbero attualmente molto meno spazio di quello che è stato assegnato e non si dispone di spazio sufficiente per effettuare la riparazione.

In alternativa se si dispone di poche raccolte effettivamente necessarie per conservare o solo un sottoinsieme di dati, è possibile spostare i dati necessari per conservarli in un nuovo database e rilasciare quello vecchio. Se è necessario lo stesso nome del database, è possibile spostarli nuovamente in un nuovo db con lo stesso nome. Assicurati di ricreare qualsiasi indice.

Un'operazione di esportazione/rilascio/importazione per database con molte raccolte otterrebbe probabilmente lo stesso risultato ma non l'ho testata.

Inoltre, come criterio è possibile mantenere le raccolte permanenti in un database separato dai dati transitori/di elaborazione e semplicemente rilasciare il database di elaborazione una volta completati i lavori.Dato che MongoDB è senza schema, nulla tranne gli indici andrebbe perso e il tuo database e le raccolte verranno ricreati quando gli inserimenti per i processi verranno eseguiti successivamente. Assicurati solo che i tuoi lavori includano la creazione di qualsiasi indice nessecary al momento opportuno.

4

Se si utilizza replica sets, che non erano disponibili quando questa domanda è stata originariamente scritta, è possibile impostare un processo per recuperare automaticamente spazio senza incorrere in problemi significativi di prestazioni o interruzioni.

Per fare ciò, si sfruttano le funzionalità di sincronizzazione iniziale automatica di un secondario in un set di repliche. Per spiegare: se si spegne un secondario, si cancellano i suoi file di dati e lo si riavvia, il secondario si risincronizza da zero da uno degli altri nodi nel set (per impostazione predefinita seleziona il nodo più vicino osservando la risposta del ping volte). Quando si verifica questa risincronizzazione, tutti i dati vengono riscritti da zero (compresi gli indici), in modo efficace fanno la stessa cosa di una riparazione e lo spazio su disco recuperato.

Eseguendo ciò su secondari (e quindi arrestando il primario e ripetendo il processo) è possibile ripristinare in modo efficace lo spazio su disco sull'intero insieme con interruzioni minime. Bisogna stare attenti se si sta leggendo da secondari, poiché ciò richiederà una rotazione secondaria per un tempo potenzialmente lungo. Volete anche assicurarvi che la vostra finestra oplog sia sufficiente per eseguire una risincronizzazione riuscita, ma generalmente è qualcosa che vorreste accertarvi se lo fate o no.

Per automatizzare questo processo, è necessario semplicemente eseguire uno script per eseguire questa azione in giorni separati (o simili) per ciascun membro del set, preferibilmente durante il periodo di inattività o la finestra di manutenzione. Una versione molto ingenuo di questo script apparirebbe come questo in bash:

NOTA: Questo è fondamentalmente pseudo codice - FINI ILLUSTRATIVI SOLO - Non utilizzare per sistemi di produzione senza significative CAMBIAMENTI

#!/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 
Problemi correlati