场景

起因是因,公司生产环境使用的阿里云提供 Mongodb 云服务(3节点),而在公司实际项目的config/database.php

数据库连接配置中确只用了一个主节点,每次因主节点负载过高主从自动切换(Primary 切换为 Secondary)后,而项目配置中确依然是连接的主库(Primary),便导致不能写入(Secondary)后,而项目配置中确依然是连接的主库(Primary),便开始收到一堆不能写入报警(Secondary 只能读不能写)。然后赶紧登陆阿里云手动切换回来(这酸爽)。

为了能做到主从切换后服务依然高可用,测试服使用 Docker 搭建3节点 Mongodb 集群服务,配置项目测试

集群搭建

3节点的 Mongodb 集群,容器名为 mongo-master 作为默认 Primarymongo-salve 作为 Secondarymongo-arbiter 仅作为选举节点,不做数据副本。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 创建network
docker network new mongo-network

# 启动主节点
docker run -d --rm --net=mongo-network -it --name mongo-master -v /data/mongo/db/:/data/db/ -v /data/mongo/configdb/:/data/configdb -p 27017:27017 mongo --dbpath /data/db --replSet mongoreplset

# 启动从节点
docker run -d --rm --net=mongo-network -it --name mongo-salve -p 27018:27017 mongo --replSet mongoreplset

# 启动选举节点
docker run -d --rm --net=mongo-network -it --name mongo-arbiter -p 27019:27017 mongo --replSet mongoreplset

测试节点服务

1
2
3
4
5
# 启动 mongo-client
docker run --rm -it --name mongo-client --net=mongo-network mongo /bin/bash

# 连接主节点
mongo --host mongo-master

配置节点数据同步

查看容器 IP,配置节点数据同步用:

1
docker inspect mongo-network

登录其中一台节点,根据上面的 ip 配置主从节点,

1
2
3
4
5
6
config = {_id:"mongoreplset", version:1, members:[
    {_id:0, host:"192.168.112.2:27017", priority:2},
    {_id:1, host:"192.168.112.3:27017", priority:1},
    {_id:2, host:"192.168.112.6:27017", priority:1,arbiterOnly:true}
]}
rs.initiate(config)

配置后再次登录每个节点,看到节点角色的变化,那说明便是成功了,我的记录如下

登录主节点(主从切换后)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
root@0e645014d20c:/# mongo --host mongo-master
MongoDB shell version v4.2.7
connecting to: mongodb://mongo-master:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("d7846eb2-b4b5-4c33-9cdb-b5f7a0478d60") }
MongoDB server version: 4.2.7
Server has startup warnings: 
2020-06-09T15:13:32.051+0000 I  STORAGE  [initandlisten] 
...
...
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---

mongoreplset:SECONDARY> 

登录从节点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
root@0e645014d20c:/# mongo --host mongo-salve 
MongoDB shell version v4.2.7
connecting to: mongodb://mongo-salve:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("7c55b482-ebb9-48ae-a465-7efe23ae37aa") }
MongoDB server version: 4.2.7
Server has startup warnings: 
...
...
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---

mongoreplset:PRIMARY> 

查看配置,命令:rs.status()

如果配置已经添加过,再次添加提示already initialized,采用如下方式修改:

1
2
3
rsconf = rs.conf()
rsconf.members = [{_id:0, host:"192.168.112.2:27017", priority:2},{_id:1, host:"192.168.112.3:27017", priority:1},{_id:2, host:"192.168.112.6:27017", priority:1,arbiterOnly:true}]
rs.reconfig(rsconf, {force: true})

小结

因为每次销毁容器,再次启动都会导致 IP 的变化,因为容器 IP 直接决定着主从角色,每次配置还得调整这是很麻烦的。着实不太舒服,建议使用docker-compose编排来做这事

最后自己这么搭建的再使用DSN连接方式测试时,遇到错误[No suitable servers found (serverselectiontryonce set): connection error calling ismaster on,至此也不晓得是啥原因,经测试阿里云给出的没这问题,临时测试服先继续使用单节点,生产配置采用 replicaSet

参考文章