一、MongoDB 5.0版本副本集集群部署
什么是MongoDB的副本集
MongoDB的副本集(Replica Set)是一种用于提高数据库系统可用性、可靠性和数据冗余性的机制。副本集包含一组相互连接的MongoDB节点,其中包括一个主节点(Primary)和多个从节点(Secondary)。主节点处理所有的写入操作以及读取操作,而从节点则通过异步复制主节点上的操作来保持数据的一致性,从而作为数据的热备份。如果主节点发生故障,从节点之一可以通过选举过程升级为主节点,以保证服务的连续性。
MongoDB副本集基本组成
MongoDB副本集通常由以下部分组成:
- 一个主节点(Primary): 处理所有写操作
- 多个从节点(Secondary): 复制主节点数据,可以处理读操作
- 可选的仲裁节点(Arbiter): 不存储数据,只参与选举
仲裁者作用
仲裁者(Arbiter)在MongoDB副本集中扮演着重要的角色,下面是仲裁者的作用
- 选举过程:仲裁者在选举过程中投出关键的一票,帮助确定新的主节点。
- 防止死锁:在偶数成员的情况下,仲裁者可以打破平局,避免系统陷入死锁状态。
- 不存储数据:仲裁者不存储任何数据,减少了存储开销和数据复制带来的网络负载。
- 提高可靠性:通过仲裁者的存在,可以显著提高副本集的可靠性和高可用性。
部署副本集
1 节点划分
mongo1 | mongo2 | 端口 | 角色 |
shared server1(Primary) | shared server1(Primary) | 27017 | 主节点 |
shared server2(Secondary) | shared server2(Secondary) | 27018 | 副本节点 |
shared server3(Secondary) | shared server3(Secondary) | 27019 | 副本节点 |
shared server4(Arbiter) | shared server4(Arbiter) | 27020 | 仲裁节点 |
2 安装MongoDB
2.1 下载并安装MongoDB
下载适用于Linux系统的MongoDB安装包,并解压至指定路径。
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-5.0.2.tgz
tar -xzvf mongodb-linux-x86_64-rhel70-5.0.2.tgz -C /usr/local
cd /usr/local/
mv mongodb-linux-x86_64-rhel70-5.0.2/ /usr/local/mongodb
3 创建主节点
3.1 创建数据和日志目录
mkdir -p /usr/local/mongodb/replica_sets/myrs_27017/{log,data/db}
3.2 配置文件
vim /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
systemLog:
destination: file
path: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.log"
logAppend: true
storage:
dbPath: "/usr/local/mongodb/replica_sets/myrs_27017/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.pid"
net:
bindIp: localhost,10.0.1.10
port: 27017
replication:
replSetName: myrs
3.3 启动主节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 15214
child process started successfully, parent exiting
4 创建副本节点
4.1 创建数据和日志目录
mkdir -p /usr/local/mongodb/replica_sets/myrs_{27018,27019,27020}/{log,data/db}
4.2 配置副本节点
vim /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
systemLog:
destination: file
path: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.log"
logAppend: true
storage:
dbPath: "/usr/local/mongodb/replica_sets/myrs_27018/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.pid"
net:
bindIp: localhost,10.0.1.10
port: 27018
replication:
replSetName: myrs
vim /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
systemLog:
destination: file
path: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.log"
logAppend: true
storage:
dbPath: "/usr/local/mongodb/replica_sets/myrs_27019/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.pid"
net:
bindIp: localhost,10.0.1.10
port: 27019
replication:
replSetName: myrs
4.3 启动节点服务
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
5 创建仲裁节点
5.1 创建配置文件
vim /usr/local/mongodb/replica_sets/myrs_27020/mongod.conf
systemLog:
destination: file
path: "/usr/local/mongodb/replica_sets/myrs_27020/log/mongod.log"
logAppend: true
storage:
dbPath: "/usr/local/mongodb/replica_sets/myrs_27020/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27020/log/mongod.pid"
net:
bindIp: localhost,10.0.1.10
port: 27020
replication:
replSetName: myrs
5.3 启动节点服务
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27020/mongod.conf
6 添加环境变量
vim /etc/profile
export PATH=/usr/local/mongodb/bin/:$PATH
source /etc/profile
which mongo
/usr/local/mongodb/bin/mongo
7 初始化副本集
7.1 进入集群
mongo --host 10.0.1.10 --port 27017
7.2 初始化集群
> rs.initiate()
7.3 查看副本集
myrs:PRIMARY> rs.conf()
7.4 添加副本节点
myrs:PRIMARY> rs.add("10.0.1.10:27018")
myrs:PRIMARY> rs.add("10.0.1.10:27019")
myrs:PRIMARY> rs.addArb("10.0.1.10:27020")
遇到问题,rs.addArb无响应解决办法:
db.adminCommand({
"setDefaultRWConcern" : 1,
"defaultWriteConcern" : {
"w" : 2
}
})
7.5 再次查看副本集配置信息
myrs:PRIMARY> rs.conf()
{
"_id" : "myrs",
"version" : 6,
"term" : 2,
"members" : [
{
"_id" : 0,
"host" : "10.0.1.10:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"secondaryDelaySecs" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "10.0.1.10:27018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"secondaryDelaySecs" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "10.0.1.10:27019",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"secondaryDelaySecs" : NumberLong(0),
"votes" : 1
},
{
"_id" : 3,
"host" : "10.0.1.10:27020",
"arbiterOnly" : true,
"buildIndexes" : true,
"hidden" : false,
"priority" : 0,
"tags" : {
},
"secondaryDelaySecs" : NumberLong(0),
"votes" : 1
}
]
- 成员0:
-
_id
:0,成员的唯一标识符。host
:10.0.1.10:27017
,表示该成员的主机地址和端口。arbiterOnly
:false
,表示这不是一个仲裁节点。priority
:1,优先级为1,意味着它可以成为主节点。votes
:1,投票权重为1,参与选举投票。
测试副本集的数据读写同步操作
1 测试步骤
1.1 准备工作
确保副本集已经正确配置并运行。可以通过以下命令查看副本集的配置:
myrs:PRIMARY> rs.conf()
插入数据在主节点上插入一些测试数据,以确保数据能够正确地写入并同步到从节点。
myrs:PRIMARY> use testdb;
myrs:PRIMARY> db.test.insertOne({ name: "John Doe", age: 30 });
{
"acknowledged" : true,
"insertedId" : ObjectId("66d57a427713464146c2cca9")
}
1.2 验证主节点
在主节点上查询刚刚插入的数据,确保数据已经成功插入。
myrs:PRIMARY> db.test.find();
{ "_id" : ObjectId("66d57a427713464146c2cca9"), "name" : "John Doe", "age" : 30 }
1.3 等待数据同步
数据插入后,可能需要几秒钟的时间才能完全同步到从节点。可以使用 rs.status()
查看同步进度。
myrs:PRIMARY> rs.status()
查看 health
字段,确保从节点的状态为 1
。
1.4 设置副本节点可读并验证从节点
连接到从节点,查询刚刚插入的数据,确保数据已经成功同步。
设置从节点有读取权限
myrs:SECONDARY> rs.secondaryOk()
设置从节点关闭读取权限
myrs:SECONDARY> rs.secondaryOk(false)
myrs:SECONDARY> use testdb;
myrs:SECONDARY> db.test.find();
{ "_id" : ObjectId("66d57a427713464146c2cca9"), "name" : "John Doe", "age" : 30 }
如果数据已经出现在从节点上,说明同步操作成功。
1.5 更新数据
在主节点上更新刚刚插入的数据,再次验证同步操作。
myrs:PRIMARY> db.test.updateOne({ name: "John Doe" }, { $set: { age: 31 } });
验证更新同步在从节点上查询更新后的数据,确保数据已经同步。
myrs:SECONDARY> db.test.find();
{ "_id" : ObjectId("66d57a427713464146c2cca9"), "name" : "John Doe", "age" : 31 }
删除数据在主节点上删除刚刚插入的数据,再次验证同步操作。
myrs:PRIMARY> db.test.deleteOne({ name: "John Doe" });
验证删除同步在从节点上查询删除后的数据,确保数据已经同步删除。
myrs:SECONDARY> db.test.find();
2 仲裁节点不存储数据
mongo --host 10.0.1.10 --port 27020
myrs:ARBITER> rs.secondaryOk()
myrs:ARBITER> show dbs
uncaught exception: Error: listDatabases failed:{
"topologyVersion" : {
"processId" : ObjectId("66d563aefe48eda115ba75a8"),
"counter" : NumberLong(1)
},
"ok" : 0,
"errmsg" : "node is not in primary or recovering state",
"code" : 13436,
"codeName" : "NotPrimaryOrSecondary"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs/<@src/mongo/shell/mongo.js:145:19
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:97:12
shellHelper.show@src/mongo/shell/utils.js:956:13
shellHelper@src/mongo/shell/utils.js:838:15
@(shellhelp2):1:1
主节点的选举规则
MongoDB 副本集中的主节点选举规则是为了确保在一个分布式环境中选择一个合适的节点来承担主节点的角色。主节点负责处理所有的写操作,并将数据同步到从节点。以下是一些主要的选举规则和流程:
1.1 选举流程
故障检测:
- 当主节点发生故障或离线时,从节点会检测到这种情况,并开始进行选举过程。
心跳机制:
- 副本集中的成员定期发送心跳消息来检测其他成员的状态。如果一段时间内没有收到主节点的心跳响应,从节点会认为主节点已离线。
选举开始:
- 当检测到主节点离线时,从节点会进入选举阶段。每个从节点都会尝试成为新的主节点。
选举资格:
- 只有具有选举资格的节点才能成为主节点。选举资格取决于优先级(
priority
)、投票权重(votes
)和其他配置参数。
1.2 选举规则
优先级(Priority):
- 每个节点都有一个优先级值(
priority
),默认为1。优先级较高的节点更有可能成为主节点。 - 优先级为0的节点不能成为主节点。
选举顺序:
- 如果多个节点具有相同的优先级,则按照节点的_id进行排序。
- 具有较高优先级的节点将优先成为主节点。
投票机制:
- 每个节点都有一个投票权重(
votes
),默认为1。节点需要获得大多数投票才能成为主节点。 - 仲裁节点(
arbiterOnly
)不存储数据,但参与投票。仲裁节点的投票权重为1。
多数票原则:
- 在选举过程中,需要获得大多数节点的投票才能成为主节点。如果总共有N个节点,则需要超过N/2的票数。
二、mongosync集群之间数据同步
参考链接:Cluster-to-Cluster Sync - MongoDB Cluster-to-Cluster Sync v1.8
Cluster-to-Cluster Sync 通过 mongosync
实用程序提供 MongoDB 集群之间的持续数据同步或一次性数据迁移。
mongosync
可以在两个集群之间持续同步数据,帮助您创建反映生产环境的专用分析、开发或测试集群。
同步后的集群还能满足审计和数据驻留合规性的局部性要求。除了连续的数据同步外,mongosync
还可以用于集群间的一次性数据迁移。
使用mongosync需要考虑版本兼容问题
三、mongoshake集群之间数据同步
1 部署第二台mongo主机,与第一台一样,仅需把ip修改即可。
2 从MongoDB副本集同步到MongoDB副本集
2.1 安装mongoshake
wget https://github.com/alibaba/MongoShake/releases/download/release-v2.8.4-20230425/mongo-shake-v2.8.4.tgz
tar -xzvf mongo-shake-v2.8.4.tgz -C /usr/local
cd /usr/local/
mv mongo-shake-v2.8.4/ mongoshake
2.2 修改配置文件
vim /usr/local/mongoshake/collector.conf
mongo_urls = mongodb://10.0.1.10:27017,10.0.1.10:27018,10.0.1.10:27019,10.0.1.10:27020
tunnel.address = mongodb://10.0.1.20:27017,10.0.1.20:27018,10.0.1.20:27019,10.0.1.20:27020
sync_mode = all
incr_sync.mongo_fetch_method = oplog
- mongo_urls :源端MongoDB实例的ConnectionStringURI格式连接地址
- tunnel.address:目标端MongoDB实例的ConnectionStringURI格式连接地址
- sync_mode :数据同步的方式,取值:all:执行全量数据同步和增量数据同步。full:仅执行全量数据同步。incr:仅执行增量数据同步。
- incr_sync.mongo_fetch_method = oplog # 如果希望以change stream拉取,该值需要配置change_stream,支持>=4.0.1版本。
2.3 启动!
./collector.linux -conf=collector.conf -verbose 1
2.4 测试是否能实时同步
在10.0.1.10发送端插入数据
mongo --host 10.0.1.10 --port 27017
myrs:PRIMARY> use testdb;
myrs:PRIMARY> db.test.insertOne({ name: "ke li", age: 22 });
myrs:PRIMARY> db.test.find();
{ "_id" : ObjectId("66d6c61f2f0fd77307a32d80"), "name" : "ke li", "age" : 22 }
在10.0.1.20可以查看到数据
mongo --host 10.0.1.20 --port 27017
myrs:PRIMARY> use testdb;
myrs:PRIMARY> db.test.find();
{ "_id" : ObjectId("66d6c61f2f0fd77307a32d80"), "name" : "ke li", "age" : 22 }
验证成功,实现了单向实时同步功能。
参考资料:
通过MongoShake实现MongoDB实例的单向同步_云数据库 MongoDB 版(MongoDB)-阿里云帮助中心 (aliyun.com)
Mongo-shake-阿里云开发者社区 (aliyun.com)
MongoShake最佳实践-阿里云开发者社区 (aliyun.com)