MongoDBでdumpとかrestoreとか

diskいっぱいになってきたのでdb.repairDatabase()で綺麗にしちゃおうかな!と軽い気持ちで実行したら「Cannot repair database」とMongoDBさんに怒られました。
db.rapairDatabase()を実行するには現在の使用disk容量と同じだけのdiskが必要になるっぽく、disk使用量が50%余裕で超えてたので怒られたみたいです。
mongod起動時に選択したデータ保存ディレクトリのmoveChunk配下はどうやら消していい(Can I remove old files in the moveChunk directory?)らしいのでそいつらを消してみたりもしましたがまだまだ足りない。
詰んだ?もしかして詰んだ?と思いながら検索したら以下のページが引っかかりました。
Google Groups

  • copy the data files to disk that has more space and compact it from there then copy it back
  • mount _tmp folder underneath the database folder to other disk and repairDatabase()

うむ。
もっと余裕あるとこにコピーするか_tmpに余裕あるdiskマウントしろよって感じでしょうか。
移すところもなかったのとDB単位のdumpも試してみたかったので、上のどちらにも従わずにdump→restoreする方法を選んでみます。


mongosのポートを指定してdump実行。

$ mongodump --port 27030 --db test3
connected to: 127.0.0.1:27030
DATABASE: test3  to     dump/test3
        test3.table01 to dump/test3/table01.bson
                 5 objects
        test3.system.indexes to dump/test3/system.indexes.bson
                 14 objects
        test3.table01 to dump/test3/table01.bson
                512700/7982533  6%
                1346500/7982533 16%
                1837400/7982533 23%
(略)
                 7982533 objects

終わったみたい。結果を確認します。

$ ls -hal dump/test3/
合計 2.7G
drwxrwxr-x 2 cy_mongodb cy_mongodb 4.0K  6月 22 14:09 .
drwxrwxr-x 4 cy_mongodb cy_mongodb 4.0K  6月 22 14:08 ..
-rw-rw-r-- 1 cy_mongodb cy_mongodb   54  6月 22 14:09 autoIncMgr.bson
-rw-rw-r-- 1 cy_mongodb cy_mongodb 1.8G  6月 22 14:09 table01.bson
-rw-rw-r-- 1 cy_mongodb cy_mongodb 918M  6月 22 14:09 table02.bson
-rw-rw-r-- 1 cy_mongodb cy_mongodb 1.8K  6月 22 14:08 system.indexes.bson

20GBのShard*3が全てdisk60%超えてた割に小さい。
indexの情報もdumpされてるけどそれ自体は持ってないとか、予め多めに容量確保してるとかそのへんがでかいんだろうなー。


dumpが完了したのでDBをdropします。こわい。

> use test3
switched to db test3
> db.dropDatabase()
{ "dropped" : "test3", "ok" : 1 }

やったった!
collectionはdropしても物理削除されないで残るのでdb.repairDatabase()とかする必要があるみたいですが、DBはdropした時点で各shardのDB名のディレクトリごと(ここでいうとtest3ディレクトリ)物理削除されるようです。


早速restoreといきたいところですが、DBをdropした状態でどかんといくと特定のShardに偏ってえらいことになったりしそうなので、予めShardingの設定をしておきます。

> use test3
switched to db test3

> db.stats()
{
        "raw" : {
                "mongodb01:27018" : {
                        "db" : "test3",
                        "collections" : 0,
                        "objects" : 0,
(略)
        "ok" : 1
}
> show dbs  
admin   (empty)
config  0.1875GB
test    (empty)
test3   (empty)

明示的に未作成のDBに対して操作をしてDBを作成します。
多分これやらずにすぐ下の作業してもいいんでしょうけども。
Sharding開始…!

> use admin
switched to db admin
> db.runCommand({enablesharding:"test3"})
{ "ok" : 0, "errmsg" : "already enabled" }

怒られた…!
状態を確認します。

> db.printShardingStatus()               
--- Sharding Status --- 
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
      { "_id" : "shard01", "host" : "mongodb01:27018" }
      { "_id" : "shard02", "host" : "mongodb02:27018" }
      { "_id" : "shard03", "host" : "mongodb03:27018" }
  databases:
        { "_id" : "admin", "partitioned" : false, "primary" : "config" }
        { "_id" : "test", "partitioned" : false, "primary" : "shard02" }
        { "_id" : "test3", "partitioned" : true, "primary" : "shard01" }

なんかShardingできてるらしい。
過去にShardingしてたDBと同じ名前のDBが作られると設定が引き継がれちゃうかんじでしょうか。
流石にcollectionは有効になってなさそうなのでindex作成からやります。

> db.table01.ensureIndex({id:1})
> show collections
table01
> use admin
switched to db admin
> db.runCommand({shardcollection:"test3.table01",key:{id:1}});
{ "collectionsharded" : "test3.table01", "ok" : 1 }
> db.printShardingStatus()
(略)
        { "_id" : "test3", "partitioned" : true, "primary" : "shard01" }
                test3.table01 chunks:
                                shard01 1
                        { "id" : { $minKey : 1 } } -->> { "id" : { $maxKey : 1 } } on : shard01 { "t" : 1000, "i" : 0 }

うむ。
準備できたのでrestoreを実行します。

$ mongorestore --port 27030 --db test3 dump/test3
connected to: 127.0.0.1:27030
Wed Jun 22 14:25:53 dump/test3/table01.bson
Wed Jun 22 14:25:53      going into namespace [test3.table01]
                18779116/1831938804     1%
                35891872/1831938804     1%
                58814363/1831938804     3%
                83954523/1831938804     4%
(略)
Wed Jun 22 14:50:32 { _id: ObjectId('4e00a67ca1915e8b84809654'), ns: "test3.table02", key: { id: 1.0 }, name: "id_1", v: 0 }
Wed Jun 22 14:50:32      14 objects found

おわった!
db.mycoll.totalSize()の結果が3.7GBくらいのDBで25分くらいかかりました。
migration中はrestoreが遅くなるのでさもありなんという感じではありますが、プロダクト環境ではまあ_tmpにマウントとかが現実的な気がするなーと思いました。
ファイルシステムがext3だったりもするのでもろもろスペック次第では大分変わるのかもしれませんけれども。
ちなみにrestore前に張っておいたindexとrestore対象ファイルで持っているindexは重複しているもの(shardkeyのために貼ったindexなど)もありましたが、重複を含め特に問題なくindexは張られているみたいです。
なーるほーどなー。

スポンサーリンク