はじめに
MongoDB をつかったことがなかったのですが、触ってみてレプリケーションに出会いました。
レプリケーションは 複数の mongo を動かす必要があるので、 Docker をつかってローカルで、レプリケーションの動きを体験 してみました。
3つのコンテナを用意して、以下のような役割を与えます。
- Primary
- Secondary
- Arbiter
これで、Primary の mongo を止めて、Secondary が Primary に昇格するのを眺めたいと思います。
対象読者
- MongoDB つかったことない
- MongoDB のレプリケーション知らない
- レプリケーションの概念はなんとなくわかる
- Docker は使ったことある
- 僕
バージョン
- centos6
- mongo3.6
流れ
- コンテナを 3 つ用意する
- 各コンテナの間で通信できる IPAddress を確認
- 各コンテナで mongo を起動する
- Primary, Secondary, Arbiter の設定をする
- 動作を確認する
Step1 コンテナを 3 つ用意する
Docker Hub にイメージを用意しましたので、それを使います。
ターミナルを 3 つ開きます。そしてそれぞれ以下を叩きます。
3つかきますが、それぞれコンテナ名が mongo1
mongo2
mongo3
としているだけです。
$ docker run -it --name mongo1 mochizukikotaro/centos6-mongo3.6:0.0.1 bash
$ docker run -it --name mongo2 mochizukikotaro/centos6-mongo3.6:0.0.1 bash
$ docker run -it --name mongo3 mochizukikotaro/centos6-mongo3.6:0.0.1 bash
image (mochizukikotaro/centos6-mongo3.6/) の説明
centos6 をベースにして、mongo3.6を入れたイメージになっています。 service mongod start
とかが打てる状態になっています。
また、 /etc/mongod.conf
と /etc/yum.repos.d/mongodb-org-3.6.repo
を置いてあります。
詳細はこちらをご覧ください。
https://hub.docker.com/r/mochizukikotaro/centos6-mongo3.6/
Step2 各コンテナの間で通信できる IPAddress を確認
// プロセスを確認
$ docker ps --format "{{.Image}}\t{{.Names}}"
mochizukikotaro/centos6-mongo3.6:0.0.1 mongo3
mochizukikotaro/centos6-mongo3.6:0.0.1 mongo2
mochizukikotaro/centos6-mongo3.6:0.0.1 mongo1
// IPAddress を確認
$ dk inspect -f '{{.NetworkSettings.IPAddress}}' mongo1
172.17.0.2
上記のように IPAddress を確認できます。結果は以下の通りです。これをあとでレプリカセットを設定するときに使います。
コンテナ名 | IP |
---|---|
mongo1 | 172.17.0.2 |
mongo2 | 172.17.0.3 |
mongo3 | 172.17.0.4 |
Step3 各コンテナで mongo を起動する
# service mongod status <- 確認したければ
# service mongod start
ただ、start するだけですね。
Step3 Primary, Secondary, Arbiter の設定をする
ここが本題ですね。基本的に terminal_1 で作業をします。
まずは rs.status()
でレプリカセットのステータスを見ます。
# mongo
> rs.status()
{
"info" : "run rs.initiate(...) if not yet done for the set",
"ok" : 0,
"errmsg" : "no replset config has been received",
"code" : 94,
"codeName" : "NotYetInitialized"
}
まだセットしてないなら、 rs.initiate(...)
するようにとあります。
なので、早速したいと思います。
まずは Primary をつくる
ちなみに、 /etc/mongod.conf
には以下の設定をしています。
replication:
replSetName: "testRepl"
ですので、mongo 内で以下を打ちます。
rs.initiate(
{
_id: "testRepl",
members: [
{ _id: 0, host : "172.17.0.2:27017" },
]
}
)
IPAddress は Step2 で取得した mongo1 コンテナの IPAddress です。
上をうつと下のように帰ってきて、無事成功しました。
{
"ok" : 1,
"operationTime" : Timestamp(1520298587, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520298587, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
すると以下のように rs.status()
が変わります。
testRepl:PRIMARY> rs.status()
{
"set" : "testRepl",
"date" : ISODate("2018-03-06T01:13:23.932Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1520298799, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1520298799, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1520298799, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1520298799, 1),
"t" : NumberLong(1)
}
},
"members" : [
{
"_id" : 0,
"name" : "172.17.0.2:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1643,
"optime" : {
"ts" : Timestamp(1520298799, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-03-06T01:13:19Z"),
"electionTime" : Timestamp(1520298587, 2),
"electionDate" : ISODate("2018-03-06T01:09:47Z"),
"configVersion" : 1,
"self" : true
}
],
"ok" : 1,
"operationTime" : Timestamp(1520298799, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520298799, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
これで、mongo1 が Primary になりました。
つづいて Secondary をつくる
mongo2 を Secondary にします。 rs.add()
を使います。
mongo2 の IP が 172.17.0.3
なので、以下のようになります。
testRepl:PRIMARY> rs.add({_id: 1, host: "172.17.0.3:27017"})
{
"ok" : 1,
"operationTime" : Timestamp(1520298995, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520298995, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
これで、 terminal_2 を確認しますと、以下のように Secandary として入力を待っている感じです。
testRepl:SECONDARY>
最後に Arbiter をつくる
mongo3 の IP は 172.17.0.4
なので以下のようにします。
testRepl:PRIMARY> rs.addArb("172.17.0.4:27017")
{
"ok" : 1,
"operationTime" : Timestamp(1520299760, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520299760, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
mongo3 を確認すると、無事に Arbiter となっています。
testRepl:ARBITER>
動作を確認する
まずは Primary で適当にデータを入れます。
testRepl:PRIMARY> use study
switched to db study
testRepl:PRIMARY> db.user.insert({name: 'taro'})
WriteResult({ "nInserted" : 1 })
testRepl:PRIMARY> db.user.find()
{ "_id" : ObjectId("5a9def656b45e5c362a6bf4d"), "name" : "taro" }
それを Secondary で確認します。
testRepl:SECONDARY> rs.slaveOk()
testRepl:SECONDARY> use study
switched to db study
testRepl:SECONDARY> db.user.find()
{ "_id" : ObjectId("5a9def656b45e5c362a6bf4d"), "name" : "taro" }
つぎに、Primary である mongo1 を止めて見ます。以下のように切り替わることがわかりました。
また、 Primary で rs.stepDown()
を打つことで、自身を Secondary に落として、他方を Primary にあげることもできます。
以上です。
補足
いろいろなかったことにしたいとき
mongod.conf の replication をコメントアウト
show databases
use local
db.dropDatabase()
コメントインして、再起動。
rs.initiate() をなかったことにしたいとき
use local
db.system.replset.remove({})