MongoDBのShardingを試してみた。その3 障害発生時の挙動について
今回はMongoDBのSharding環境にて、各サーバが停止した場合の挙動について検証してみたいと思います。
mongosサーバ
最初はmongosサーバです。
早速、mongosサーバを落としてみましょう。
[matsuou1@testsvr mongodb]$ kill -2 14973
次に、mongosサーバに接続してみます。
[matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10000/logdb MongoDB shell version: 1.8.0 connecting to: localhost:10000/logdb Tue Apr 19 23:51:28 Error: couldn't connect to server localhost:10000 shell/mongo.js:81 exception: connect failed
当然と言えば当然ですが、mongosサーバへの接続に失敗します。
まとめ
想定通り、mongosサーバに接続できなくなりました。
各shardには問題なく接続でき、クエリの実行も可能ですが、複数shardをまたがるようなクエリの実行は出来なくなります。
下手な構成な場合は単一障害点となりうるので、基本的にはwebサーバやアプリサーバなど実際にアプリケーションが動作するサーバで
実行させて、プロセスの死活監視を行い、障害が発生したらプロセスの再起動を行う感じの運用になるのではないでしょうか。
mongosは、単なるルーティングプロセスでデータの管理はしないので、復旧時に特に気を使う必要はないかと思います。
shardサーバ
次は、3つあるshardサーバのうち1つを落としてみます。
shard3のプロセスIDを確認し、落としてみます。
[matsuou1@testsvr mongodb]$ kill -2 18436
試しにカウントを取ってみましたが、エラーとなります。
> db.logs10.count() Tue Apr 19 14:45:54 uncaught exception: count failed: { "assertion" : "DBClientBase::findOne: transport error: localhost:10003 query: { count: \"logs10\", query: {} }", "assertionCode" : 10276, "errmsg" : "db assertion failure", "ok" : 0 } > db.logs10.count() Tue Apr 19 14:45:57 uncaught exception: error { "$err" : "socket exception", "code" : 11002 }
shard keyでアクセスし、shard3以外のshardのみにアクセスする場合は、クエリ―は実行可能
> db.logs10.find({ uid : "f26AKDmNMkIXXXXt"}) { "_id" : ObjectId("4da7d407af13de0b7c6XXXX0"), "month" : "2010/02", "uid" : "f26AKDmNMkIXXXXt", "timestamp" : "2010/02/28 16:00:51", "path" : "/?pid=P07K&sid=E74D&uid=1", "device" : "940P" } { "_id" : ObjectId("4da7d407af13de0b7c6c35cd"), "month" : "2010/02", "uid" : "f26AKDmNMkIXXXXt", "timestamp" : "2010/02/28 16:01:12", "path" : "/", "device" : "940P" } { "_id" : ObjectId("4da7d407af13de0b7c6c369d"), "month" : "2010/02", "uid" : "f26AKDmNMkIXXXXt", "timestamp" : "2010/02/28 16:06:06", "path" : "/index.html", "device" : "940P" } { "_id" : ObjectId("4da7d44aaf13de0b7c7aa66d"), "month" : "2010/03", "uid" : "f26AKDmNMkIXXXXt", "timestamp" : "2010/03/31 16:51:34", "path" : "/?pid=P07K&sid=E74D&uid=1", "device" : "940P" }
障害中に実行可能なクエリのまとめ
shard環境では、targetedとglobalの2つのタイプのクエリに分けられます。
targetedは、最小限のshard(多くの場合は1つのみ)にアクセスし、globalはほぼ全てのshardにアクセスします。
つまり、このタイプの違いによって、障害中に実行可能かどうかが分かれることになります。
クエリのタイプについては、マニュアルの Operation Types を参照してください。
- targetedクエリ
- 実行可能なクエリの例
・shard keyを指定して、落ちているshard以外のshardの検索
・shard keyを指定して、落ちているshard以外のshardのアップデート
・インサート
- globalクエリ
- 実行不可能なクエリの例
・shard keyを指定して、落ちているshardのデータの検索
・shard keyを指定しない検索
まとめ
shard障害が発生すると、障害shardを参照するクエリは実行エラーとなるが、問題ないshardへのshard keyを使用したクエリは実行可能。
アプリへの影響が大きいので、基本的にはReplica set を構成し、冗長化を行うべきです。
configサーバ
最後に、configサーバが落ちた場合についてです。
先ほどと同じように、configサーバを落としてみます。
[matsuou1@testsvr mongodb]$ kill -2 27480
この状態で、以下の操作を行ってみます。
- shardの追加、削除
まずは、shard4を新たに起動します。
[matsuou1@testsvr mongodb]$ ./bin/mongod --shardsvr --port 10005 --dbpath /tmp/mongodb/shard4 --logpath /tmp/mongodb/log/shard4.log &
adminサーバより、addshardコマンドを実行します。
[matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10000/admin MongoDB shell version: 1.8.0 connecting to: localhost:10000/admin > db.runCommand( { addshard : "localhost:10005" } ); Wed Apr 20 00:48:51 uncaught exception: error { "$err" : "socket exception", "code" : 11002 }
想定通りにエラーとなります。クラスタのメタデータを管理するサーバが落ちているので当然ですよね。
- 大量データロード
次に大量のデータをロードし、chunkがどのようになるか確認します。
1行のみ入れてあるcollectionに対し、100万行程のアクセスログをインポートしてみます。
logdb.logs12 chunks: shard0000 1 { "timestamp" : { $minKey : 1 } } -->> { "timestamp" : { $maxKey : 1 } } on : shard0000 { "t" : 1000, "i" : 0 }
chunkの分割や移動は行われなくなるため、色々大変となるところの検証を行うつもりでいたのですが、
shardやmongosが大量のExceptionを吐いて、mongoimportが激遅に。。。
shardのログ
Wed Apr 20 01:24:23 [initandlisten] connection accepted from 127.0.0.1:46419 #53871 Wed Apr 20 01:24:23 [conn53871] end connection 127.0.0.1:46419 Wed Apr 20 01:24:23 [initandlisten] connection accepted from 127.0.0.1:46421 #53872 Wed Apr 20 01:24:23 [conn53846] end connection 127.0.0.1:46369
mongosのログ
Wed Apr 20 01:25:57 [conn2] DBException in process: socket exception Wed Apr 20 01:25:57 [conn2] ~ScopedDBConnection: _conn != null Wed Apr 20 01:25:57 [conn2] DBException in process: socket exception Wed Apr 20 01:25:57 [conn2] ~ScopedDBConnection: _conn != null Wed Apr 20 01:25:57 [conn2] DBException in process: socket exception
わざわざ、configサーバを落とした状態でmongoimportする人はなかなかいないと思いますが、エラー吐きまくりな状態になるのでやめておいたほうが無難です。時間があったら、もう少し調査&最新版で検証してみます。
まとめ
configサーバ障害が発生すると、システムのメタデータはリードオンリーになるため、shardの追加、削除などは出来なくなります。
システムは機能し続けますが、chunkの分割や移動は行われなくなるため、このタイミングで大量のデータロードを行うとmigrateできないために、アンバランスなshardができてしまう可能性があります。(マニュアルより。。。)
また、configサーバが落ちている場合は、クラスタのメタデータが必要なためmongosサーバが起動できません。
configサーバと同時にmongosサーバも落ちた場合は、先にconfigサーバ復旧後にmongosサーバを復旧させる必要があります。
マニュアルでは、ダメージは大きくないよと記載されていますが、意外なところで思わぬバグ等を踏む可能性もあるので、可能な限り早く復旧しましょう。
全体まとめ
今回は、sharding環境構成する3つのサーバに対し、それぞれ障害が発生した場合にどういう現象が発生するか検証してみました。
障害発生時に焦るよりは、障害発生時にどのような状況になるのかを事前に把握し、速やかに復旧させたいですね。
障害が発生しない、または、きちんと冗長構成を取っておくのが良いのは、間違いないのですが。
色々、踏み込めてない気がするので、時間があれば後で追記するかもしれません。