MongoDBのShardingを試してみた。その2 Migration中の挙動について
Sharding環境にて、shard keyを使用しない以下のクエリに問題があることが知られている。
(第2回MongoDB勉強会の@doryokujinさんの発表参照。私の参加日記は ここ から)
- Chunk Migration中のcount
- 同時書き込み発生時のsingle-update()
- 同時書き込み発生時のunique index
- tmp_collectionが削除されないmapreduce
今回は、Sharding環境にて、chunkのMigration中の各クエリの挙動について検証します。
同時書き込みの発生再現は、難しいので今回は割愛します。
この検証では、mongodb 1.8.0を使用しています。
構成については、 MongoDBのShardingを試してみた。その1 を参照
Chunk Migration中のcount
原因
- Chunk Migration中は処理が完了するまで、移動元、移動先に同じchunkが存在する。
- 完全にコピーが完了し、configサーバが更新されて完了となる。
検証
まずは、意図的にchunkの偏りを発生させます。
sharding設定前に100万件程のアクセスログを投入し、確認していこうかと思います。
[matsuou1@testsvr mongodb]$ ./bin/mongoimport -h localhost:10001 -d logdb -c logs10 --ignoreBlanks --type tsv --fields month,uid,timestamp,path,device /tmp/ mongodb/work/access_201003.log connected to: localhost:10001 (略) imported 946611 objects
shardingの設定を行い、chunkの分散を確認します。
[matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10000/logdb MongoDB shell version: 1.8.0 connecting to: localhost:10000/logdb > db.logs10.count(); 946611 > db.logs10.ensureIndex( { uid : 1 } ); > use admin switched to db admin > db.runCommand( { shardcollection : "logdb.logs10" , key : { uid : 1 } } ); { "collectionsharded" : "logdb.logs10", "ok" : 1 } > db.printShardingStatus(); (略) logdb.logs10 chunks: shard0001 1 shard0002 1 shard0000 266 too many chunksn to print, use verbose if you want to force print > db.printShardingStatus(); (略) logdb.logs10 chunks: shard0001 25 shard0002 25 shard0000 218
最初、shard0000にあった全てのchunkが、shard0001、shard0002にmigrationが行われ、平準化されています。
全て平準化される前に、countを実施するとchunk migration途中のchunkが重複カウントされ、正しい値より大きな値が表示されるはず。
とりあえず、shard keyではないtimestampを条件にしたcountを10秒に1回程度実行してみましょう。
> db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285133 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285108 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285120 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285047 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285128 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285140 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284984 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285153 ★
まとめ
★がついている個所が、正しい値(284078)より多い数値が表示された。
表示される値は都度異なり、重複カウントされるchunkに依存する。
25回中6回、不正な値が出力された。約25%なので、migration中はかなりの確率で発生しうると言える。
運用中のchunk migration時にも気をつける必要があるが、single構成からsharding構成に変更する際も当然注意が必要。