読者です 読者をやめる 読者になる 読者になる

moveChunkでドキュメントが消える件の検証

MongoDB

色々いじって確実に再現するっぽいパターンがあったのでめも。

// mongosで対象DBに入ってindex作成(いずれかをDESCに)
> db.table01.ensureIndex({userId:1,targetuserId:-1})

// adminDBに入ってcollectionのSharding開始。フィールド自体は同じものを指定
> db.runCommand({shardcollection:"test2.table01",key:{userId:1,targetuserId:1}})  

// index確認
> db.table01.getIndexes()                 
[
        {
                "name" : "_id_",
                "ns" : "test2.table01",
                "key" : {
                        "_id" : 1
                },
                "v" : 0
        },
        {
                "_id" : ObjectId("4ddd1c686975e1482915920c"),
                "ns" : "test2.table01",
                "key" : {
                        "userId" : 1,
                        "targetuserId" : -1
                },
                "name" : "userId_1_targetuserId_-1",
                "v" : 0 
        },…(1)
        {
                "ns" : "test2.table01",
                "key" : {
                        "userId" : 1,
                        "targetuserId" : 1
                },
                "name" : "userId_1_targetuserId_1",
                "v" : 0
        }…(2)
]

// テストデータをぶち込んだ後Shardingのステータスを確認
> db.printShardingStatus()
                test2.table01 chunks:
                                set02   2
                                set01   4
                        { "userId" : { $minKey : 1 }, "targetuserId" : { $minKey : 1 } } -->> { "userId" : "userId1", "targetuserId" : "targetUserId1" } on : set02 { "t" : 2000, "i" : 0 }
                        { "userId" : "userId1", "targetuserId" : "targetUserId1" } -->> { "userId" : "userId2", "targetuserId" : "targetUserId2" } on : set01 { "t" : 3000, "i" : 6 }
(略)

// moveChunkするchunkの範囲にいるドキュメント数を確認
> db.table01.count({userId:"userId1"})
3

// moveChunkを実行
> db.runCommand({moveChunk:"test2.table01",find: { "userId" : "userId1",targetuserId:"targetUserId1" },to:"set03"})      
{ "millis" : 6164, "ok" : 1 }

// 移動元(ここでいうとset01)のログを確認
Thu May 26 00:25:51 [conn146] moveChunk number of documents: 55597
(略)
Thu May 26 00:30:13 [cleanupOldData] moveChunk deleted: 55599
// ↑移動対象を越えるドキュメントが削除されている

// 先ほど確認したドキュメント数を再度確認
> db.table01.count({userId:"userId1"})
1
// 減ってる

複合ShardKeyかつensureIndexでどれかのフィールドをDESC指定してindex作成((1)のindex)、shardcollectionではASCしか指定できないのでASCを指定すると自動でindex生成((2)のindex)。
この条件でmoveChunkを実行すると、ShardKey1に一致するドキュメントが移動されないにもかかわらず削除対象になってしまい、本来消えるべきでないドキュメントが消えてしまう。
ここでいう(2)のindexを予めensureIndexで作っておいた場合、同現象は再現しませんでした。
どうやらensureIndexで作成するとかshardcollectionで作成するとか関係なくて、複合ShardKeyの組み合わせが一致してるindexがあって、かついずれかにDESCが指定されているものがASCが指定されているものより先に作成されている場合に起きるみたい。
なので、

db.table01.ensureIndex({userId:1,targetuserId:-1})
db.table01.ensureIndex({userId:1,targetuserId:1})
db.runCommand({shardcollection:"test2.table01",key:{userId:1,targetuserId:1}})

これだと再現するが、

db.table01.ensureIndex({userId:1,targetuserId:1})
db.table01.ensureIndex({userId:1,targetuserId:-1})
db.runCommand({shardcollection:"test2.table01",key:{userId:1,targetuserId:1}})

これだと再現しない。


大分見当違いのことを書いてる可能性がありますが確認した範囲ではこんなかんじの挙動。うーんうーん。なぞだ。

スポンサーリンク