MongoDBはデータを削除しても容量は解放されない。再利用されるのかどうかよくワカラナイ (検証してないので教えてくれたら嬉しい) 。
節約型でMongoDBを運用していたりすると「ハードディスクやばいよー」ってなる。
何度か実際に対応して問題なさそうだったのでまとめた。
環境
- ReplicaSetで3台構成で運用
- MongoDB Versionは 2.4.4, 2.4.8 でやった
- OS debian squeeze
一般的な解決策
- サービスをメンテナンスにして大きなサーバに置き換える
- 必要ないデータを削除後、サービスをメンテナンスにして repairDatabase する
考えてみる。
大きなサーバに置き換え
メリット
- シンプル
- 安全そう
- 簡単そう
デメリット
- サービス一時停止
- コストアップ
repairDatabase
メリット
- コストキープ
- 他のデータ不整合とかも取れるぽい
- MongoDBぽい
デメリット
- サービス一時停止
- 時間がどのくらいかかるのか検証しないといけない
- ブラックボックス
- 空き容量がDB容量+2GB無いと実行できない
repairDatabase requires free disk space equal to the size of your current data set plus 2 gigabytes.
repairDatabase — MongoDB Manual 2.6.4
やりたくない
- そもそもサービス停止は出来る限りやりたくない。
- 少しなら仕方ないけど1日とか半日とか死亡フラグ
- よくわからない事は取り返しつかなくなりそうなのでやりたくない
- 当たり前だけどコストはかけないに越したことはない
- マイノリティ根性(もっといい方法は絶対あると信じてた)
違う方法でやってみた
- いらないCollectionを消す
- これは処理めっちゃ軽いのでバンバン消した
- しかしやはり容量は解放されず
- SECONDARYをからっぽにして再度syncさせたらどうなるんだっけ
- 容量減ったΣ(゚д゚
- SECONDARY1台ずつ容量へらしてsyncさせる
- 全部sync終わったらPRIMARYと入れ替える (短時間だがアプリ一時停止必要)
- 元PRIMARYもからっぽにして再sync
- あら不思議。メンテナンスは30分ぐらいで完了
作業内容詳細
Replicaset構成
- PRIMARY
- 10.120.41.197
- SECONDARY
- 10.120.41.196
- SECONDARY
- 10.120.41.199
1.いらないCollectionを消す
set:PRIMARY> use dbname;
set:PRIMARY> db.collectionname.drop()
一瞬で消えるはず
2.SECONDARYをReplicaSetからはずす
set:PRIMARY> rs.remove("10.120.41.196:27017")
外したSECONDARYのログが落ち着くまで見守る
3.外したSECONDARYのMongoDBを止める
set:REMOVED> use admin;
set:REMOVED> db.shutdownServer();
4.外したSECONDARYのdbpathとlogpathを削除
不安な場合は圧縮してどこかにバックアップとっておけばそのまま戻せるはず (未確認)
$ sudo rm -r /var/lib/mongodb/*
$ sudo rm -r /var/log/mongodb/*
5.mongoDB復活
各OSのやり方でどうぞ
$ sudo service mongod start
6.ReplicaSet追加
追加する時にどのmemberからsyncしてくるのか設定しないと、PRIMARYからsyncしちゃってサービスに影響でちゃいます。
rs.syncFromは迅速に叩くとそこからsyncになるので毎回急いでる。 (いい方法ご存知であれば教えてほしい)
- PRIMARY側作業
set:PRIMARY> rs.add("10.120.41.196:27017") # 追加するSECONDARY
- 追加するSECONDARY側作業
これをPRIMARYでaddされるまで連打してる。OKのログが出ればとりあえず大丈夫
大きいDBであればsyncFromのサーバのログにslow queryとかが出るのでそこからsync出来ている事が明確になる。
もしPRIMARYでログが出てしまった場合には慌てずにrs.removeしよう
> rs.syncFrom('10.120.41.199:27017') # もう一つのSECONDARY
7.あとはsyncをまつ。
set:PRIMARY> rs.status()
を実行して追加したSECONDARYが "stateStr" : "SECONDARY",
となってれば完了。
8.もう1個のSECONDARYも同じ事やる
そうするとPRIMARY以外は最適化された容量になる。
最後はPRIMARY
9.PRIMARYとSECONDARYを入れ替える
これは数秒程度書き込みが出来ないタイミングが出来てしまうので、
メンテナンスにしないとダメ。
とはいえ切り替わるのは数秒なので、経験上メンテナンス時間は30分以上かかったことはない。
- PRIMARY側作業
set:PRIMARY> rs.freeze(15)
set:PRIMARY> rs.stepDown(1)
10.あとは元PRIMARYもからっぽにしたら完了
( ´ー`)フゥー...
これよりいい方法をご存知でしたら是非教えていただけたら嬉しいです!