# Mongodb副本集 ## 介绍 为了解决Mongodb数据高可用,官方提供了副本集机制,Mongodb副本集至少需要三个节点,其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据,两个从节点中也可以让其中一个节点做仲裁,不存数据。 Mongodb各个节点常见的搭配方式为:一主一从、一主多从。副本集中只有主能写,其余的从只能读。 主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行,这些操作,从而保证从节点的数据与主节点一致。 Mongodb副本集结构图如下所示: ![](./11.png) 当主节点发生故障后,其中一个从节点会成为新的主。 ![](./12.png) MongoDB副本集在主从复制基础上实现了故障转移的功能,也就是当主节点宕机时,某一台副本节点会自动提升为新主节点。 ## 副本集搭建 [详细参考](https://zhuanlan.zhihu.com/p/98451473) 搭建三台主机并安装mongodb [安装教程](https://cloudplayer.readthedocs.io/zh-cn/latest/%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/MongoDB%E5%AE%89%E8%A3%85.html) 1.定义PATH ```bash vi /etc/profile.d/mongodb.sh ##增加或者修改 export PATH=$PATH:/usr/local/mongodb/bin source /etc/profile.d/mongodb.sh ##使环境变量生效 ``` 2.创建keyfile (副本集各成员之间认证) ```bash openssl rand -base64 20 > /usr/local/mongodb/conf/keyfile chmod 400 /usr/local/mongodb/conf/keyfile ``` 3.编辑配置文件 ```bash mkdir /usr/local/mongodb/{conf,logs} mkdir -p /data/mongodb vi /usr/local/mongodb/conf/mongodb.conf ##添加如下内容,注意有缩进 systemLog: #MongoDB发送所有日志输出的目标指定为文件 destination: file #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径 path: "/usr/local/mongodb/logs/mongodb.log" #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾 logAppend: true storage: #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod dbPath: "/data/mongodb" journal: #启用或禁用持久性日志以确保数据文件保持有效和可恢复。 enabled: true processManagement: #启用在后台运行mongos或mongod进程的守护进程模式。 fork: true #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID pidFilePath: "/usr/local/mongodb/logs/mongod.pid" #从中加载时区数据库的完整路径 timeZoneInfo: /usr/share/zoneinfo net: #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip #bindIpAll: true #服务实例绑定的IP,0.0.0.0让所有机器都能连接。 bindIp: 0.0.0.0 #bindIp #绑定的端口 port: 27017 # 安全配置 security: # 配置密码文件 keyFile: /usr/local/mongodb/conf/keyfile replication: #副本集的名称 replSetName: "aming" ``` 4.编辑systemd服务管理脚本 ```bash vi /lib/systemd/system/mongodb.service ##写入如下内容 [Unit] Description=mongodb After=network.target remote-fs.target nss-lookup.target [Service] User=mongodb Type=forking ExecStart=/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/conf/mongodb.conf ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -QUIT PrivateTmp=true [Install] WantedBy=multi-user.target ``` 5.创建用户,修改权限 ```bash useradd -s /sbin/nologin mongodb chown -R mongodb /data/mongodb /usr/local/mongodb ``` 6.启动服务 ```bash systemctl daemon-reload systemctl start mongodb systemctl enable mongodb ``` 7.安装其余节点 将节点1上的mongodb相关文件拷贝到另外两个节点 ```bash scp -r /usr/local/mongodb aminglinux02:/usr/local/ scp -r /usr/local/mongodb aminglinux03:/usr/local/ scp /lib/systemd/system/mongodb.service aminglinux02:/lib/systemd/system/ scp /lib/systemd/system/mongodb.service aminglinux03:/lib/systemd/system/ ``` 其他操作同上 8.节点1上创建用户 编辑配置文件 ```bash vi /usr/local/mongodb/conf/mongodb.conf ##注释掉下面几行 # 安全配置 #security: # 配置密码文件 #keyFile: /usr/local/mongodb/conf/keyfile #replication: #副本集的名称 #replSetName: "aming" ``` 重启服务 ```bash systemctl restart mongodb ``` 用mongosh工具连接mongodb [安装教程](https://cloudplayer.readthedocs.io/zh-cn/latest/%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9Cmongodb.html) ``` mongosh ip:prot ``` 进到mongodb命令行里面,创建用户 ``` use admin db.createUser({user:"root",pwd:"aminglinux.com",roles:["root"]}) ``` 退出mongodb命令行,继续编辑配置文件,将刚刚注释掉的几行恢复 ``` vi /usr/local/mongodb/conf/mongodb.conf ##注释掉下面几行 # 安全配置 security: # 配置密码文件 keyFile: /usr/local/mongodb/conf/keyfile replication: #副本集的名称 replSetName: "aming" ``` 重启服务 ``` systemctl restart mongodb ``` 9.到节点1上初始化副本集 连接mongodb ``` mongosh ip:prot ``` 认证 ``` use admin db.auth("root","aminglinux.com") ``` 副本集初始化 ``` rs.initiate( { _id: "aming", version: 1, members: [ { _id: 0, host : "aminglinux01:27017" }, { _id: 1, host : "aminglinux02:27017", arbiterOnly: true }, { _id: 2, host : "aminglinux03:27017" } ] } ) ``` 查看副本集状态 ``` aming [direct: primary] admin> rs.status() { set: 'aming', date: ISODate("2022-10-04T13:27:38.429Z"), myState: 1, term: Long("1"), syncSourceHost: '', syncSourceId: -1, heartbeatIntervalMillis: Long("2000"), majorityVoteCount: 2, writeMajorityCount: 2, votingMembersCount: 3, writableVotingMembersCount: 2, optimes: { lastCommittedOpTime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") }, lastCommittedWallTime: ISODate("2022-10-04T13:27:34.625Z"), readConcernMajorityOpTime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") }, appliedOpTime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") }, durableOpTime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") }, lastAppliedWallTime: ISODate("2022-10-04T13:27:34.625Z"), lastDurableWallTime: ISODate("2022-10-04T13:27:34.625Z") }, lastStableRecoveryTimestamp: Timestamp({ t: 1664890004, i: 1 }), electionCandidateMetrics: { lastElectionReason: 'electionTimeout', lastElectionDate: ISODate("2022-10-04T13:15:03.957Z"), electionTerm: Long("1"), lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") }, lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") }, numVotesNeeded: 2, priorityAtElection: 1, electionTimeoutMillis: Long("10000"), numCatchUpOps: Long("0"), newTermStartDate: ISODate("2022-10-04T13:15:04.286Z"), wMajorityWriteAvailabilityDate: ISODate("2022-10-04T13:15:05.828Z") }, members: [ { _id: 0, name: 'aminglinux01:27017', health: 1, state: 1, stateStr: 'PRIMARY', uptime: 835, optime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") }, optimeDate: ISODate("2022-10-04T13:27:34.000Z"), lastAppliedWallTime: ISODate("2022-10-04T13:27:34.625Z"), lastDurableWallTime: ISODate("2022-10-04T13:27:34.625Z"), syncSourceHost: '', syncSourceId: -1, infoMessage: '', electionTime: Timestamp({ t: 1664889303, i: 1 }), electionDate: ISODate("2022-10-04T13:15:03.000Z"), configVersion: 1, configTerm: 1, self: true, lastHeartbeatMessage: '' }, { _id: 1, name: 'aminglinux02:27017', health: 1, state: 7, stateStr: 'ARBITER', uptime: 764, lastHeartbeat: ISODate("2022-10-04T13:27:38.120Z"), lastHeartbeatRecv: ISODate("2022-10-04T13:27:37.485Z"), pingMs: Long("2"), lastHeartbeatMessage: '', syncSourceHost: '', syncSourceId: -1, infoMessage: '', configVersion: 1, configTerm: 1 }, { _id: 2, name: 'aminglinux03:27017', health: 1, state: 2, stateStr: 'SECONDARY', uptime: 764, optime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") }, optimeDurable: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") }, optimeDate: ISODate("2022-10-04T13:27:34.000Z"), optimeDurableDate: ISODate("2022-10-04T13:27:34.000Z"), lastAppliedWallTime: ISODate("2022-10-04T13:27:34.625Z"), lastDurableWallTime: ISODate("2022-10-04T13:27:34.625Z"), lastHeartbeat: ISODate("2022-10-04T13:27:38.121Z"), lastHeartbeatRecv: ISODate("2022-10-04T13:27:37.014Z"), pingMs: Long("3"), lastHeartbeatMessage: '', syncSourceHost: 'aminglinux01:27017', syncSourceId: 0, infoMessage: '', configVersion: 1, configTerm: 1 } ], ok: 1, '$clusterTime': { clusterTime: Timestamp({ t: 1664890054, i: 1 }), signature: { hash: Binary(Buffer.from("387cab53507429b2fa1e5de0d4bdef373f63e6f7", "hex"), 0), keyId: Long("7150645112140201989") } }, operationTime: Timestamp({ t: 1664890054, i: 1 }) } ``` 10.模拟故障 将节点1上的mongodb服务停掉 ``` systemctl stop mongodb ``` 到节点3上查看副本集状态 ``` mongosh 127.0.0.1 use admin db.auth("root","aminglinux.com") rs.status() { set: 'aming', date: ISODate("2022-10-09T08:13:37.403Z"), myState: 1, term: Long("3"), syncSourceHost: '', syncSourceId: -1, heartbeatIntervalMillis: Long("2000"), majorityVoteCount: 2, writeMajorityCount: 2, votingMembersCount: 3, writableVotingMembersCount: 2, optimes: { lastCommittedOpTime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") }, lastCommittedWallTime: ISODate("2022-10-09T08:13:28.672Z"), readConcernMajorityOpTime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") }, appliedOpTime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") }, durableOpTime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") }, lastAppliedWallTime: ISODate("2022-10-09T08:13:28.672Z"), lastDurableWallTime: ISODate("2022-10-09T08:13:28.672Z") }, lastStableRecoveryTimestamp: Timestamp({ t: 1664890404, i: 1 }), electionCandidateMetrics: { lastElectionReason: 'electionTimeout', lastElectionDate: ISODate("2022-10-09T08:13:28.601Z"), electionTerm: Long("3"), lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1664890414, i: 1 }), t: Long("1") }, lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1664890414, i: 1 }), t: Long("1") }, numVotesNeeded: 2, priorityAtElection: 1, electionTimeoutMillis: Long("10000"), numCatchUpOps: Long("0"), newTermStartDate: ISODate("2022-10-09T08:13:28.672Z"), wMajorityWriteAvailabilityDate: ISODate("2022-10-09T08:13:29.698Z") }, electionParticipantMetrics: { votedForCandidate: true, electionTerm: Long("1"), lastVoteDate: ISODate("2022-10-09T07:56:09.459Z"), electionCandidateMemberId: 0, voteReason: '', lastAppliedOpTimeAtElection: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") }, maxAppliedOpTimeInSet: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") }, priorityAtElection: 1 }, members: [ { _id: 0, name: 'aminglinux01:27017', health: 0, state: 8, 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("2022-10-09T08:13:28.672Z"), lastDurableWallTime: ISODate("2022-10-09T08:13:28.672Z"), lastHeartbeat: ISODate("2022-10-09T08:13:36.815Z"), lastHeartbeatRecv: ISODate("2022-10-09T08:13:29.686Z"), pingMs: Long("1"), lastHeartbeatMessage: 'Error connecting to aminglinux01:27017 (192.168.222.128:27017) :: caused by :: Connection refused', syncSourceHost: '', syncSourceId: -1, infoMessage: '', configVersion: 1, configTerm: 1 }, { _id: 1, name: 'aminglinux02:27017', health: 1, state: 7, stateStr: 'ARBITER', uptime: 1057, lastHeartbeat: ISODate("2022-10-09T08:13:36.702Z"), lastHeartbeatRecv: ISODate("2022-10-09T08:13:36.701Z"), pingMs: Long("2"), lastHeartbeatMessage: '', syncSourceHost: '', syncSourceId: -1, infoMessage: '', configVersion: 1, configTerm: 3 }, { _id: 2, name: 'aminglinux03:27017', health: 1, state: 1, stateStr: 'PRIMARY', uptime: 2384, optime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") }, optimeDate: ISODate("2022-10-09T08:13:28.000Z"), lastAppliedWallTime: ISODate("2022-10-09T08:13:28.672Z"), lastDurableWallTime: ISODate("2022-10-09T08:13:28.672Z"), syncSourceHost: '', syncSourceId: -1, infoMessage: '', electionTime: Timestamp({ t: 1665303208, i: 1 }), electionDate: ISODate("2022-10-09T08:13:28.000Z"), configVersion: 1, configTerm: 3, self: true, lastHeartbeatMessage: '' } ], ok: 1, '$clusterTime': { clusterTime: Timestamp({ t: 1665303208, i: 2 }), signature: { hash: Binary(Buffer.from("dd7df9ea0f127c3deb97a9658053320863968bcc", "hex"), 0), keyId: Long("7150645112140201989") } }, operationTime: Timestamp({ t: 1665303208, i: 2 }) } ``` 此时节点1,显示无法连接,节点3变成了primary 再次将节点1启动 ``` systemctl start mongodb ``` 节点3上再次查看副本集状态 ``` rs.status() { set: 'aming', date: ISODate("2022-10-09T08:15:29.956Z"), myState: 1, term: Long("3"), syncSourceHost: '', syncSourceId: -1, heartbeatIntervalMillis: Long("2000"), majorityVoteCount: 2, writeMajorityCount: 2, votingMembersCount: 3, writableVotingMembersCount: 2, optimes: { lastCommittedOpTime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") }, lastCommittedWallTime: ISODate("2022-10-09T08:15:28.707Z"), readConcernMajorityOpTime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") }, appliedOpTime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") }, durableOpTime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") }, lastAppliedWallTime: ISODate("2022-10-09T08:15:28.707Z"), lastDurableWallTime: ISODate("2022-10-09T08:15:28.707Z") }, lastStableRecoveryTimestamp: Timestamp({ t: 1665303208, i: 2 }), electionCandidateMetrics: { lastElectionReason: 'electionTimeout', lastElectionDate: ISODate("2022-10-09T08:13:28.601Z"), electionTerm: Long("3"), lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1664890414, i: 1 }), t: Long("1") }, lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1664890414, i: 1 }), t: Long("1") }, numVotesNeeded: 2, priorityAtElection: 1, electionTimeoutMillis: Long("10000"), numCatchUpOps: Long("0"), newTermStartDate: ISODate("2022-10-09T08:13:28.672Z"), wMajorityWriteAvailabilityDate: ISODate("2022-10-09T08:13:29.698Z") }, electionParticipantMetrics: { votedForCandidate: true, electionTerm: Long("1"), lastVoteDate: ISODate("2022-10-09T07:56:09.459Z"), electionCandidateMemberId: 0, voteReason: '', lastAppliedOpTimeAtElection: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") }, maxAppliedOpTimeInSet: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") }, priorityAtElection: 1 }, members: [ { _id: 0, name: 'aminglinux01:27017', health: 1, state: 2, stateStr: 'SECONDARY', uptime: 4, optime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") }, optimeDurable: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") }, optimeDate: ISODate("2022-10-09T08:15:28.000Z"), optimeDurableDate: ISODate("2022-10-09T08:15:28.000Z"), lastAppliedWallTime: ISODate("2022-10-09T08:15:28.707Z"), lastDurableWallTime: ISODate("2022-10-09T08:15:28.707Z"), lastHeartbeat: ISODate("2022-10-09T08:15:29.118Z"), lastHeartbeatRecv: ISODate("2022-10-09T08:15:28.271Z"), pingMs: Long("1"), lastHeartbeatMessage: '', syncSourceHost: 'aminglinux03:27017', syncSourceId: 2, infoMessage: '', configVersion: 1, configTerm: 3 }, { _id: 1, name: 'aminglinux02:27017', health: 1, state: 7, stateStr: 'ARBITER', uptime: 1169, lastHeartbeat: ISODate("2022-10-09T08:15:28.843Z"), lastHeartbeatRecv: ISODate("2022-10-09T08:15:28.828Z"), pingMs: Long("1"), lastHeartbeatMessage: '', syncSourceHost: '', syncSourceId: -1, infoMessage: '', configVersion: 1, configTerm: 3 }, { _id: 2, name: 'aminglinux03:27017', health: 1, state: 1, stateStr: 'PRIMARY', uptime: 2496, optime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") }, optimeDate: ISODate("2022-10-09T08:15:28.000Z"), lastAppliedWallTime: ISODate("2022-10-09T08:15:28.707Z"), lastDurableWallTime: ISODate("2022-10-09T08:15:28.707Z"), syncSourceHost: '', syncSourceId: -1, infoMessage: '', electionTime: Timestamp({ t: 1665303208, i: 1 }), electionDate: ISODate("2022-10-09T08:13:28.000Z"), configVersion: 1, configTerm: 3, self: true, lastHeartbeatMessage: '' } ], ok: 1, '$clusterTime': { clusterTime: Timestamp({ t: 1665303328, i: 1 }), signature: { hash: Binary(Buffer.from("79f96888b9567f3f1be25b3436a206fc59c31519", "hex"), 0), keyId: Long("7150645112140201989") } }, operationTime: Timestamp({ t: 1665303328, i: 1 }) } ``` 节点1上线,变为secondary