什么是副本集
MongoDB副本集(Replica Set)是一种数据冗余和故障恢复机制,它允许你维护相同数据的一个或多个副本,并提供自动故障转移和数据恢复能力。副本集是一个包含多个MongoDB实例(通常称为成员)的集合,其中一个成员被选举为主节点(Primary),其他成员作为从节点(Secondary)或仲裁节点(Arbiter)。
副本集的角色:
- 主节点(Primary):负责处理客户端的读写请求,并将数据更改写入其本地数据文件中。同时,主节点还会将这些更改记录在一个名为oplog(操作日志)的特殊日志文件中,并异步地复制给从节点。
- 从节点(Secondary):从主节点复制数据,并在本地存储一份副本。默认情况下,从节点默认不处理客户端的读请求,但你可以将其配置为可以读取,从而分散读请求并提高性能。在发生故障时,一个从节点可以被选举为主节点。
- 仲裁节点(Arbiter):只参与故障转移投票,不存储数据。它通常用于确保副本集具有奇数个成员(以实现多数投票),同时减少存储成本。
副本集的工作机制:
- 数据复制:主节点将oplog中的更改异步复制到从节点。
- 故障转移:如果主节点不可用,副本集中的其他成员将尝试选举一个新的主节点。这个过程基于心跳检测和投票机制。
- 读请求路由:客户端可以将读请求发送到主节点或从节点(如果配置为可读)。
副本集至少需要3个成员,可以配置为一主两从
如果主节点挂掉,两个从节点会重新选举,找到一个从节点,将其提升为主
在某些情况下(例如存在一个主节点和一个从节点,但由于成本有限无法再添加另一个从节点),您可以选择将一个实例配置为仲裁节点添加到副本集中。仲裁节点参与选举,但不持有数据(即不提供数据冗余):
在选举时,主节点可能降为从节点,从节点也可能提升为主节点,但仲裁节点永远只能是仲裁节点。
数据同步原理
Primary节点写入数据,Secondary通过读取Primary的oplog得到复制信息,开始复制数据并且将复制信息写入到自己的oplog。如果某个操作失败,则secondary节点停止从当前数据源复制数据。如果某个secondary节点由于某些原因挂掉了,当重新启动后,就会自动从oplog的最后一个操作开始同步,同步完成后,将信息写入自己的oplog,由于复制操作是先复制数据,复制完成后再写入oplog,有可能相同的操作会同步两份,不过MongoDB的oplog的操作是幂等的,也就是说将oplog的同一个操作执行多次,与执行一次的效果是一样的:
当Primary节点完成数据操作后,Secondary会做出一系列的动作保证数据的同步:
- 检查自己local库的oplog.rs集合找出最近的时间戳。
- 检查Primary节点local库oplog.rs集合,找出大于此时间戳的记录。
- 将找到的记录插入到自己的oplog.rs集合中,并执行这些操作。
secondary从primary端获取日志,然后在本地完全顺序的执行oplog所记录的各种操作(oplog不记录查询操作),这个日志就是local数据库中的oplog.rs表,默认在64位机器上这个表是比较大的,占磁盘大小的5%,oplog.rs的大小可以在启动参数中设 定: --oplogSize 1000,单位是M。
注意:在副本集的环境中,要是所有的Secondary都宕机了,只剩下Primary。最后Primary会变成Secondary,不能提供服务。
部署
Docker compose 部署
创建目录
mkdir -p /mongodb/data
编写 docker-compose.yml 文件
services:
mongo:
image: mongo:7.0
container_name: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: 123456
MONGO_INITDB_REPLICA_SET_NAME: rs0
ports:
- 27017:27017
volumes:
- mongodb-data:/data/db
- /mongodb/mongodb-keyfile:/data/mongodb-keyfile
command:
- /bin/sh
- -c
- |
chmod 400 /mongodb/mongodb-keyfile
chown 999:999 /mongodb/mongodb-keyfile
mongod --replSet rs0 --keyFile /data/mongodb-keyfile --bind_ip_all
volumes:
mongodb-data:
所有主机的 yml 文件是一致的
这个时候不要着急启动 docker
先生成一份 key
openssl rand -base64 756 > mongodb-keyfile
开始启动容器
docker compose up -d
当然这句话要在 /mongodb 文件夹下使用
查看集群状态
docker exec -it mongo mongosh -u root -p 123456 --authenticationDatabase admin
在随机一台主机上执行,或者你想让哪台主机成为 leader 你就在哪台主机上执行
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "192.168.142.157:27017" },
{ _id: 1, host: "192.168.142.156:27017" },
{ _id: 2, host: "192.168.142.155:27017" },
{ _id: 3, host: "192.168.142.158:27017" }
]
})
另外,如果 上面这个操作执行不成功的话,可以分开执行
rs.initiate()
这个地方是除了本机,都加上,效果按理来说是和上面那种方式是一样的
rs.add("192.168.142.156:27017") // 添加第一个从节点
rs.add("192.168.142.155:27017") // 添加第二个从节点
rs.add("192.168.142.158:27017") // 添加第三个从节点
进入 mongodb 的 shell 平台之后再使用
rs.status()
查看集群状态
{
set: 'rs0',
date: ISODate('2024-10-01T12:20:28.852Z'),
myState: 1,
term: Long('1'),
syncSourceHost: '',
syncSourceId: -1,
heartbeatIntervalMillis: Long('2000'),
majorityVoteCount: 1,
writeMajorityCount: 1,
votingMembersCount: 1,
writableVotingMembersCount: 1,
optimes: {
lastCommittedOpTime: { ts: Timestamp({ t: 1727785225, i: 1 }), t: Long('1') },
lastCommittedWallTime: ISODate('2024-10-01T12:20:25.424Z'),
readConcernMajorityOpTime: { ts: Timestamp({ t: 1727785225, i: 1 }), t: Long('1') },
appliedOpTime: { ts: Timestamp({ t: 1727785225, i: 1 }), t: Long('1') },
durableOpTime: { ts: Timestamp({ t: 1727785225, i: 1 }), t: Long('1') },
lastAppliedWallTime: ISODate('2024-10-01T12:20:25.424Z'),
lastDurableWallTime: ISODate('2024-10-01T12:20:25.424Z')
},
lastStableRecoveryTimestamp: Timestamp({ t: 1727785185, i: 1 }),
electionCandidateMetrics: {
lastElectionReason: 'electionTimeout',
lastElectionDate: ISODate('2024-10-01T12:15:55.481Z'),
electionTerm: Long('1'),
lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1727784955, i: 1 }), t: Long('-1') },
lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1727784955, i: 1 }), t: Long('-1') },
numVotesNeeded: 1,
priorityAtElection: 1,
electionTimeoutMillis: Long('10000'),
newTermStartDate: ISODate('2024-10-01T12:15:55.492Z'),
wMajorityWriteAvailabilityDate: ISODate('2024-10-01T12:15:55.499Z')
},
members: [
{
_id: 0,
name: '151fa19ef0c8:27017',
health: 1,
state: 1,
stateStr: 'PRIMARY',
uptime: 683,
optime: { ts: Timestamp({ t: 1727785225, i: 1 }), t: Long('1') },
optimeDate: ISODate('2024-10-01T12:20:25.000Z'),
lastAppliedWallTime: ISODate('2024-10-01T12:20:25.424Z'),
lastDurableWallTime: ISODate('2024-10-01T12:20:25.424Z'),
syncSourceHost: '',
syncSourceId: -1,
infoMessage: '',
electionTime: Timestamp({ t: 1727784955, i: 2 }),
electionDate: ISODate('2024-10-01T12:15:55.000Z'),
configVersion: 4,
configTerm: 1,
self: true,
lastHeartbeatMessage: ''
},
{
_id: 1,
name: '192.168.142.156:27017',
health: 0,
state: 6,
stateStr: '(not reachable/healthy)',
uptime: 0,
optime: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDurable: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDate: ISODate('1970-01-01T00:00:00.000Z'),
optimeDurableDate: ISODate('1970-01-01T00:00:00.000Z'),
lastAppliedWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastDurableWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastHeartbeat: ISODate('2024-10-01T12:20:27.429Z'),
lastHeartbeatRecv: ISODate('1970-01-01T00:00:00.000Z'),
pingMs: Long('0'),
lastHeartbeatMessage: '',
authenticated: false,
syncSourceHost: '',
syncSourceId: -1,
infoMessage: '',
configVersion: -1,
configTerm: -1
},
{
_id: 2,
name: '192.168.142.155:27017',
health: 0,
state: 6,
stateStr: '(not reachable/healthy)',
uptime: 0,
optime: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDurable: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDate: ISODate('1970-01-01T00:00:00.000Z'),
optimeDurableDate: ISODate('1970-01-01T00:00:00.000Z'),
lastAppliedWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastDurableWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastHeartbeat: ISODate('2024-10-01T12:20:27.428Z'),
lastHeartbeatRecv: ISODate('1970-01-01T00:00:00.000Z'),
pingMs: Long('0'),
lastHeartbeatMessage: '',
authenticated: false,
syncSourceHost: '',
syncSourceId: -1,
infoMessage: '',
configVersion: -1,
configTerm: -1
},
{
_id: 3,
name: '192.168.142.158:27017',
health: 0,
state: 6,
stateStr: '(not reachable/healthy)',
uptime: 0,
optime: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDurable: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDate: ISODate('1970-01-01T00:00:00.000Z'),
optimeDurableDate: ISODate('1970-01-01T00:00:00.000Z'),
lastAppliedWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastDurableWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastHeartbeat: ISODate('2024-10-01T12:20:27.429Z'),
lastHeartbeatRecv: ISODate('1970-01-01T00:00:00.000Z'),
pingMs: Long('0'),
lastHeartbeatMessage: '',
authenticated: false,
syncSourceHost: '',
syncSourceId: -1,
infoMessage: '',
configVersion: -1,
configTerm: -1
}
],
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1727785225, i: 1 }),
signature: {
hash: Binary.createFromBase64('MfUjNuJ+qWiRTAB699IlXMoOlU0=', 0),
keyId: Long('7420779876245831686')
}
},
operationTime: Timestamp({ t: 1727785225, i: 1 })
}
看 members 有几个对象,我这里有三个,说明我们的副本集终于搭建成功了
大家还要注意的一点是,rs.initiate() 只能在主节点上执行,rs.ststus() 也只有主节点上能查看副本集信息,其他的节点在没有执行 rs.initiate() 时,执行 rs.status() 还是会报错的
MongoServerError[NotYetInitialized]: no replset config has been received
虽然我对这种设计有点摸不着头脑,但是这是正常的,反正这样部署是没问题的
普通部署
首先,我们需要在每一台主机上先安装好 mongodb ,这里我直接使用脚本安装,有需要的小伙伴可以去看一下我之前的一篇 mongodb 的单机部署的博客我有分享我的脚本
链接:https://blog.csdn.net/qq_62866151/article/details/142662644?spm=1001.2014.3001.5501
先创建一个 mongo 文件夹,进入文件夹
mkdir -p /mongo/data
data目录是存放数据的,我们 cd 到它的上一级即可
cd /mongo
拿到脚本之后给脚本执行权限
chmod u+x mongo_setup.sh
运行脚本
./mongo_setup.sh
安装完毕之后依据脚本最后打印的几条命令依次执行,最终
root@master:/mongo# systemctl status mongod
● mongod.service - MongoDB Database Server
Loaded: loaded (/lib/systemd/system/mongod.service; disabled; vendor preset: enab>
Active: active (running) since Tue 2024-10-01 13:54:32 UTC; 4min 53s ago
Docs: https://docs.mongodb.org/manual
Main PID: 98050 (mongod)
Memory: 72.9M
CPU: 1.150s
CGroup: /system.slice/mongod.service
└─98050 /usr/bin/mongod --config /etc/mongod.conf
Oct 01 13:54:32 master systemd[1]: Started MongoDB Database Server.
Oct 01 13:54:32 master mongod[98050]: {"t":{"$date":"2024-10-01T13:54:32.853Z"},"s":"I>
表示 mongodb 部署成功了
接下来我们去修改一下相关的配置文件
vim /etc/mongod.conf
悠着点改
# network interfaces
net:
port: 27017
bindIp: 0.0.0.0
#security:
security:
authorization: enabled
keyFile: "/mongo/mongo.key"
clusterAuthMode: "keyFile"
#operationProfiling:
#replication:
replication:
replSetName: "rs0"
oplogSizeMB: 5000
改完之后不要忘记,之前 docker 部署的时候还生成过 mongodb-keyfile
openssl rand -base64 666 > /mongo/mongo.key
chmod 400 /mongo/mongo.key
创建用户
useradd -M mongodb
passwd mongodb
<密码自定义>
chown mongodb:mongodb -R /mongo
重启
systemctl restart mongod.service
这个地方的 key 文件和上面的 docker 部署的那个 key 还是有点差别的
使用 mongosh 命令进入 mongodb 的 shell 界面
首先初始化
use admin
rs.initiate()
在创建一个用户
admin> db.createUser({user:"adminUser",pwd:"123456",roles:[{role :"clusterAdmin",db:"admin"}]})
退出出来使用用户登录进去
mongosh -u adminUser-p 123456 --authenticationDatabase admin
进去之后还是要 use admin
然后再
还是老规矩,除了自己
rs.add("192.168.142.156:27017") // 添加第一个从节点
rs.add("192.168.142.155:27017") // 添加第二个从节点
rs.add("192.168.142.158:27017") // 添加第三个从节点
如果你觉得这样子比较麻烦的话,还可以这样操作
第一步:第一次进来先只创建一个用户
mongosh
use admin
admin> db.createUser({user:"adminUser",pwd:"123456",roles:[{role :"clusterAdmin",db:"admin"}]})
创建完成之后再退出 exit
再次使用创建的用户登录,登陆进去之后
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "192.168.142.157:27017" },
{ _id: 1, host: "192.168.142.156:27017" },
{ _id: 2, host: "192.168.142.155:27017" },
{ _id: 3, host: "192.168.142.158:27017" }
]
})
这样子应该也是没问题的,我们查看一下结果
rs.status()
{
set: 'rs0',
date: ISODate('2024-10-01T15:38:16.051Z'),
myState: 1,
term: Long('1'),
syncSourceHost: '',
syncSourceId: -1,
heartbeatIntervalMillis: Long('2000'),
majorityVoteCount: 1,
writeMajorityCount: 1,
votingMembersCount: 1,
writableVotingMembersCount: 1,
optimes: {
lastCommittedOpTime: { ts: Timestamp({ t: 1727797091, i: 1 }), t: Long('1') },
lastCommittedWallTime: ISODate('2024-10-01T15:38:11.962Z'),
readConcernMajorityOpTime: { ts: Timestamp({ t: 1727797091, i: 1 }), t: Long('1') },
appliedOpTime: { ts: Timestamp({ t: 1727797091, i: 1 }), t: Long('1') },
durableOpTime: { ts: Timestamp({ t: 1727797091, i: 1 }), t: Long('1') },
lastAppliedWallTime: ISODate('2024-10-01T15:38:11.962Z'),
lastDurableWallTime: ISODate('2024-10-01T15:38:11.962Z')
},
lastStableRecoveryTimestamp: Timestamp({ t: 1727797061, i: 1 }),
electionCandidateMetrics: {
lastElectionReason: 'electionTimeout',
lastElectionDate: ISODate('2024-10-01T15:21:51.898Z'),
electionTerm: Long('1'),
lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1727796111, i: 1 }), t: Long('-1') },
lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1727796111, i: 1 }), t: Long('-1') },
numVotesNeeded: 1,
priorityAtElection: 1,
electionTimeoutMillis: Long('10000'),
newTermStartDate: ISODate('2024-10-01T15:21:51.908Z'),
wMajorityWriteAvailabilityDate: ISODate('2024-10-01T15:21:51.915Z')
},
members: [
{
_id: 0,
name: 'master:27017',
health: 1,
state: 1,
stateStr: 'PRIMARY',
uptime: 1169,
optime: { ts: Timestamp({ t: 1727797091, i: 1 }), t: Long('1') },
optimeDate: ISODate('2024-10-01T15:38:11.000Z'),
lastAppliedWallTime: ISODate('2024-10-01T15:38:11.962Z'),
lastDurableWallTime: ISODate('2024-10-01T15:38:11.962Z'),
syncSourceHost: '',
syncSourceId: -1,
infoMessage: '',
electionTime: Timestamp({ t: 1727796111, i: 2 }),
electionDate: ISODate('2024-10-01T15:21:51.000Z'),
configVersion: 4,
configTerm: 1,
self: true,
lastHeartbeatMessage: ''
},
{
_id: 1,
name: '192.168.142.156:27017',
health: 0,
state: 6,
stateStr: '(not reachable/healthy)',
uptime: 0,
optime: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDurable: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDate: ISODate('1970-01-01T00:00:00.000Z'),
optimeDurableDate: ISODate('1970-01-01T00:00:00.000Z'),
lastAppliedWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastDurableWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastHeartbeat: ISODate('2024-10-01T15:38:15.441Z'),
lastHeartbeatRecv: ISODate('1970-01-01T00:00:00.000Z'),
pingMs: Long('0'),
lastHeartbeatMessage: '',
authenticated: false,
syncSourceHost: '',
syncSourceId: -1,
infoMessage: '',
configVersion: -1,
configTerm: -1
},
{
_id: 2,
name: '192.168.142.155:27017',
health: 0,
state: 6,
stateStr: '(not reachable/healthy)',
uptime: 0,
optime: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDurable: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDate: ISODate('1970-01-01T00:00:00.000Z'),
optimeDurableDate: ISODate('1970-01-01T00:00:00.000Z'),
lastAppliedWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastDurableWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastHeartbeat: ISODate('2024-10-01T15:38:15.441Z'),
lastHeartbeatRecv: ISODate('1970-01-01T00:00:00.000Z'),
pingMs: Long('0'),
lastHeartbeatMessage: '',
authenticated: false,
syncSourceHost: '',
syncSourceId: -1,
infoMessage: '',
configVersion: -1,
configTerm: -1
},
{
_id: 3,
name: '192.168.142.158:27017',
health: 0,
state: 6,
stateStr: '(not reachable/healthy)',
uptime: 0,
optime: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDurable: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') },
optimeDate: ISODate('1970-01-01T00:00:00.000Z'),
optimeDurableDate: ISODate('1970-01-01T00:00:00.000Z'),
lastAppliedWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastDurableWallTime: ISODate('1970-01-01T00:00:00.000Z'),
lastHeartbeat: ISODate('2024-10-01T15:38:15.441Z'),
lastHeartbeatRecv: ISODate('1970-01-01T00:00:00.000Z'),
pingMs: Long('0'),
lastHeartbeatMessage: '',
authenticated: false,
syncSourceHost: '',
syncSourceId: -1,
infoMessage: '',
configVersion: -1,
configTerm: -1
}
],
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1727797091, i: 1 }),
signature: {
hash: Binary.createFromBase64('LDaTTPVX1qNYxZzrNdEZZttnxwQ=', 0),
keyId: Long('7420827790900985863')
}
},
operationTime: Timestamp({ t: 1727797091, i: 1 })
}
另外,如果要搭建仲裁的话,只需要略微改动一下
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "192.168.142.157:27017", priority: 3 },
{ _id: 1, host: "192.168.142.156:27017" , priority: 2},
{ _id: 2, host: "192.168.142.155:27017" , priority: 1},
{ _id: 3, host: "192.168.142.158:27017", arbiterOnly: true }
]
})
或者 rs.add() 替换成 rs.addArb()
你想把哪个节点设置成仲裁,哪个节点的 rs.add 就替换成 rs.addArb 即可
也是不负众望,最后 members 里面所有的节点都添加进来了
那么 两种部署 方式已经演示结束,希望大家能够学会
最后再来总结一下:
副本集的管理
查看副本集
# 查看配置
rs.config()
# 查看副本集状态:
rs.status()
# 查看master
rs.isMaster()
管理副本集成员
删除成员
- 在要删除的成员实例上停止数据库实例
# 登录至指定节点停止实例
rs0:SECONDARY> use admin;
switched to db admin
rs0:SECONDARY> db.shutdownServer()
server should be down...
- 在master上执行删除操作
rs0:PRIMARY> rs.remove("10.1.56.85:27017")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1641217135, 1),
"signature" : {
"hash" : BinData(0,"nhyPvAHXJmE62L0LvIC3J8hAQl8="),
"keyId" : NumberLong("7048958896664215556")
}
},
"operationTime" : Timestamp(1641217135, 1)
}
- 检查集群是否正常删除
rs.status()
添加成员
- 启动mongo并修改相应配置
# /etc/mongod.conf配置文件
security:
authorization: enabled
clusterAuthMode: "keyFile"
keyFile: "/data/mongo/mongodb.key"
replication:
replSetName: "rs0"
oplogSizeMB: 5000
# 如果之前有数据,记得清理
rm -rf /var/lib/mongo/*
# 启动mongo
systemctl start mongod
- 添加成员至副本集
# 在主节点执行以下操作
rs0:PRIMARY> rs.add({host: "10.1.56.85:27017", priority: 0, votes: 0})
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1641217386, 1),
"signature" : {
"hash" : BinData(0,"KLr++3ulixdXPfZhFFAqMhuZuuM="),
"keyId" : NumberLong("7048958896664215556")
}
},
"operationTime" : Timestamp(1641217386, 1)
}
-
重新配置优先级
一旦新加入的成员已经过渡到 SECONDARY状态,如果需要的话,使用rs.reconfig()更新新添加的成员priority和votes
rs0:PRIMARY> var cfg=rs.conf();
rs0:PRIMARY> cfg.members[2].priority = 1
1
rs0:PRIMARY> cfg.members[2].votes = 1
1
rs0:PRIMARY> rs.reconfig(cfg)
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1641217534, 1),
"signature" : {
"hash" : BinData(0,"lj6U6EcieJCS5xJ/eAokxptiNfA="),
"keyId" : NumberLong("7048958896664215556")
}
},
"operationTime" : Timestamp(1641217534, 1)
}
以上配置完成后,可以再次通过rs.status()查看集群状态
附录
执行rs.conf()时抛如下异常:
rs0:PRIMARY> rs.conf()
uncaught exception: Error: Could not retrieve replica set config: {
"ok" : 0,
"errmsg" : "not authorized on admin to execute command { replSetGetConfig: 1.0, lsid: { id: UUID(\"4a7cd439-f949-41dc-acef-2838267a908a\") }, $clusterTime: { clusterTime: Timestamp(1641214558, 1), signature: { hash: BinData(0, D8E6570EDE34381A0866EB5600A32747FE4BD4DB), keyId: 7048958896664215556 } }, $db: \"admin\" }",
"code" : 13,
"codeName" : "Unauthorized",
"$clusterTime" : {
"clusterTime" : Timestamp(1641214701, 2),
"signature" : {
"hash" : BinData(0,"y18DwhtkerhqWMwPKLy2m8JXsdk="),
"keyId" : NumberLong("7048958896664215556")
}
},
"operationTime" : Timestamp(1641214701, 2)
} :
rs.conf@src/mongo/shell/utils.js:1713:11
@(shell):1:1
原因是当前用户权限不够,需要超级管理员权限:
use admin
db.grantRolesToUser("admin",[{role: "root", db: "admin"}])