最近项目中需要用到MongoDB,由于资源有限,手头上就只有两台云服务器和一些本地服务器,购买阿里云的MongoDB最低配的1C2G3节点的一年也要三四千块钱,索性自己搭一个吧。
以下理论性质的内容是我用两天时间从各个博客汇总过来,再经过我个人的理解总结出来的,所以可能会有偏差,还望不吝赐教
MongoDB集群分为三种:
- 主从复制模式(Master Slave Replication)
- 副本集模式(Replica Set)
- 分片模式(Sharding)
主从复制模式(Master Slave Replication)
从官方文档中可以看到,该模式已经从3.6版本开始被废弃了
简单来说就是一个主服务器跟着几个从服务器,对数据的写操作只能通过主服务器,但会同步到从服务器上,所以可以保证主从数据一致。由于主从身份确定,所以一旦主服务器宕机,则对数据的写操作就不能完成了,仅能切换到从服务器上,以保证读操作不受影响,直至主服务器恢复。
参考官方文档:https://docs.mongodb.com/v3.6/core/master-slave/
副本集模式(Replica Set)
副本集模式和主从复制模式很像,都是只能对主节点进行写,写操作同步到副(从)节点,以保证数据一致性。不一样的地方是,主副关系不是确定不变的,一旦出现主节点宕机,则会触发选举,重新选举出主节点,宕机节点在恢复后又可以重新加入集群,如此保证高可用性。节点数最少需要为3,且为奇数,原理类似zookeeper的脑裂问题。
如下图所示,是一个最简单的1主2副三节点模式,节点间通过心跳保证彼此状态公开。
主节点:
- 向副节点同步数据
副节点:
- 触发选举
- 参与选举
- 参与投票
如果服务器资源有限,可以将一台服务器设置为投票节点,仅参与投票,不保存业务数据(我就是这么做的)
我们还可以设置一台隐藏节点,该节点不参与选举(priority=0),对前端不可见,且只保存业务数据
隐藏节点:
- 不参与选举
- 参与投票
- 对前端不可见
在隐藏节点的基础上,如果添加延迟复制的能力,就变成了延迟复制节点
所以延迟复制节点可以用来做定时备份的任务,比如每个小时备份一次数据
分片模式(Sharding)
分片模式是为了应对大数据集和高吞吐量操作而产生的。具体我还不太了解,和之前的模式相比最大的不同就是每个节点保存的业务数据都只是所有数据的一部分。
实际生产环境部署的方案是副本集或者副本集+分片的方式,由于我这个项目的数据量不大,所以就只采用3节点的副本集。
参考官方文档:https://docs.mongodb.com/manual/replication/
看过一篇博客,收获不少,推荐给你们https://jelly.jd.com/article/5f990ebbbfbee00150eb620a
理论说完了,现在我讲一下如何通过docker部署3节点replica set
所有操作都写在脚本中了,一共四个文件
.
├── setup.sh
├── docker-compose-0.yml
├── docker-compose-1.yml
└── docker-compose-2.yml
假设有三台服务器,三台服务器在一个局域网内。
- 服务器A
- 公网ip:39.11.11.111
- 局域网ip:10.11.11.111
- 服务器B
- 公网ip:39.11.11.112
- 局域网ip:10.11.11.112
- 服务器C
- 公网ip:39.11.11.113
- 局域网ip:10.11.11.113
我们打算在服务器A上部署主节点,服务器B上部署副节点,服务器C上部署投票节点。
需要先在服务器B和服务器C上执行如下代码,最后在服务器A上执行如下代码,注意一定要按顺序。
>>> bash setup.sh
特别的,我将服务器A的priority设置为最高的2,效果就是在A宕机后,B被选为主节点,而当服务器A恢复后,则A重新当选主节点。
# @author : microfat
# @time : 04/25/21 15:29:04
# @File : setup.sh
#!/bin/sh
IP=$(curl https://api.ipify.org)
echo "$IP"
if [ $IP == "39.11.11.111" ]
then
echo "mongo0"
docker-compose -f docker-compose-0.yml up -d
sleep 5
docker exec mongo0 mongo --eval "
rs.initiate(
{
_id : 'rs0',
members: [
{ _id : 0, host : \"10.11.11.111:27017\", priority: 2 },
{ _id : 1, host : \"10.11.11.112:27017\", priority: 1 },
{ _id : 2, host : \"10.11.11.113:27017\", priority: 1, arbiterOnly: true }
]
}
)
"
exit
elif [ $IP == "39.11.11.112" ]
then
echo "mongo1"
docker-compose -f docker-compose-1.yml up -d
elif [ $IP == "39.11.11.113" ]
then
echo "mongo2"
docker-compose -f docker-compose-2.yml up -d
else
echo "服务器不在部署范围之内"
fi
# @author : microfat
# @time : 04/25/21 15:29:04
# @File : docker-compose-0.yml
version: "3.8"
services:
mongo0:
container_name: mongo0
image: mongo
expose:
- 27017
ports:
- 27017:27017
volumes:
- mongo0:/data/db
restart: always
entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0", "--journal", "--enableMajorityReadConcern", "false" ]
volumes:
mongo0:
# @author : microfat
# @time : 04/25/21 15:29:10
# @File : docker-compose-1.yml
version: "3.8"
services:
mongo1:
container_name: mongo1
image: mongo
expose:
- 27017
ports:
- 27017:27017
volumes:
- mongo1:/data/db
restart: always
entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0", "--journal", "--enableMajorityReadConcern", "false" ]
volumes:
mongo1:
# @author : microfat
# @time : 04/25/21 15:28:58
# @File : docker-compose-2.yml
version: "3.8"
services:
mongo2:
container_name: mongo2
image: mongo
expose:
- 27017
ports:
- 27017:27017
volumes:
- mongo2:/data/db
restart: always
entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0", "--journal", "--enableMajorityReadConcern", "false" ]
volumes:
mongo2: