目录
一、什么是Mongodb副本集
MongoDB副本集(Replica Set)是一种MongoDB数据库的高可用性架构,它包含多个MongoDB服务器实例。副本集提供了数据冗余和故障转移机制,以确保在其中一个节点发生故障时,数据库系统仍然能够继续提供服务。
1、副本集:一个副本集就是一组MongoDB实例组成的集群,由一个主(Primary)服务器和多个备份
(Secondary)服务器构成
2、主节点(master):主节点接收所有写入操作。主节点将对其数据集所做的所有更改记录到其
oplog。
3、副节点(secondary):复制主节点的 oplog 并将操作应用到其数据集,如果主节点不可用,一个
合格的副节点将被选为新的主节点。
4、仲裁节点(arbiter):负载选举,当主节点不可用,它将从副节点中选一个作为主节点。
二、什么是副本集主副本
主节点是副本集中唯一接收写入的成员 操作。MongoDB 在主要和 然后记录对主节点的oplog.二 次成员复制此日志并应用 对其数据集的操作。
在以下三成员副本集中,主副本接受所有副本 写入操作。然后,辅助数据库复制要应用于的 oplog 他们的数据集。
副本集的所有成员都可以接受读取操作。但是,通过 默认情况下,应用程序将其读取操作定向到主服务器 成员。看读取首选项有关更改 默认读取行为。
副本集最多可以有一个主副本集。[1]如果当前主服务器不可用, 选举决定了新的初选。看副本集选举了解更多详情。
在以下 3 成员副本集中,主副本将变得不可用。 这将触发选择剩余之一的选举 辅助数据库作为新的主数据库。
在某些情况、副本集中的两个节点 可能暂时认为它们是主要的,但最多是其中之一 他们将能够完成写入{ w: "majority" }写关注。可以完成的节点{ w: "majority" }写入是当前 primary,而另一个节点是尚未出现的前主节点 承认其降级,通常是由于网络分区. 发生这种情况时,连接到前一个主数据库的客户端可能会 尽管已请求读取首选项,但仍会观察过时的数据primary,以及对前一个主要遗嘱的新写入 最终回滚。
副本集详细说明可参考官方文档:Replica Set Primary — MongoDB Manual
三、副本集集群部署
在上一篇中是单机部署,今天来说一下使用docker compose部署副本集
3.1 下载镜像
下载monodb镜像,我这里版本为:4.0.27
docker pull mongo:4.0.27
3.2 创建三个mongodb的数据目录
实际开发部署中是需要三台服务器部署,我这里以一台为例
#这个目录为自己根据服务器数据目录自行创建
#我这里路径是 /usr/local/mongodb-cluster
mkdir -p /path/to/your/mongodb-cluster/data/master
mkdir -p /path/to/your/mongodb-cluster/data/secondary
mkdir -p /path/to/your/mongodb-cluster/data/arbiter
3.3 编写配置文件
编辑.env文件
mongo_v=mongo:4.0.27
编辑docker-compose.yml文件
version: '3.7'
services:
master:
image: ${mongo_v}
container_name: master
restart: always
ports:
- 0.0.0.0:27017:27017
volumes:
- ./data/master:/data/db
command: mongod --dbpath /data/db --replSet appSet --oplogSize 128 # --auth 开启认证
secondary:
image: ${mongo_v}
container_name: secondary
restart: always
ports:
- 0.0.0.0:27018:27017
volumes:
- ./data/secondary:/data/db
command: mongod --dbpath /data/db --replSet appSet --oplogSize 128 # --auth 开启认证
arbiter:
image: ${mongo_v}
container_name: arbiter
restart: always
ports:
- 0.0.0.0:27019:27017
volumes:
- ./data/arbiter:/data/db
command: mongod --replSet appSet --smallfiles --oplogSize 128
3.4 启动mongodb
在/path/to/your/mongodb-cluster/docker-compose.yml的目录执行
docker-compse up -d
3.5 配置副本集
3.5.1 进入容器内部
配置副本集进入容器内部,我们是需要进入主节点容器内部才能执行
docker exec -it master mongo
3.5.2 初始化副本集
在mongo shell里面执行:rs.initiate()
>rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "f4721e7cb257:27017",
"ok" : 1
}
3.5.3 添加副本集
初始化副本集之后,继续执行:rs.add('192.168.191.159:27018') 表示将secondary添加进副本
appSet:PRIMARY> rs.add('192.168.191.159:27018')
{
"ok" : 1,
"operationTime" : Timestamp(1637841965, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1637841965, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
继续执行:rs.add('192.168.191.159:27019',true) 其中true表示这个节点是仲裁节点
appSet:PRIMARY> rs.add('192.168.191.159:27019',true)
{
"ok" : 1,
"operationTime" : Timestamp(1637842080, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1637842080, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
3.5.4 查看配置
使用 rs.conf() 查看副本集配置
appSet: PRIMARY > rs.conf() {
"_id": "testSet",
"version": 3,
"protocolVersion": NumberLong(1),
"writeConcernMajorityJournalDefault": true,
"members": [{
"_id": 0,
"host": "4db784b74950:27017",
11 "arbiterOnly": false,
"buildIndexes": true,
"hidden": false,
"priority": 1,
"tags": {
},
"slaveDelay": NumberLong(0),
"votes": 1
},
{
"_id": 1,
"host": "192.168.191.159:27018",
"arbiterOnly": false,
"buildIndexes": true,
"hidden": false,
"priority": 1,
"tags": {
},
"slaveDelay": NumberLong(0),
"votes": 1
},
{
"_id": 2,
"host": "192.168.191.159:27019",
"arbiterOnly": true,
"buildIndexes": true,
"hidden": false,
"priority": 0,
"tags": {
},
"slaveDelay": NumberLong(0),
"votes": 1
}
],
"settings": {
"chainingAllowed": true,
"heartbeatIntervalMillis": 2000,
51 "heartbeatTimeoutSecs": 10,
"electionTimeoutMillis": 10000,
"catchUpTimeoutMillis": -1,
"catchUpTakeoverDelayMillis": 30000,
"getLastErrorModes": {
},
"getLastErrorDefaults": {
"w": 1,
"wtimeout": 0
},
"replicaSetId": ObjectId("619f72b4828ec77e1f058106")
}
}
3.5.5 查看副本集状态
rs.status() 命令查看副本集状态
appSet: PRIMARY > rs.status()
{
"set": "testSet",
"date": ISODate("2021-11-25T11:27:26.422Z"),
"myState": 1,
"term": NumberLong(1),
"syncingTo": "",
"syncSourceHost": "",
"syncSourceId": -1,
"heartbeatIntervalMillis": NumberLong(2000),
"optimes": {
"lastCommittedOpTime": {
"ts": Timestamp(1637839642, 1),
"t": NumberLong(1)
},
"readConcernMajorityOpTime": {
"ts": Timestamp(1637839642, 1),
"t": NumberLong(1)
},
"appliedOpTime": {
"ts": Timestamp(1637839642, 1),
"t": NumberLong(1)
},
]
"durableOpTime": {
"ts": Timestamp(1637839642, 1),
"t": NumberLong(1)
}
},
"lastStableCheckpointTimestamp": Timestamp(1637839602, 1),
"electionCandidateMetrics": {
"lastElectionReason": "electionTimeout",
"lastElectionDate": ISODate("2021-11-25T11:25:42.593Z"),
"electionTerm": NumberLong(1),
"lastCommittedOpTimeAtElection": {
"ts": Timestamp(0, 0),
"t": NumberLong(-1)
},
"lastSeenOpTimeAtElection": {
"ts": Timestamp(1637839542, 1),
"t": NumberLong(-1)
},
"numVotesNeeded": 1,
"priorityAtElection": 1,
"electionTimeoutMillis": NumberLong(10000),
"newTermStartDate": ISODate("2021-11-25T11:25:42.616Z"),
"wMajorityWriteAvailabilityDate": ISODate("2021-11-25T11:25:42.855Z")
},
"members": [{
"_id": 0,
"name": "4db784b74950:27017",
"health": 1, #健康状态 1 表明正常; 0 表明异常
"state": 1, # 1 表明是 Primary; 2 表明是 Secondary;
"stateStr": "PRIMARY", #主节点
"uptime": 160,
"optime": {
"ts": Timestamp(1637839642, 1),
"t": NumberLong(1)
},
"optimeDate": ISODate("2021-11-25T11:27:22Z"),
"syncingTo": "",
"syncSourceHost": "",
"syncSourceId": -1,
"infoMessage": "could not find member to sync from",
"electionTime": Timestamp(1637839542, 2),
"electionDate": ISODate("2021-11-25T11:25:42Z"),
"configVersion": 3,
"self": true,
"lastHeartbeatMessage": ""
},
{
"_id": 1,
"name": "192.168.191.159:27018",
"health": 1,
"state": 2,
"stateStr": "SECONDARY", #副节点
"uptime": 72,
"optime": {
"ts": Timestamp(1637839642, 1),
"t": NumberLong(1)
},
"optimeDurable": {
"ts": Timestamp(1637839642, 1),
"t": NumberLong(1)
},
"optimeDate": ISODate("2021-11-25T11:27:22Z"),
"optimeDurableDate": ISODate("2021-11-25T11:27:22Z"),
"lastHeartbeat": ISODate("2021-11-25T11:27:25.570Z"),
"lastHeartbeatRecv": ISODate("2021-11-25T11:27:25.574Z"),
"pingMs": NumberLong(0),
"lastHeartbeatMessage": "",
"syncingTo": "4db784b74950:27017",
"syncSourceHost": "4db784b74950:27017",
"syncSourceId": 0,
"infoMessage": "",
"configVersion": 3
},
{
"_id": 2,
"name": "192.168.191.159:27019",
"health": 1,
"state": 7,
"stateStr": "ARBITER", #仲裁节点
"uptime": 32,
"lastHeartbeat": ISODate("2021-11-25T11:27:25.569Z"),
"lastHeartbeatRecv": ISODate("2021-11-25T11:27:24.489Z"),
"pingMs": NumberLong(0),
"lastHeartbeatMessage": "",
"syncingTo": "",
"syncSourceHost": "",
"syncSourceId": -1,
"infoMessage": "",
"configVersion": 3
}
],
"ok": 1,
"operationTime": Timestamp(1637839642, 1),
"$clusterTime": {
"clusterTime": Timestamp(1637839642, 1),
"signature": {
"hash": BinData(0, "AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId": NumberLong(0)
}
}
}
如果想要修改副本集的配置,可以采用以下方法
#通过修改conf
conf=rs.conf()
conf.members[0].host="192.168.191.159:27017"
rs.reconfig(conf,{"force":true}) #修改conf生效
3.6 验证mongodb可用性
在mongodb shell中先进入master节点 ,给test库写入一条数据
root@server183:/data/wwwroot/mongodb-cluster# docker exec -it master mongo
MongoDB shell version v4.0.27
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("59d31632-cbc0-4b31-ab39-eef1d7a6e439") }
MongoDB server version: 4.0.27
Server has startup warnings:
2024-02-25T12:01:25.139+0000 I STORAGE [initandlisten]
2024-02-25T12:01:25.139+0000 I STORAGE [initandlisten] ** WARNING: Using the XFS filesyst
2024-02-25T12:01:25.139+0000 I STORAGE [initandlisten] ** See http://dochub.mong
2024-02-25T12:01:29.203+0000 I CONTROL [initandlisten]
2024-02-25T12:01:29.203+0000 I CONTROL [initandlisten] ** WARNING: Access control is not
2024-02-25T12:01:29.203+0000 I CONTROL [initandlisten] ** Read and write access
2024-02-25T12:01:29.204+0000 I CONTROL [initandlisten]
2024-02-25T12:01:29.204+0000 I CONTROL [initandlisten]
2024-02-25T12:01:29.204+0000 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transpa
2024-02-25T12:01:29.204+0000 I CONTROL [initandlisten] ** We suggest setting it to
2024-02-25T12:01:29.204+0000 I CONTROL [initandlisten]
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).
The monitoring data will be available on a MongoDB website with a unique URL accessible to
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring(
---
appSet:PRIMARY> use test
switched to db test
appSet:PRIMARY> db.test.insert({userName:"lisi",age: 18})
WriteResult({ "nInserted" : 1 })
在进入secondary中进行查询,跟写入
root@server183:/data/wwwroot/mongodb-cluster# docker exec -it secondary mongo
MongoDB shell version v4.0.27
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("7865c966-4024-42e6-9b75-41dd0d7c8447") }
MongoDB server version: 4.0.27
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
http://docs.mongodb.org/
Questions? Try the support group
http://groups.google.com/group/mongodb-user
Server has startup warnings:
2021-11-25T12:01:24.556+0000 I STORAGE [initandlisten]
2021-11-25T12:01:24.556+0000 I STORAGE [initandlisten] ** WARNING: Using the XFS filesyst
2021-11-25T12:01:24.557+0000 I STORAGE [initandlisten] ** See http://dochub.mong
2021-11-25T12:01:26.173+0000 I CONTROL [initandlisten]
2021-11-25T12:01:26.173+0000 I CONTROL [initandlisten] ** WARNING: Access control is not
2021-11-25T12:01:26.173+0000 I CONTROL [initandlisten] ** Read and write access
2021-11-25T12:01:26.173+0000 I CONTROL [initandlisten]
2021-11-25T12:01:26.173+0000 I CONTROL [initandlisten]
2021-11-25T12:01:26.173+0000 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transpa
2021-11-25T12:01:26.173+0000 I CONTROL [initandlisten] ** We suggest setting it to
2021-11-25T12:01:26.174+0000 I CONTROL [initandlisten]
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).
The monitoring data will be available on a MongoDB website with a unique URL accessible t
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring(
---
appSet:SECONDARY> use test
switched to db test
appSet:SECONDARY> db.test.find()
Error: error: {
"operationTime": Timestamp(1637842226, 1),
"ok": 0,
"errmsg": "not master and slaveOk=false",
"code": 13435,
"codeName": "NotMasterNoSlaveOk",
"$clusterTime": {
"clusterTime": Timestamp(1637842226, 1),
"signature": {
"hash": BinData(0, "AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId": NumberLong(0)
}
}
}
#这个错误表明你正在尝试在一个不是主节点(Primary)的 MongoDB 节点上执行 find 操作,并且在这个#节点上 slaveOk 选项被设置为 false。
#在 MongoDB 中,slaveOk 选项用于指示副本节点是否可以执行读操作。当 slaveOk 设置为 false 时,非主节点不允许执行读操作。
#设置 slaveOk 选项为 true: 如果你确实希望在非主节点上执行读操作,你可以通过在 MongoDB Shell #中执行以下命令来设置 slaveOk 选项为 true,执行rs.secondaryOk()
appSet:SECONDARY> rs.secondaryOk()
appSet:SECONDARY> db.test.find() #查询主节点写入数据
{ "_id" : ObjectId("619f7d022e828f48178dd15e"), "userName" : "lisi", "age" : 18 }
#在副节点进行写入数据
testSet:SECONDARY> db.test.insert({userName:"zhangsan",age: 18})
#写入失败
WriteCommandError({
"operationTime": Timestamp(1637842291, 1),
"ok": 0,
"errmsg": "not master", #这里提示说不是master节点不能进行写入操作
"code": 10107,
"codeName": "NotMaster",
"$clusterTime": {
"clusterTime": Timestamp(1637842291, 1),
"signature": {
"hash": BinData(0, "AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId": NumberLong(0)
}
}
})
由上测试可知:副节点只能读,不能写,主节点master可以读写