41

mongodbドキュメントには次のように書かれています

このスペースを圧縮するには、mongoシェルからdb.repairDatabase()を実行します(この操作はブロックされ、低速になることに注意してください)。

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

mongodbが削除されたディスクスペースを自動的に解放する方法を知りたいですか?

ps多くのダウンロードタスクを最大20GBのmongodbに保存し、これらを30分で完了しました。

4

4 に答える 4

68

一般に、データファイルを縮小する必要がない場合は、まったく縮小しないでください。これは、ディスク上でデータファイルを「拡張」することはかなりコストのかかる操作であり、MongoDBがデータファイルに割り当てることができるスペースが多いほど、断片化が少なくなるためです。

したがって、データベースにできるだけ多くのディスク領域を提供するようにしてください。

ただし、データベースを縮小する必要がある場合は、2つの点に注意する必要があります。

  1. MongoDBは、データファイルを2倍にすることでデータファイルを拡大し、データファイルが64MB、次に128MBなど、最大2GBになるようにします(この時点で、2GBになるまでファイルを保持するために倍増を停止します)。

  2. ほとんどのデータベースと同様に...縮小などの操作を行うには、別のジョブをスケジュールする必要があります。MongoDBには「自動縮小」はありません。実際、主要なnoSQLデータベース(その名前は嫌いです)では、Riakだけが自動縮小します。したがって、縮小を実行するには、OSのスケジューラを使用してジョブを作成する必要があります。bashスクリプトを使用することも、ジョブにphpスクリプトを実行させることもできます。

サーバーサイドJavascript

サーバー側のJavascriptを使用して、縮小を実行し、ジョブ(cronやWindowsスケジューリングサービスなど)を介して定期的にmongoのシェルを介してそのJSを実行できます...

fooというコレクションを想定すると、以下のjavascriptをbar.jsというファイルに保存して、...を実行します。

$ mongo foo bar.js

javascriptファイルは次のようになります...

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

これは実行され、次のようなものを返します...

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

これをスケジュールに従って実行すると(ピーク時間はありません)、準備は完了です。

上限付きコレクション

ただし、もう1つのオプション、上限付きコレクションがあります。

上限付きコレクションは、非常に高性能な自動FIFOエージングアウト機能を備えた固定サイズのコレクションです(エージングアウトは挿入順序に基づいています)。あなたがそれに精通しているなら、それらは「RRD」の概念に少し似ています。

さらに、キャップされたコレクションは自動的に高性能になり、コレクション内のオブジェクトの挿入順序を維持します。これは、ロギングなどの特定のユースケースにとって非常に強力です。

基本的に、コレクションのサイズ(またはドキュメントの数)を.. 20GBに制限できます。その制限に達すると、MongoDBは最も古いレコードを破棄し、新しいエントリに置き換えます。

これは、大量のデータを保持し、時間の経過とともに古いデータを破棄し、同じ量のディスク領域を使用して維持するための優れた方法です。

于 2010-12-30T04:52:18.447 に答える
26

システムをロックする余裕がない場合、またはストレージが2倍にならない場合は、db.repairDatabase()を実行するよりもうまく機能する可能性のある別のソリューションがあります。

レプリカセットを使用している必要があります。

私の考えでは、ディスクをゴブリングしている余分なデータをすべて削除し、セカンダリレプリカを停止し、そのデータディレクトリをワイプして起動し、マスターと再同期させます。

このプロセスには時間がかかりますが、rs.stepDown()を実行すると、数秒のダウンタイムしかかかりません。

また、これは自動化できません。それは可能ですが、私は試してみる気がないと思います。

于 2012-11-13T21:49:47.923 に答える
8

db.repairDatabase()を実行するには、ファイルシステムで使用可能なデータベースの現在のサイズと同じスペースが必要です。これは、残っているコレクションまたはデータベースに保持する必要のあるデータが現在割り当てられているスペースよりもはるかに少ないスペースを使用し、修復を行うための十分なスペースがないことがわかっている場合に厄介になる可能性があります。

別の方法として、実際に保持する必要のあるコレクションが少ない場合、またはデータのサブセットのみが必要な場合は、保持する必要のあるデータを新しいデータベースに移動して、古いデータベースを削除できます。同じデータベース名が必要な場合は、同じ名前の新しいデータベースに戻すことができます。必ずインデックスを再作成してください。

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

多くのコレクションを持つデータベースのエクスポート/ドロップ/インポート操作で同じ結果が得られる可能性がありますが、私はテストしていません。

また、ポリシーとして、一時/処理データとは別のデータベースに永続的なコレクションを保持し、ジョブが完了したら処理データベースを削除することもできます。MongoDBはスキーマがないため、インデックス以外は失われず、プロセスの挿入が次に実行されるときにデータベースとコレクションが再作成されます。適切なタイミングで必要なインデックスを作成することが仕事に含まれていることを確認してください。

于 2013-01-14T16:56:53.670 に答える
4

この質問が最初に作成されたときに使用できなかったレプリカセットを使用している場合は、重大な中断やパフォーマンスの問題を発生させることなく、スペースを自動的に再利用するプロセスを設定できます。

これを行うには、レプリカセット内のセカンダリの自動初期同期機能を利用します。説明:セカンダリをシャットダウンし、そのデータファイルをワイプして再起動すると、セカンダリはセット内の他のノードの1つから最初から再同期します(デフォルトでは、ping応答を見て最も近いノードを選択します)時間)。この再同期が発生すると、すべてのデータ(インデックスを含む)が最初から再書き込みされ、修復と同じことを効果的に実行し、ディスク領域を再利用します。

これをセカンダリで実行する(そしてプライマリをステップダウンしてプロセスを繰り返す)ことにより、最小限の中断でセット全体のディスク領域を効果的に再利用できます。セカンダリから読み取る場合は注意が必要です。これにより、セカンダリが長時間ローテーションから外れる可能性があるためです。また、oplogウィンドウが再同期を正常に実行するのに十分であることを確認する必要がありますが、これは通常、これを実行するかどうかを確認する必要があります。

このプロセスを自動化するには、スクリプトを実行して、セットの各メンバーに対して別々の日(または同様の日)に、できれば静かな時間またはメンテナンス時間中にこのアクションを実行する必要があります。このスクリプトの非常に単純なバージョンは、次のようになりますbash

注:これは基本的に擬似コードです-説明目的のみ-重要な変更なしに本番システムに使用しないでください

#!/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 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 
于 2014-10-23T15:21:57.063 に答える