【MongoDB】Re04 副本集 ReplicationSet
MongoDB中的副本集(Replica Set)是一组维护相同数据集的mongod服务。 副本集可提供冗余和高
可用性,是所有生产部署的基础。
也可以说,副本集类似于有自动故障恢复功能的主从集群。通俗的讲就是用多台机器进行同一数据的异
步同步,从而使多台机器拥有同一数据的多个副本,并且当主库当掉时在不需要用户干预的情况下自动
切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。
(1)冗余和数据可用性
复制提供冗余并提高数据可用性。 通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别
的容错功能,以防止丢失单个数据库服务器。
在某些情况下,复制可以提供增加的读取性能,因为客户端可以将读取操作发送到不同的服务上,
在不
同数据中心维护数据副本可以增加分布式应用程序的数据位置和可用性。 您还可以为专用目的维护其他
副本,例如灾难恢复,报告或备份。
(2)MongoDB中的复制
副本集是一组维护相同数据集的mongod实例。 副本集包含多个数据承载节点和可选的一个仲裁节点。
在承载数据的节点中,一个且仅一个成员被视为主节点,而其他节点被视为次要(从)节点。
主节点接收所有写操作。 副本集只能有一个主要能够确认具有{w:“most”}写入关注的写入; 虽然在某
些情况下,另一个mongod实例可能暂时认为自己也是主要的。主要记录其操作日志中的数据集的所有
更改,即oplog。
辅助(副本)节点复制主节点的oplog并将操作应用于其数据集,以使辅助节点的数据集反映主节点的数据
集。 如果主要人员不在,则符合条件的中学将举行选举以选出新的主要人员。
(3)主从复制和副本集区别
主从集群和副本集最大的区别就是副本集没有固定的“主节点”;整个集群会选出一个“主节点”,当其挂
掉后,又在剩下的从节点中选中其他节点为“主节点”,副本集总有一个活跃点(主、primary)和一个或多
个备份节点(从、secondary)。
副本集有两种类型三种角色
两种类型:
主节点(Primary)类型:
数据操作的主要连接点,可读写。
次要(辅助、从)节点(Secondaries)类型:
数据冗余备份节点,可以读或选举。
三种角色:
主要成员(Primary):
主要接收所有写操作。就是主节点。
副本成员(Replicate):
从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,
但可以读操作(但需要配置)。是默认的一种从节点类型。
仲裁者(Arbiter):
不保留任何数据的副本,只具有投票选举作用。
当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。
也是一种从节点类型。
关于仲裁者的额外说明:
您可以将额外的mongod实例添加到副本集作为仲裁者。 仲裁者不维护数据集。
仲裁者的目的是通过响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。
因为它们不存储数据集,所以仲裁器可以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。 如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的“大多数”投票。 仲裁者不需要专用硬件。 仲裁者将永远是仲裁者,而主要人员可能会退出并成为次要人员,而次要人员可能成为选举期间的主要人员。
如果你的副本+主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。 如果你的副本+主节点的个数是奇数,可以不加仲裁者。
搭建副本集的要素:
1、统一的副本集名称
2、从哪个节点登陆进行配置,就决定这个节点是主节点
3、配置可以使用默认配置,或者主动声明配置
4、也可以后续添加配置
Docker搭建MongoDB副本集
参考博客,直接设定为1主 2从配置
https://www.cnblogs.com/cowboys/p/9264494.html
拉镜像
docker pull mongo
创建副本集实例的容器,指定副本集名称一样:
# 创建3个容器,指定副本集名称 docker run --name primary -p 27117:27017 -d mongo --replSet "rs" docker run --name replicate1 -p 27217:27017 -d mongo --replSet "rs" docker run --name arbiter -p 27317:27017 -d mongo --replSet "rs"
登陆的注意事项
# 从主节点登陆 docker exec -it primary /bin/bash # 注意IP只能写本机具体IP值,映射名称不解析 mongo --host 192.168.101.14 --port 27117
1主 2从 直接配置
var config={ _id:"rs", members:[ {_id:0,host:"192.168.101.14:27117"}, {_id:1,host:"192.168.101.14:27217"}, {_id:2,host:"192.168.101.14:27317"} ]};
要改成 1主 1从 1裁只需要更改配置项:
var config={ _id:"rs", members:[ {_id:0,host:"192.168.101.14:27117"}, {_id:1,host:"192.168.101.14:27217"}, {_id:2, host:"192.168.101.14:27317", arbiterOnly:true} ]};
初始化执行
rs.initiate(config)
状态信息检查:
副本集配置信息: rs.conf() ######################################################################## rs:SECONDARY> rs.conf() { "_id" : "rs", "version" : 1, "term" : 1, "members" : [ { "_id" : 0, "host" : "192.168.101.14:27117", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "secondaryDelaySecs" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "192.168.101.14:27217", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "secondaryDelaySecs" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "192.168.101.14:27317", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "secondaryDelaySecs" : NumberLong(0), "votes" : 1 } ], "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "settings" : { "chainingAllowed" : true, "heartbeatIntervalMillis" : 2000, "heartbeatTimeoutSecs" : 10, "electionTimeoutMillis" : 10000, "catchUpTimeoutMillis" : -1, "catchUpTakeoverDelayMillis" : 30000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("61fa5c42f42465c5c09dbab8") } } rs:PRIMARY> ######################################################################## rs:PRIMARY> rs.status() { "set" : "rs", "date" : ISODate("2022-02-02T10:28:23.296Z"), "myState" : 1, "term" : NumberLong(1), "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "votingMembersCount" : 3, "writableVotingMembersCount" : 3, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1643797701, 1), "t" : NumberLong(1) }, "lastCommittedWallTime" : ISODate("2022-02-02T10:28:21.788Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1643797701, 1), "t" : NumberLong(1) }, "appliedOpTime" : { "ts" : Timestamp(1643797701, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1643797701, 1), "t" : NumberLong(1) }, "lastAppliedWallTime" : ISODate("2022-02-02T10:28:21.788Z"), "lastDurableWallTime" : ISODate("2022-02-02T10:28:21.788Z") }, "lastStableRecoveryTimestamp" : Timestamp(1643797681, 1), "electionCandidateMetrics" : { "lastElectionReason" : "electionTimeout", "lastElectionDate" : ISODate("2022-02-02T10:26:21.692Z"), "electionTerm" : NumberLong(1), "lastCommittedOpTimeAtElection" : { "ts" : Timestamp(1643797570, 1), "t" : NumberLong(-1) }, "lastSeenOpTimeAtElection" : { "ts" : Timestamp(1643797570, 1), "t" : NumberLong(-1) }, "numVotesNeeded" : 2, "priorityAtElection" : 1, "electionTimeoutMillis" : NumberLong(10000), "numCatchUpOps" : NumberLong(0), "newTermStartDate" : ISODate("2022-02-02T10:26:21.750Z"), "wMajorityWriteAvailabilityDate" : ISODate("2022-02-02T10:26:23.225Z") }, "members" : [ { "_id" : 0, "name" : "192.168.101.14:27117", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 485, "optime" : { "ts" : Timestamp(1643797701, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2022-02-02T10:28:21Z"), "lastAppliedWallTime" : ISODate("2022-02-02T10:28:21.788Z"), "lastDurableWallTime" : ISODate("2022-02-02T10:28:21.788Z"), "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1643797581, 1), "electionDate" : ISODate("2022-02-02T10:26:21Z"), "configVersion" : 1, "configTerm" : 1, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "192.168.101.14:27217", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 132, "optime" : { "ts" : Timestamp(1643797701, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1643797701, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2022-02-02T10:28:21Z"), "optimeDurableDate" : ISODate("2022-02-02T10:28:21Z"), "lastAppliedWallTime" : ISODate("2022-02-02T10:28:21.788Z"), "lastDurableWallTime" : ISODate("2022-02-02T10:28:21.788Z"), "lastHeartbeat" : ISODate("2022-02-02T10:28:21.820Z"), "lastHeartbeatRecv" : ISODate("2022-02-02T10:28:21.333Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncSourceHost" : "192.168.101.14:27117", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 1, "configTerm" : 1 }, { "_id" : 2, "name" : "192.168.101.14:27317", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 132, "optime" : { "ts" : Timestamp(1643797701, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1643797701, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2022-02-02T10:28:21Z"), "optimeDurableDate" : ISODate("2022-02-02T10:28:21Z"), "lastAppliedWallTime" : ISODate("2022-02-02T10:28:21.788Z"), "lastDurableWallTime" : ISODate("2022-02-02T10:28:21.788Z"), "lastHeartbeat" : ISODate("2022-02-02T10:28:21.820Z"), "lastHeartbeatRecv" : ISODate("2022-02-02T10:28:21.333Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncSourceHost" : "192.168.101.14:27117", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 1, "configTerm" : 1 } ], "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1643797701, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1643797701, 1) } ########################################################################
测试副本集配置是否成功?
主节点创建数据
# 创建文章库 rs:PRIMARY> use articledb switched to db articledb # 查看当前库 rs:PRIMARY> db articledb # 插入数据 rs:PRIMARY> db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光 明媚","userid":"1001","nickname":"Rose","createdatetime":new Date()}) WriteResult({ "nInserted" : 1 })
# 查询数据 rs:PRIMARY> db.comment.find() { "_id" : ObjectId("61fa681f159c1f7349b6ba43"), "articleid" : "100000", "content" : "今天天气真好,阳光 明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2022-02-02T11:16:47.403Z") } rs:PRIMARY>
从节点登陆
docker exec -it replicate1 /bin/bash mongo --host 192.168.101.14 --port 27217
查看DB发现报错:
rs:SECONDARY> show dbs; uncaught exception: Error: listDatabases failed:{ "topologyVersion" : { "processId" : ObjectId("61fa6758306bf1b65a46f320"), "counter" : NumberLong(4) }, "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotPrimaryNoSecondaryOk", "$clusterTime" : { "clusterTime" : Timestamp(1643800672, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1643800672, 1) } : _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 rs:SECONDARY>
当前从节点只是一个备份,不是奴隶节点,无法读取数据,写当然更不行。
因为默认情况下,从节点是没有读写权限的,可以增加读的权限,但需要进行设置
设置为奴隶节点,允许在从成员上运行读的操作
rs:SECONDARY> rs.slaveOk(true) WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead. rs:SECONDARY>
语法已过世,需要更改成
rs.secondaryOk()
现在可以查看了:
rs:SECONDARY> show dbs; admin 0.000GB articledb 0.000GB config 0.000GB local 0.000GB
从节点插入数据发现还是被禁止了
rs:SECONDARY> use articledb switched to db articledb rs:SECONDARY> db.comment.find() { "_id" : ObjectId("61fa681f159c1f7349b6ba43"), "articleid" : "100000", "content" : "今天天气真好,阳光 明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2022-02-02T11:16:47.403Z") } rs:SECONDARY> db.comment.insert({"_id":"1","articleid":"100001","content":"我们 不应该把清晨浪费在手机上,健康很重要,k一杯温水幸福你我 他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08- 05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"}) WriteCommandError({ "topologyVersion" : { "processId" : ObjectId("61fa6758306bf1b65a46f320"), "counter" : NumberLong(4) }, "ok" : 0, "errmsg" : "not master", "code" : 10107, "codeName" : "NotWritablePrimary", "$clusterTime" : { "clusterTime" : Timestamp(1643801243, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1643801243, 1) }) rs:SECONDARY>
取消从节点读权限:
rs:SECONDARY> rs.slaveOk(false) WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead. rs:SECONDARY> db.comment.find() Error: error: { "topologyVersion" : { "processId" : ObjectId("61fa6758306bf1b65a46f320"), "counter" : NumberLong(4) }, "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotPrimaryNoSecondaryOk", "$clusterTime" : { "clusterTime" : Timestamp(1643801363, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1643801363, 1) } rs:SECONDARY>
仲裁节点里面只存放副本集的配置信息:
但是查看和从节点一样不允许
rs:ARBITER> show dbs uncaught exception: Error: listDatabases failed:{ "topologyVersion" : { "processId" : ObjectId("61fa675921f7d83dcdf21a72"), "counter" : NumberLong(2) }, "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotPrimaryNoSecondaryOk" } : _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 rs:ARBITER>
mongoDB配置文件
sudo vim /etc/mongod.conf
本地设置则是写在配置文件中,命令参数注入也是可以的
# mongod.conf # for documentation of all options, see: # http://docs.mongodb.org/manual/reference/configuration-options/ # where to write logging data. 指定日志输出的配置 systemLog: destination: file logAppend: true path: /var/log/mongodb/mongod.log # Where and how to store data. 指定数据存储的位置 storage: dbPath: /var/lib/mongo journal: enabled: true # engine: # wiredTiger: # how the process runs 进程号文件配置 processManagement: fork: true # fork and run in background pidFilePath: /var/run/mongodb/mongod.pid # location of pidfile timeZoneInfo: /usr/share/zoneinfo # network interfaces 网络接口配置 net: port: 27017 bindIp: 0.0.0.0 # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting. #security: #operationProfiling: #replication: #sharding: ## Enterprise-Only Options #auditLog: #snmp: