我在docker-compose中尝试验证MongoDB的自动恢复(故障切换)功能
首先
过去,对于紧急性不高的项目,我们一直使用Standalone(单机结构)的MongoDB。不过,这一次我们尝试使用MongoDB来验证在发生故障时的自动故障转移(从Primary自动切换到Secondary)机制。
故障转移是什么意思?
故障转移是指在主用计算机服务器/系统/网络发生异常情况时,自动切换到冗余的备用计算机服务器/系统/网络的功能。相对于此,手动切换的操作被称为切换。引自维基百科。
环境构建的前提条件。
已安装好了Docker Compose,在实验中使用的是版本为v2.2.1的Docker Compose进行验证。
故障转移验证过程
使用docker-compose下载源代码
请从Github(mongo-replicaset-docker-compose)上克隆源代码。
克隆完成后,请执行$ docker-compose up -d以进行环境配置。
确认副本设置
- Primaryのコンテナに接続します。
$ docker exec -it mongodb-primary bash
使用mongo命令连接到Primary成员。
$ mongo -u root -p toor
使用rs.status命令来查看副本集的状态。
replset:PRIMARY> rs.status();
{
...
"members" : [
{
"_id" : 0,
"name" : "mongodb-primary:27017",
"health" : 1, -- 1/稼働, 2/停止
"stateStr" : "PRIMARY",
...
},
{
"_id" : 1,
"name" : "mongodb-secondary1:27018",
"health" : 1,
"stateStr" : "SECONDARY", -- データの読み書き可能なメンバー
...
},
{
"_id" : 2,
"name" : "mongodb-secondary2:27019",
"health" : 1,
"stateStr" : "SECONDARY", -- データの読み書き可能なメンバー
...
},
{
"_id" : 3,
"name" : "mongodb-arbiter:27020",
"health" : 1,
"stateStr" : "ARBITER", -- SECONDAYが偶数の場合に投票数を奇数にするための仕組み、データストアは持ちませんです。データは持ちません。
...
}
],
...
}
验证从主要到次要的复制。
我将电影数据写入主要位置。
replset:PRIMARY> use movie;
replset:PRIMARY> db.movie.find();
replset:PRIMARY> db.movie.find({});
replset:PRIMARY> db.movie.insert({title: "千と千尋の神隠し"});
WriteResult({ "nInserted" : 1 })
replset:PRIMARY> db.movie.insert({title: "となりのトトロ"});
WriteResult({ "nInserted" : 1 })
replset:PRIMARY> db.movie.insert({title: "ハウルの動く城"});
WriteResult({ "nInserted" : 1 })
replset:PRIMARY> db.movie.insert({title: "もののけ姫"});
WriteResult({ "nInserted" : 1 })
replset:PRIMARY> db.movie.find();
{ "_id" : ObjectId("61cb1bee1484b6d46186ac15"), "title" : "千と千尋の神隠し" }
{ "_id" : ObjectId("61cb1c061484b6d46186ac16"), "title" : "となりのトトロ" }
{ "_id" : ObjectId("61cb1c141484b6d46186ac17"), "title" : "ハウルの動く城" }
{ "_id" : ObjectId("61cb1c201484b6d46186ac18"), "title" : "もののけ姫" }
replset:PRIMARY> exit
bye
root@mongodb-primary:/# exit
exit
确认有在Secondary上复制的数据
$ docker exec -it mongodb-secondary1 bash
root@mongodb-secondary1:/# mongo -u root -p toor --port 27018
replset:SECONDARY> db.getMongo().setSecondaryOk(); <<-- ここ忘れずに実行しないとクエリが実行できません。
replset:SECONDARY> use movie;
switched to db movie
replset:SECONDARY> db.movie.find();
{ "_id" : ObjectId("61cb1bee1484b6d46186ac15"), "title" : "千と千尋の神隠し" }
{ "_id" : ObjectId("61cb1c061484b6d46186ac16"), "title" : "となりのトトロ" }
{ "_id" : ObjectId("61cb1c141484b6d46186ac17"), "title" : "ハウルの動く城" }
{ "_id" : ObjectId("61cb1c201484b6d46186ac18"), "title" : "もののけ姫" }
replset:SECONDARY> exit
bye
root@mongodb-secondary1:/# exit
exit
我们确认了Primary和Secondary的数据是相同的!
暫時停用主要容器進行故障切換確認。
$ docker stop mongodb-primary <<-- プライマリのコンテナの一時停止
mongodb-primary
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bb5f739bbcb5 mongo-express:latest "tini -- /docker-ent…" 43 minutes ago Up 40 minutes 0.0.0.0:8081->8081/tcp mongo-express
e7f47e42ec32 mongo-replicaset-docker-compose_mongo-connector "docker-entrypoint.s…" 43 minutes ago Exited (0) 43 minutes ago mongo-connector
1c69595e200e mongo-replicaset-docker-compose_mongodb-arbiter "docker-entrypoint.s…" 44 minutes ago Up 44 minutes (healthy) 27017/tcp, 0.0.0.0:27020->27020/tcp mongodb-arbiter
fa6683c69b79 mongo-replicaset-docker-compose_mongodb-secondary2 "docker-entrypoint.s…" 44 minutes ago Up 44 minutes (healthy) 27017/tcp, 0.0.0.0:27019->27019/tcp mongodb-secondary2
09fad2c160e7 mongo-replicaset-docker-compose_mongodb-secondary1 "docker-entrypoint.s…" 44 minutes ago Up 44 minutes (healthy) 27017/tcp, 0.0.0.0:27018->27018/tcp mongodb-secondary1
a63d3f8bf48d mongo-replicaset-docker-compose_mongodb-primary "docker-entrypoint.s…" 44 minutes ago Exited (137) 24 seconds ago <<-- プライマリのコンテナが停止されたこと確認
我要确认mongo-replicaset-docker-compose_mongodb-primary的状态是否为Exited。
在Secondary上查看复制集合的情况。
$ docker exec -it mongodb-secondary1 bash
root@mongodb-secondary1:/# mongo -u root -p toor --port 27018
replset:PRIMARY> rs.status();
{
...
"members" : [
{
"_id" : 0,
"name" : "mongodb-primary:27017",
"health" : 0, <<--- 停止状態になってる
"stateStr" : "(not reachable/healthy)",
...
},
{
"_id" : 1,
"name" : "mongodb-secondary1:27018",
"health" : 1,
"stateStr" : "PRIMARY", <<--- secondaryから投票によりPrimaryに昇格されました!!
...
},
{
"_id" : 2,
"name" : "mongodb-secondary2:27019",
"health" : 1,
"stateStr" : "SECONDARY",
...
},
{
"_id" : 3,
"name" : "mongodb-arbiter:27020",
"health" : 1,
"stateStr" : "ARBITER",
...
}
],
...
}
replset:PRIMARY> exit
bye
root@mongodb-secondary1:/# exit
exit
在处理主服务器的故障恢复方面,将主服务器恢复为原始状态。
$ docker start mongodb-primary
mongodb-primary
$ docker exec -it mongodb-secondary1 bash
root@mongodb-secondary1:/# mongo -u root -p toor --port 27018
replset:SECONDARY> rs.stepDown() <<---- 自分自身を降格させる(Secondaryになる)
replset:SECONDARY> rs.status();
{
...
"members" : [
{
"_id" : 0,
"name" : "mongodb-primary:27017",
"health" : 1,
"stateStr" : "PRIMARY",
...
},
{
"_id" : 1,
"name" : "mongodb-secondary1:27018",
"health" : 1,
"stateStr" : "SECONDARY",
...
},
{
"_id" : 2,
"name" : "mongodb-secondary2:27019",
"health" : 1,
"stateStr" : "SECONDARY",
...
},
{
"_id" : 3,
"name" : "mongodb-arbiter:27020",
"health" : 1,
"stateStr" : "ARBITER",
...
}
],
...
}
最终
使用docker-compose构建副本集,并确认主服务器的数据被复制到副本服务器上,当主服务器出现故障时,通过投票选举将副本服务器升级为主服务器,实现自动故障转移而不停止服务。
不建议在生产环境中继续使用此方法。建议将其配置为微服务,并将它们分别作为不同的服务器。