MongoDBのSharding機能で遊ぶ - hachiのブログで、Shardingを試したので、今度はRelipcaSetで遊んでみました。
構成は以下のようにしました。Shardingのときとポート番号などを変えているのはわかりやすくするためです。
図を見れば一目瞭然ですが、こんな変な構成は実際には組みません。実際は各ShardにReplicaSetを組んでいきます。
今回はSharding部分の説明は省いていきます。
mongodの設定
mongod --shardsvr --dbpath /data/mongod1_r0 --logpath /data/mongod1_r0/log/mongod1_r0.log --port 27030 --fork --nojournal --replSet rs mongod --shardsvr --dbpath /data/mongod1_r1 --logpath /data/mongod1_r1/log/mongod1_r1.log --port 27031 --fork --nojournal --replSet rs mongod --shardsvr --dbpath /data/mongod1_r2 --logpath /data/mongod1_r2/log/mongod1_r2.log --port 27032 --fork --nojournal --replSet rs
ここでのポイントは最後の"--replSet rs"です。これでこれら3つが同じReplicaSetということを示してます。ログファイルを見ると
Sun Mar 4 15:48:57 [rsStart] replSet info you may need to run replSetInitiate -- rs.initiate() in the shell -- if that is not already done Sun Mar 4 15:49:07 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG)
と出てきます。初期化しなさいということなので、初期化しましょう。
ReplicaSetの初期化
mongo localhost:27030 use admin var config = {_id: 'rs', members: [ {_id: 0, host: 'localhost:27030'}, {_id: 1, host: 'localhost:27031'}, {_id: 2, host: 'localhost:27032'}] }; rs.initiate(config);
_idはいつもMongoが勝手に設定してくれるのですが、ここでは自分で設定します。レプリカ名と対象のHost名を引数にしてinitiateへ渡します。
rs.status()を実行すると、RelipcaSetの状態が表示されます。とりあえず、stateStrを注目すると1つはPRIMARY、残り2つがSECONDARYになっていくのがわかります。順調に進んでいくログを見るのは楽しいですね。
rs.status() { "set" : "rs", "date" : ISODate("2012-03-04T15:58:18Z"), "myState" : 2, "members" : [ { "_id" : 0, "name" : "localhost:27030", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "optime" : { "t" : 1330876687000, "i" : 1 }, "optimeDate" : ISODate("2012-03-04T15:58:07Z"), "self" : true }, { "_id" : 1, "name" : "localhost:27031", "health" : 1, "state" : 5, "stateStr" : "STARTUP2", "uptime" : 10, "optime" : { "t" : 0, "i" : 0 }, "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2012-03-04T15:58:16Z"), "pingMs" : 20, "errmsg" : "initial sync need a member to be primary or secondary to do our initial sync" }, { "_id" : 2, "name" : "localhost:27032", "health" : 1, "state" : 5, "stateStr" : "STARTUP2", "uptime" : 10, "optime" : { "t" : 0, "i" : 0 }, "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2012-03-04T15:58:16Z"), "pingMs" : 0, "errmsg" : "initial sync need a member to be primary or secondary to do our initial sync" } ], "ok" : 1 } PRIMARY> rs.status() { "set" : "rs", "date" : ISODate("2012-03-04T15:58:30Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "localhost:27030", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "optime" : { "t" : 1330876687000, "i" : 1 }, "optimeDate" : ISODate("2012-03-04T15:58:07Z"), "self" : true }, { "_id" : 1, "name" : "localhost:27031", "health" : 1, "state" : 3, "stateStr" : "RECOVERING", "uptime" : 22, "optime" : { "t" : 0, "i" : 0 }, "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2012-03-04T15:58:28Z"), "pingMs" : 4, "errmsg" : "initial sync need a member to be primary or secondary to do our initial sync" }, { "_id" : 2, "name" : "localhost:27032", "health" : 1, "state" : 3, "stateStr" : "RECOVERING", "uptime" : 22, "optime" : { "t" : 0, "i" : 0 }, "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2012-03-04T15:58:28Z"), "pingMs" : 0, "errmsg" : "initial sync need a member to be primary or secondary to do our initial sync" } ], "ok" : 1 } PRIMARY> rs.status() { "set" : "rs", "date" : ISODate("2012-03-04T15:58:50Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "localhost:27030", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "optime" : { "t" : 1330876687000, "i" : 1 }, "optimeDate" : ISODate("2012-03-04T15:58:07Z"), "self" : true }, { "_id" : 1, "name" : "localhost:27031", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 42, "optime" : { "t" : 1330876687000, "i" : 1 }, "optimeDate" : ISODate("2012-03-04T15:58:07Z"), "lastHeartbeat" : ISODate("2012-03-04T15:58:48Z"), "pingMs" : 0 }, { "_id" : 2, "name" : "localhost:27032", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 42, "optime" : { "t" : 1330876687000, "i" : 1 }, "optimeDate" : ISODate("2012-03-04T15:58:07Z"), "lastHeartbeat" : ISODate("2012-03-04T15:58:48Z"), "pingMs" : 0 } ], "ok" : 1 }
Shardingの設定
少しだけShardingの設定がかわります。mongosに接続後
mongos> db.runCommand({'addShard': 'rs/localhost:27030,localhost:27031,localhost:27032'}) { "shardAdded" : "rs", "ok" : 1 } mongos> db.runCommand({'addShard': 'localhost:27040'}) { "shardAdded" : "shard0000", "ok" : 1 } mongos> db.runCommand({'addShard': 'localhost:27050'})
として、最初のshardを追加するときに"レプリカ名/ホスト名1,ホスト名,…"とします。Shardの設定を見ると
mongos> db.runCommand( { listshards : 1 } ); { "shards" : [ { "_id" : "rs", "host" : "rs/localhost:27030,localhost:27032,localhost:27031" }, { "_id" : "shard0000", "host" : "localhost:27040" }, { "_id" : "shard0001", "host" : "localhost:27050" } ], "ok" : 1 }
で、OKです。
これで、PRIMARYのプロセスをkillすると、自動的にSECONDARYに切り替わります。
Mon Mar 5 16:08:29 [rsHealthPoll] replSet info localhost:27030 is down (or slow to respond): DBClientBase::findN: transport error: localhost:27030 query: { replSetHeartbeat: "rs", v: 1, pv: 1, checkEmpty: false, from: "localhost:27031" } Mon Mar 5 16:08:29 [rsHealthPoll] replSet member localhost:27030 is now in state DOWN Mon Mar 5 16:08:30 [rsMgr] replSet info electSelf 1 Mon Mar 5 16:08:30 [rsMgr] replSet PRIMARY
落ちてる間にデータを更新してみましょう。
mongo localhost:27021 MongoDB shell version: 2.0.2 connecting to: localhost:27021/test mongos> var user = db.user.findOne({userId:1}) mongos> user null
お、ひっかからない。PRIMARYを見に行ってみよう。
PRIMARY> var user = db.user.findOne({userId:1}) PRIMARY> user { "_id" : ObjectId("4f54e670cc67d707e0df245e"), "userId" : 1, "name" : "userName11", "createAt" : 1330964080067 }
あるね。再度、mongosから見に行ってみよう
mongos> var user = db.user.findOne({userId:1}) mongos> user { "_id" : ObjectId("4f54e670cc67d707e0df245e"), "userId" : 1, "name" : "userName11", "createAt" : 1330964080067 }
あれ?あるなぁ…データの同期中だったのかな?ちなみにSECONDARYから見るとどうなるのかな?
SECONDARY> use blog switched to db blog SECONDARY> var user = db.user.findOne({userId:1}) Mon Mar 5 16:22:38 uncaught exception: error { "$err" : "not master and slaveok=false", "code" : 13435 }
ここでslaveが見れないのはslave側でデータの取得を許可していないためです。rs.slaveOkを実行するとslaveから実行できます。
とりあえず基本的な設定はこのへんで終了。
参考:
Replica Sets - MongoDB
Replica Set Tutorial - Docs-Japanese - 10gen Confluence