MongoDB 集群配置
一、副本集 Replica Sets
1.1 简介
MongoDB 中的副本集(Replica Set)是一组维护相同数据集的 mongod 服务。 副本集可提供冗余和高可用性,是所有生产部署的基础。
也可以说,副本集类似于有自动故障恢复功能的主从集群。通俗的讲就是用多台机器进行同一数据的异步同步,从而使多台机器拥有同一数据的多个副本,并且当主库 down 掉时在不需要用户干预的情况下自动切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。
1):冗余和数据可用性
复制提供冗余并提高数据可用性。 通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别的容错功能,以防止丢失单个数据库服务器。
在某些情况下,复制可以提供增加的读取性能,因为客户端可以将读取操作发送到不同的服务上, 在不同数据中心维护数据副本可以增加分布式应用程序的数据位置和可用性。 您还可以为专用目的维护其他副本,例如灾难恢复,报告或备份。
2):MongoDB 中的复制
副本集是一组维护相同数据集的 mongod 实例。 副本集包含多个数据承载节点和可选的一个仲裁节点。在承载数据的节点中,一个且仅一个成员被视为主节点,而其他节点被视为次要(从)节点。
主节点接收所有写操作。 副本集只能有一个主要的写入; 虽然在某些情况下,另一个 mongod 实例可能暂时认为自己也是主要的。主要记录其操作日志中的数据集的所有更改,即 oplog。
辅助(副本)节点复制主节点的 oplog 并将操作应用于其数据集,以使辅助节点的数据集反映主节点的数据集。 如果主要人员不在,则符合条件的中学将举行选举以选出新的主要人员。
3):主从复制和副本集区别
主从集群和副本集最大的区别就是副本集没有固定的 “主节点”;整个集群会选出一个“主节点”,当其挂掉后,又在剩下的从节点中选中其他节点为 “主节点”,副本集总有一个活跃点(主、primary) 和一个或多个备份节点 (从、secondary)。
1.2 副本集三个角色
副本集有两种类型三种角色。
两种类型:
主节点(Primary)类型:数据操作的主要连接点,可读写。
次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举。
三种角色:
主要成员(Primary):主要接收所有写操作。就是主节点。
副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型。
仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。
关于仲裁者的额外说明:
您可以将额外的 mongod 实例添加到副本集作为仲裁者。 仲裁者不维护数据集。 仲裁者的目的是通过响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。 因为它们不存储数据集,所以仲裁器可以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。
如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的“大多数”投票。 仲裁者不需要专用硬件。
仲裁者将永远是仲裁者,而主要人员可能会退出并成为次要人员,而次要人员可能成为选举期间的主要人员。
如果你的副本+主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。
如果你的副本+主节点的个数是奇数,可以不加仲裁者。
1.3 副本集架构目标
一主一副本一仲裁,架构图如下所示:
1.4 副本集的创建
1.4.1 创建主节点
建立存放数据和日志的目录
# 存放日志信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27017/log# 存放数据信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27017/data/db
新建配置信息
vim /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
内容如下:
systemLog:# MongoDB发送所有日志输出的目标指定为文件destination: file# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径path: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.log"# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。logAppend: true
storage:# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。dbPath: "/usr/local/mongodb/replica_sets/myrs_27017/data/db"journal:# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。enabled: true
processManagement:# 启用在后台运行mongos或mongod进程的守护进程模式。fork: true# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PIDpidFilePath: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.pid"
net:# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip#bindIpAll: true# 服务实例绑定的IPbindIp: localhost,192.168.229.154#bindIp# 绑定的端口port: 27017
replication:# 副本集的名称replSetName: myrs
启动节点服务:
[root@node1 mongodb]# /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: 42243
child process started successfully, parent exiting
1.4.2 创建副本节点
建立存放数据和日志的目录
# 存放日志信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27018/log# 存放数据信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27018/data/db
新建配置信息
vim /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
内容如下:
systemLog:# MongoDB发送所有日志输出的目标指定为文件destination: file# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径path: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.log"# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。logAppend: true
storage:# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。dbPath: "/usr/local/mongodb/replica_sets/myrs_27018/data/db"journal:# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。enabled: true
processManagement:# 启用在后台运行mongos或mongod进程的守护进程模式。fork: true# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PIDpidFilePath: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.pid"
net:# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip#bindIpAll: true# 服务实例绑定的IPbindIp: localhost,192.168.229.154#bindIp# 绑定的端口port: 27018
replication:# 副本集的名称replSetName: myrs
启动节点服务:
[root@node1 mongodb]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 45029
child process started successfully, parent exiting
1.4.3 创建仲裁节点
建立存放数据和日志的目录
# 存放日志信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27019/log# 存放数据信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27019/data/db
新建配置信息
vim /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
内容如下:
systemLog:# MongoDB发送所有日志输出的目标指定为文件destination: file# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径path: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.log"# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。logAppend: true
storage:# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。dbPath: "/usr/local/mongodb/replica_sets/myrs_27019/data/db"journal:# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。enabled: true
processManagement:# 启用在后台运行mongos或mongod进程的守护进程模式。fork: true# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PIDpidFilePath: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.pid"
net:# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip#bindIpAll: true# 服务实例绑定的IPbindIp: localhost,192.168.229.154#bindIp# 绑定的端口port: 27019
replication:# 副本集的名称replSetName: myrs
启动节点服务:
[root@node1 mongodb]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 46093
child process started successfully, parent exiting
1.4.4 初始化配置副本集和主节点
使用客户端命令连接任意一个节点,但这里尽量要连接主节点 (27017节点):
/usr/local/mongodb/bin/mongo --host=192.168.229.154 --port=27017
结果,连接上之后,很多命令无法使用,比如 show dbs 等,如下所示,必须初始化副本集才可以。
# 使用默认的配置来初始化副本集
rs.initiate()
# "ok":1,说明创建成功。
# 命令行提示符发生变化,变成了一个从节点角色,此时默认不能读写。稍等片刻,回车,变成主节点。
> rs.initiate()
{"info2" : "no configuration specified. Using a default configuration for the set","me" : "192.168.229.154:27017","ok" : 1
}
myrs:SECONDARY>
myrs:PRIMARY>
1.4.5 查看副本集的配置内容
查看当前副本集配置的文档,语法如下:
# rs.config() 是该方法的别名。
# configuration:可选,如果没有配置,则使用默认主节点配置
rs.conf(configuration)
在 27017 上执行副本集中当前节点的默认节点配置,如下:
myrs:PRIMARY> rs.conf()
{# 副本集的配置数据存储的主键值,默认就是副本集的名字"_id" : "myrs","version" : 1,"protocolVersion" : NumberLong(1),"writeConcernMajorityJournalDefault" : true,# 副本集成员数组,此时只有一个: "host" : "192.168.229.154:27017" "members" : [{"_id" : 0,"host" : "192.168.229.154:27017",# 该成员不是仲裁节点"arbiterOnly" : false,"buildIndexes" : true,"hidden" : false,# 优先级(权重值)"priority" : 1,"tags" : {},"slaveDelay" : NumberLong(0),"votes" : 1}],# 副本集的参数配置"settings" : {"chainingAllowed" : true,"heartbeatIntervalMillis" : 2000,"heartbeatTimeoutSecs" : 10,"electionTimeoutMillis" : 10000,"catchUpTimeoutMillis" : -1,"catchUpTakeoverDelayMillis" : 30000,"getLastErrorModes" : {},"getLastErrorDefaults" : {"w" : 1,"wtimeout" : 0},"replicaSetId" : ObjectId("6528b761af0089c47768dd07")}
}
提示:
副本集配置的查看命令,本质是查询的是 system.replset 的表中的数据
myrs:PRIMARY> use local
switched to db local
myrs:PRIMARY> show collections
oplog.rs
replset.election
replset.minvalid
replset.oplogTruncateAfterPoint
startup_log
system.replset
system.rollback.id
myrs:PRIMARY> db.system.replset.find()
{ "_id" : "myrs", "version" : 1, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "192.168.229.154:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatIntervalMillis" : 2000, "heartbeatTimeoutSecs" : 10, "electionTimeoutMillis" : 10000, "catchUpTimeoutMillis" : -1, "catchUpTakeoverDelayMillis" : 30000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("6528b761af0089c47768dd07") } }
myrs:PRIMARY>
1.4.6 查看副本集状态
返回包含状态信息的文档。此输出使用从副本集的其他成员发送的心跳包中获得的数据反映副本集的当前状态。语法如下:
rs.status()
# 在 27017 上查看副本集状态
myrs:PRIMARY> rs.status()
{# 副本集的名字"set" : "myrs","date" : ISODate("2023-10-13T06:33:05.838Z"),# 说明状态正常"myState" : 1,"term" : NumberLong(1),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"heartbeatIntervalMillis" : NumberLong(2000),"optimes" : {"lastCommittedOpTime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)},"readConcernMajorityOpTime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)},"appliedOpTime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)},"durableOpTime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)}},"lastStableCheckpointTimestamp" : Timestamp(1697178721, 1),"electionCandidateMetrics" : {"lastElectionReason" : "electionTimeout","lastElectionDate" : ISODate("2023-10-13T03:20:02.154Z"),"electionTerm" : NumberLong(1),"lastCommittedOpTimeAtElection" : {"ts" : Timestamp(0, 0),"t" : NumberLong(-1)},"lastSeenOpTimeAtElection" : {"ts" : Timestamp(1697167201, 1),"t" : NumberLong(-1)},"numVotesNeeded" : 1,"priorityAtElection" : 1,"electionTimeoutMillis" : NumberLong(10000),"newTermStartDate" : ISODate("2023-10-13T03:20:02.231Z"),"wMajorityWriteAvailabilityDate" : ISODate("2023-10-13T03:20:02.308Z")},# 副本集成员数组,此时只有一个"members" : [{"_id" : 0,"name" : "192.168.229.154:27017",# 该节点是健康的"health" : 1,"state" : 1,"stateStr" : "PRIMARY","uptime" : 12350,"optime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:33:01Z"),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"infoMessage" : "","electionTime" : Timestamp(1697167202, 1),"electionDate" : ISODate("2023-10-13T03:20:02Z"),"configVersion" : 1,"self" : true,"lastHeartbeatMessage" : ""}],"ok" : 1,"operationTime" : Timestamp(1697178781, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697178781, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
1.4.7 添加副本从节点
在主节点添加从节点,将其他成员加入到副本集,语法如下:
# host格式为:ip地址:端口号
rs.add(host)
将 27018 的副本节点添加到副本集中,命令如下:
myrs:PRIMARY> rs.add("192.168.229.154:27018")
{# 说明添加成功"ok" : 1,"operationTime" : Timestamp(1697179246, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697179246, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
此时,再次查看副本集状态
myrs:PRIMARY> rs.status()
{"set" : "myrs","date" : ISODate("2023-10-13T06:41:58.219Z"),"myState" : 1,"term" : NumberLong(1),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"heartbeatIntervalMillis" : NumberLong(2000),"optimes" : {"lastCommittedOpTime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"readConcernMajorityOpTime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"appliedOpTime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"durableOpTime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)}},"lastStableCheckpointTimestamp" : Timestamp(1697179262, 1),"electionCandidateMetrics" : {"lastElectionReason" : "electionTimeout","lastElectionDate" : ISODate("2023-10-13T03:20:02.154Z"),"electionTerm" : NumberLong(1),"lastCommittedOpTimeAtElection" : {"ts" : Timestamp(0, 0),"t" : NumberLong(-1)},"lastSeenOpTimeAtElection" : {"ts" : Timestamp(1697167201, 1),"t" : NumberLong(-1)},"numVotesNeeded" : 1,"priorityAtElection" : 1,"electionTimeoutMillis" : NumberLong(10000),"newTermStartDate" : ISODate("2023-10-13T03:20:02.231Z"),"wMajorityWriteAvailabilityDate" : ISODate("2023-10-13T03:20:02.308Z")},"members" : [{"_id" : 0,"name" : "192.168.229.154:27017","health" : 1,"state" : 1,"stateStr" : "PRIMARY","uptime" : 12883,"optime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:41:52Z"),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"infoMessage" : "","electionTime" : Timestamp(1697167202, 1),"electionDate" : ISODate("2023-10-13T03:20:02Z"),"configVersion" : 2,"self" : true,"lastHeartbeatMessage" : ""},# 这个新创建的第二个角色{"_id" : 1,"name" : "192.168.229.154:27018","health" : 1,"state" : 2,"stateStr" : "SECONDARY","uptime" : 71,"optime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"optimeDurable" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:41:52Z"),"optimeDurableDate" : ISODate("2023-10-13T06:41:52Z"),"lastHeartbeat" : ISODate("2023-10-13T06:41:56.894Z"),"lastHeartbeatRecv" : ISODate("2023-10-13T06:41:57.236Z"),"pingMs" : NumberLong(0),"lastHeartbeatMessage" : "","syncingTo" : "192.168.229.154:27017","syncSourceHost" : "192.168.229.154:27017","syncSourceId" : 0,"infoMessage" : "","configVersion" : 2}],"ok" : 1,"operationTime" : Timestamp(1697179312, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697179312, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
1.4.8 添加仲裁从节点
添加一个仲裁节点到副本集,语法如下:
rs.addArb(host)
将 27019 的仲裁节点添加到副本集中
myrs:PRIMARY> rs.addArb("192.168.229.154:27019")
{# 说明添加成功"ok" : 1,"operationTime" : Timestamp(1697179436, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697179436, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
此时,再次查看副本集状态
myrs:PRIMARY> rs.status()
{"set" : "myrs","date" : ISODate("2023-10-13T06:45:08.595Z"),"myState" : 1,"term" : NumberLong(1),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"heartbeatIntervalMillis" : NumberLong(2000),"optimes" : {"lastCommittedOpTime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"readConcernMajorityOpTime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"appliedOpTime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"durableOpTime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)}},"lastStableCheckpointTimestamp" : Timestamp(1697179436, 1),"electionCandidateMetrics" : {"lastElectionReason" : "electionTimeout","lastElectionDate" : ISODate("2023-10-13T03:20:02.154Z"),"electionTerm" : NumberLong(1),"lastCommittedOpTimeAtElection" : {"ts" : Timestamp(0, 0),"t" : NumberLong(-1)},"lastSeenOpTimeAtElection" : {"ts" : Timestamp(1697167201, 1),"t" : NumberLong(-1)},"numVotesNeeded" : 1,"priorityAtElection" : 1,"electionTimeoutMillis" : NumberLong(10000),"newTermStartDate" : ISODate("2023-10-13T03:20:02.231Z"),"wMajorityWriteAvailabilityDate" : ISODate("2023-10-13T03:20:02.308Z")},"members" : [{"_id" : 0,"name" : "192.168.229.154:27017","health" : 1,"state" : 1,"stateStr" : "PRIMARY","uptime" : 13073,"optime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:45:02Z"),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"infoMessage" : "","electionTime" : Timestamp(1697167202, 1),"electionDate" : ISODate("2023-10-13T03:20:02Z"),"configVersion" : 3,"self" : true,"lastHeartbeatMessage" : ""},{"_id" : 1,"name" : "192.168.229.154:27018","health" : 1,"state" : 2,"stateStr" : "SECONDARY","uptime" : 262,"optime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"optimeDurable" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:45:02Z"),"optimeDurableDate" : ISODate("2023-10-13T06:45:02Z"),"lastHeartbeat" : ISODate("2023-10-13T06:45:06.956Z"),"lastHeartbeatRecv" : ISODate("2023-10-13T06:45:06.973Z"),"pingMs" : NumberLong(0),"lastHeartbeatMessage" : "","syncingTo" : "192.168.229.154:27017","syncSourceHost" : "192.168.229.154:27017","syncSourceId" : 0,"infoMessage" : "","configVersion" : 3},{"_id" : 2,"name" : "192.168.229.154:27019","health" : 1,"state" : 7,"stateStr" : "ARBITER","uptime" : 71,"lastHeartbeat" : ISODate("2023-10-13T06:45:06.955Z"),"lastHeartbeatRecv" : ISODate("2023-10-13T06:45:06.956Z"),"pingMs" : NumberLong(0),"lastHeartbeatMessage" : "","syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"infoMessage" : "","configVersion" : 3}],"ok" : 1,"operationTime" : Timestamp(1697179502, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697179502, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
1.5 副本集读写操作
接下来我们测试三个不同角色的节点的数据读写情况。登录主节点 27017,写入和读取数据
myrs:PRIMARY> use articledb
switched to db articledb
myrs:PRIMARY> db
articledb
myrs:PRIMARY> db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date()})
WriteResult({ "nInserted" : 1 })
myrs:PRIMARY> db.comment.find()
{ "_id" : ObjectId("6528e8155dabb447bc9211d2"), "articleid" : "100000", "content" : "今天天气真好,阳光明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2023-10-13T06:47:49.542Z") }
登录从节点 27018
myrs:SECONDARY> show dbs
2023-10-13T00:06:41.119-0700 E QUERY [js] Error: listDatabases failed:{"operationTime" : Timestamp(1697180793, 1),"ok" : 0,"errmsg" : "not master and slaveOk=false","code" : 13435,"codeName" : "NotMasterNoSlaveOk","$clusterTime" : {"clusterTime" : Timestamp(1697180793, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:151:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
发现,不能读取集合的数据。当前从节点只是一个备份,不是奴隶节点,无法读取数据,写当然更不行。
因为默认情况下,从节点是没有读写权限的,可以增加读的权限,但需要进行设置。
# 设置读操作权限
# 该命令是 db.getMongo().setSlaveOk() 的简化命令。
rs.slaveOk() 或 rs.slaveOk(true)
# 在 27018 上设置作为奴隶节点权限,具备读权限
myrs:SECONDARY> rs.slaveOk()
WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead.
# 执行查询命令,运行成功!
myrs:SECONDARY> show dbs
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.000GB
myrs:SECONDARY> db.comment.find()
myrs:SECONDARY> use articledb
switched to db articledb
myrs:SECONDARY> db.comment.find()
{ "_id" : ObjectId("6528e8155dabb447bc9211d2"), "articleid" : "100000", "content" : "今天天气真好,阳光明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2023-10-13T06:47:49.542Z") }
# 但仍然不允许插入
myrs: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({"operationTime" : Timestamp(1697181093, 1),"ok" : 0,"errmsg" : "not master","code" : 10107,"codeName" : "NotMaster","$clusterTime" : {"clusterTime" : Timestamp(1697181093, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
})
现在实现了读写分离,让主插入数据,让从来读取数据。
如果要取消作为奴隶节点的读权限:
rs.slaveOk(false)
# 在 27018 取消设置奴隶节点权限
myrs:SECONDARY> rs.slaveOk(false)
WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead.
# 无法再查看数据
myrs:SECONDARY> db.comment.find()
Error: error: {"operationTime" : Timestamp(1697181203, 1),"ok" : 0,"errmsg" : "not master and slaveOk=false","code" : 13435,"codeName" : "NotMasterNoSlaveOk","$clusterTime" : {"clusterTime" : Timestamp(1697181203, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
仲裁者节点,不存放任何业务数据的,可以登录查看
# 登录 27019 节点
/usr/local/mongodb/bin/mongo --host 192.168.229.154 --port 27019# 设置为奴隶节点
myrs:ARBITER> rs.slaveOk()
WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead.
# 无法查看相关信息
myrs:ARBITER> show dbs
2023-10-13T00:15:19.072-0700 E QUERY [js] Error: listDatabases failed:{"ok" : 0,"errmsg" : "node is not in primary or recovering state","code" : 13436,"codeName" : "NotMasterOrSecondary"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:151:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
1.6 主节点的选举原则
MongoDB 在副本集中,会自动进行主节点的选举,主节点选举的触发条件:
a、主节点故障
b、主节点网络不可达(默认心跳信息为10秒)
c、人工干预(rs.stepDown(600))
一旦触发选举,就要根据一定规则来选主节点。选举规则是根据票数来决定谁获胜:
票数最高,并且获得了 “大多数” 成员的投票支持的节点获胜。
“大多数” 的定义为:假设复制集内投票成员数量为 N,则大多数为 N/2 + 1。例如:3 个投票成员,则大多数的值是 2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举出 Primary,复制集将无法提供写服务,处于只读状态。
若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。
数据的新旧是通过操作日志 oplog 来对比的。
在获得票数的时候,优先级(priority)参数影响重大。
可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为 0-1000,相当于可额外增加 0-1000 的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员更有资格成为主要成员,更低的值可使成员更不符合条件。
默认情况下,优先级的值是 1
myrs:PRIMARY> rs.conf()
{"_id" : "myrs","version" : 3,"protocolVersion" : NumberLong(1),"writeConcernMajorityJournalDefault" : true,"members" : [{"_id" : 0,"host" : "192.168.229.154:27017","arbiterOnly" : false,"buildIndexes" : true,"hidden" : false,"priority" : 1,"tags" : {},"slaveDelay" : NumberLong(0),"votes" : 1},{"_id" : 1,"host" : "192.168.229.154:27018","arbiterOnly" : false,"buildIndexes" : true,"hidden" : false,"priority" : 1,"tags" : {},"slaveDelay" : NumberLong(0),"votes" : 1},{"_id" : 2,"host" : "192.168.229.154:27019","arbiterOnly" : true,"buildIndexes" : true,"hidden" : false,"priority" : 0,"tags" : {},"slaveDelay" : NumberLong(0),"votes" : 1}],"settings" : {"chainingAllowed" : true,"heartbeatIntervalMillis" : 2000,"heartbeatTimeoutSecs" : 10,"electionTimeoutMillis" : 10000,"catchUpTimeoutMillis" : -1,"catchUpTakeoverDelayMillis" : 30000,"getLastErrorModes" : {},"getLastErrorDefaults" : {"w" : 1,"wtimeout" : 0},"replicaSetId" : ObjectId("6528b761af0089c47768dd07")}
}
可以看出,主节点和副本节点的优先级各为 1,即,默认可以认为都已经有了一票。但选举节点,优先级是 0,(要注意是,官方说了,选举节点的优先级必须是 0,不能是别的值。即不具备选举权,但具有投票权)。
1.7 故障测试
1.7.1 副本节点故障测试
首先关闭 27018 副本节点。主节点和仲裁节点对 27018 的心跳失败。但是因为主节点还在,因此,没有触发投票选举。如果此时,在主节点写入数据。
db.comment.insert({"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"})
再次启动 27018 从节点,会发现,主节点写入的数据,会自动同步给从节点。
1.7.2 主节点故障测试
关闭 27017 节点,从节点和仲裁节点对 27017 的心跳失败,当失败超过 10 秒,此时因为没有主节点了,会自动发起投票。
而副本节点只有 27018,因此,候选人只有一个就是 27018,开始投票。
27019 向 27018 投了一票,27018 本身自带一票,因此共两票,超过了 “大多数”
27019 是仲裁节点,没有选举权,27018 不向其投票,其票数是 0。
最终结果,27018 成为主节点。具备读写功能。在 27018 写入数据查看。
db.comment.insert({"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"})
再启动 27017 节点,发现 27017 变成了从节点,27018 仍保持主节点。
登录 27017 节点,发现是从节点了,数据自动从 27018 同步。从而实现了高可用。
1.7.3 仲裁节点和主节点故障
先关掉仲裁节点 27019,关掉现在的主节点 27018。
登录 27017 后,发现,27017 仍然是从节点,副本集中没有主节点了,导致此时,副本集是只读状态,无法写入。
为啥不选举了?因为 27017 的票数,没有获得大多数,即没有大于等于 2,它只有默认的一票(优先级是1)如果要触发选举,随便加入一个成员即可。
如果只加入 27019 仲裁节点成员,则主节点一定是 27017,因为没得选了,仲裁节点不参与选举,但参与投票。
如果只加入 27018 节点,会发起选举。因为 27017 和 27018 都是两票,则按照谁数据新,谁当主节点。
1.7.4 仲裁节点和从节点故障
先关掉仲裁节点 27019,关掉现在的副本节点 27018,
10 秒后,27017 主节点自动降级为副本节点。(服务降级)副本集不可写数据了,已经故障了。
1.8 Compass 连接副本集
1.9 SpringDataMongoDB 连接副本集
副本集语法如下:
# slaveOk=true :开启副本节点读的功能,可实现读写分离
# connect=replicaSet:自动到副本集中选择读写的主机,如果 slaveOk 是打开的,则实现了读写分离
mongodb://host1,host2,host3/数据库名称?connect=replicaSet&laveOk=true$replicaSet=副本集名字
修改我们自己的 application.yml 文件,如下所示:
spring:# 数据源配置data:mongodb:# 主机地址# host: 192.168.229.154# 数据库# database: articledb# 默认端口是27017# port: 27017# 也可以使用uri连接uri: mongodb://192.168.229.154:27017,192.168.229.154:27018,192.168.229.154:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
注意:
SpringDataMongoDB 自动实现了读写分离。
写操作时,只打开主节点连接;
读操作时,同时打开主节点和从节点连接,但使用从节点获取数据。
相关文章:

MongoDB 集群配置
一、副本集 Replica Sets 1.1 简介 MongoDB 中的副本集(Replica Set)是一组维护相同数据集的 mongod 服务。 副本集可提供冗余和高可用性,是所有生产部署的基础。 也可以说,副本集类似于有自动故障恢复功能的主从集群。通俗的讲就…...

random生成随机数的灵活运用
random返回的 [0,1) 之间的一个随即小数 思考:请写出获取 a-b 之间的一个随机整数,a,b均为整数,比如 a2 , b7 即返回一个数 x > [2,7]Math.random()*(b-a) 返回的就是 [0,b-a](int)(aMath.random()*(b-a1)) 》 (int)(2Math.random()*6) Ma…...
宏定义实现二进制数的奇偶位交换
思路分析 通过宏定义来实现二进制数的奇偶位交换,如果一个个遍历交换的话,那得算到猴年马月,这是我在网上看到的一个思路: 我们将每一位(整数在计算机里存储是4字节,32位)二进制数的奇数位保留…...

【ELK 使用指南】ELK + Filebeat 分布式日志管理平台部署
ELK和EFLK 一、前言1.1 日志分析的作用1.2 需要收集的日志1.3 完整日志系统的基本特征 二、ELK概述2.1 ELK简介2.2 为什么要用ELK?2.3 ELK的组件 三、ELK组件详解3.1 Logstash3.1.1 简介3.1.2 Logstash命令常用选项3.1.3 Logstash 的输入和输出流3.1.4 Logstash配置文件 3.2 E…...

传输层 | UDP协议、TCP协议
之前讲过的http与https都是应用层协议,当应用层协议将报文构建好之后就要将报文往下层传输层进行传递,而传输层就是负责将数据能够从发送端传到接收端。 再谈端口号 端口号(port)标识了一个主机上进行通信的不同的应用程序,在TCP/IP协议中&…...

Webmin(CVE-2019-15107)远程命令执行漏洞复现
漏洞编号 CVE-2019-15107 webmin介绍 什么是webmin Webmin是目前功能最强大的基于Web的Unix系统管理工具。管理员通过浏览器访问Webmin的各种管理功能并完成相应的管理动作http://www.webmin.com/Webmin 是一个用 Perl 编写的基于浏览器的管理应用程序。是一个基于Web的界面…...
嵌入式实时操作系统的设计与开发 (前后台系统)
前后台结构 前后台系统也称为中断驱动系统,其软件结构的显著特点是运行的程序有前台和后台之分。 在后台,一组程序按照轮询方式访问CPU;在前台,当用户的请求到达时,首先向CPU触发中断,然后将该请求转交给后…...

Macos数字音乐库:Elsten Software Bliss for Mac
Elsten Software Bliss for Mac是一款优秀的音乐管理软件,它可以帮助用户自动化整理和标记数字音乐库,同时可以自动识别音乐信息并添加标签和元数据。 此外,Bliss还可以修复音乐库中的问题,例如重复的音乐文件和缺失的专辑封面等…...
基于SpringBoot的校园周边美食探索及分享平台的设计与实现
文章目录 项目介绍主要功能截图:登录注册个人信息管理后台首页轮播图管理美食鉴赏我的好友管理我的收藏管理用户管理部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给…...

GPT-4V的图片识别和分析能力
GPT-4V是OpenAI开发的大型语言模型,是GPT-4的升级版本。GPT-4V在以下几个方面进行了改进: 模型规模更大:GPT-4V的参数量达到了1.37T,是GPT-4的10倍。训练数据更丰富:GPT-4V的训练数据包括了1.56T的文本和代码数据。算…...

蓝桥杯(等差素数列,C++)
思路: 1、因为找的是长度为10,且公差最小的等差素数列,直接用枚举即可。 2、枚举用三重循环,第一重枚举首项,第二重枚举公差,第三重因为首项算一个,所以枚举九个等差素数。 代码:…...

Ceph 中的写入放大
新钛云服已累计为您分享769篇技术干货 介绍 Ceph 是一个开源的分布式存储系统,设计初衷是提供较好的性能、可靠性和可扩展性。 Ceph 独一无二地在一个统一的系统中同时提供了对象、块、和文件存储功能。 Ceph 消除了对系统单一中心节点的依赖,实现了无中…...
Mabatis-puls强于Mybatis的地方
Mabatis-puls与Mybatis都是优秀的Java持久化框架,但是Mabatis-puls相较于Mybatis有以下几个方面的优势: 性能更优:Mabatis-puls采用了Javassist技术,使得它在运行时比Mybatis更快速,尤其是在执行大量SQL的情况下&#…...

vue项目npm intall时发生版本冲突的解决办法
在日常使用命令npm install / npm install XX下载依赖的操作中,我经常会遇到无法解析依赖树的问题(依赖冲突) 当遇到这种情况的时候,可以通过以下命令完成依赖安装: npm install --legacy-peer-deps npm install xxx…...

tomcat多实例部署jenkins
tomcat多实例部署jenkins 文章目录 tomcat多实例部署jenkins1.简介:2.优缺点:3.工作原理:4.工作流程:5.tomcat多实例部署jenkins流程5.1.环境说明5.2.部署前准备工作5.3.多实例部署tomcat5.4.部署jenkins5.5.创建一个jenkins项目5…...
强连通分量+缩点
[图论与代数结构 701] 强连通分量 题目描述 给定一张 n n n 个点 m m m 条边的有向图,求出其所有的强连通分量。 注意,本题可能存在重边和自环。 输入格式 第一行两个正整数 n n n , m m m ,表示图的点数和边数。 接下来…...
如何做系统架构设计
文章目录 1、如何进行架构设计体系架构需求体系架构设计体系架构文档化体系架构复审体系架构实现体系架构演化 2、架构设计注意事项分治原则服务自治拥抱变化可维护性考虑依赖和限制阅读代码注意事项 3、最后 系统架构应该如何设计,从自己做架构的经历来分享一些体…...

L14D6内核模块编译方法
一、内核模块基础代码解析 一个内核模块代码错误仍然会导致的内核崩溃。 GPL协议:开源规定,使用内核一些函数需要 1、单内核的缺点 单内核扩展性差的缺点减小内核镜像文件体积,一定程度上节省内存资源提高开发效率不能彻底解决稳定性低的缺…...

PyTorch入门教学——dir()函数和help()函数的应用
1、简介 已知PyTorch是一个工具包,其中包含许多功能函数。dir()函数和help()函数是学习PyTorch包的重要法宝。 dir():能让我们知道工具包以及工具包中的分隔区有什么东西。help():能让我们知道每个工具是如何使用的,即工具的使用…...

使用Elasticsearch来进行简单的DDL搜索数据
说明:Elasticsearch提供了多种多样的搜索方式来满足不同使用场景的需求,我们可以使用Elasticsearch来进行各种复制的查询,进行数据的检索。 1.1 精准查询 用来查询索引中某个类型为keyword的文本字段,类似于SQL的“”查询。 创…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...

免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...