mongoDB副本集-Replica Sets

简介

MongoDB 中的副本集( Replica Set )是一组维护相同数据集的 mongod 服务。 副本集可提供冗余和高可用性,是所有生产部署的基础。也可以说,副本集类似于有自动故障恢复功能的主从集群。通俗的讲就是用多台机器进行同一数据的异步同步,从而使多台机器拥有同一数据的多个副本,并且当主库当掉时在不需要用户干预的情况下自动切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。
1 )冗余和数据可用性
复制提供冗余并提高数据可用性。 通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别的容错功能,以防止丢失单个数据库服务器。
在某些情况下,复制可以提供增加的读取性能,因为客户端可以将读取操作发送到不同的服务上, 在不同数据中心维护数据副本可以增加分布式应用程序的数据位置和可用性。 您还可以为专用目的维护其他副本,例如灾难恢复,报告或备份。
2 MongoDB 中的复制
副本集是一组维护相同数据集的 mongod 实例。 副本集包含多个数据承载节点和可选的一个仲裁节点。在承载数据的节点中,一个且仅一个成员被视为主节点,而其他节点被视为次要(从)节点。
主节点接收所有写操作。 副本集只能有一个主要能够确认具有 {w “most”} 写入关注的写入 ; 虽然在某些情况下,另一个mongod 实例可能暂时认为自己也是主要的。主要记录其操作日志中的数据集的所有更改,即oplog

辅助 ( 副本 ) 节点复制主节点的 oplog 并将操作应用于其数据集,以使辅助节点的数据集反映主节点的数据集。 如果主要人员不在,则符合条件的中学将举行选举以选出新的主要人员。
3 )主从复制和副本集区别
主从集群和副本集最大的区别就是副本集没有固定的 主节点 ;整个集群会选出一个 主节点 ,当其挂掉后,又在剩下的从节点中选中其他节点为“ 主节点 ,副本集总有一个活跃点 ( 主、 primary) 和一个或多个备份节点( 从、 secondary)

副本集的三个角色

副本集有两种类型三种角色
两种类型:
  • 主节点(Primary)类型:数据操作的主要连接点,可读写。
  • 次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举。
三种角色:
主要成员( Primary ):主要接收所有写操作。就是主节点。
副本成员( Replicate ):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型。
仲裁者( Arbiter ):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。

 

关于仲裁者的额外说明:
您可以将额外的 mongod 实例添加到副本集作为仲裁者。 仲裁者不维护数据集。 仲裁者的目的是通过响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。 因为它们不存储数据集,所以仲裁器可以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。
如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的 大多数 投票。 仲裁者不需要专用硬件。
仲裁者将永远是仲裁者,而主要人员可能会退出并成为次要人员,而次要人员可能成为选举期间的主要人员。
如果你的副本 + 主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。
如果你的副本+ 主节点的个数是奇数,可以不加仲裁者。

副本集架构目标

一主一副本一仲裁

副本集的创建  

第一步:创建主节点

建立存放数据和日志的目录
#-----------myrs
#主节点
mkdir -p /mongodb/replica_sets/myrs_27017/log 
mkdir -p /mongodb/replica_sets/myrs_27017/data/db
新建或修改配置文件:
vim /mongodb/replica_sets/myrs_27017/mongod.conf
myrs_27017
systemLog:
    #MongoDB发送所有日志输出的目标指定为文件
    destination: file
    #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
    path: "/mongodb/replica_sets/myrs_27017/log/mongod.log"
    #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
    logAppend: true
storage:
    #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
    dbPath: "/mongodb/replica_sets/myrs_27017/data/db"
processManagement:
    #启用在后台运行mongos或mongod进程的守护进程模式。
    fork: true
    #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
    pidFilePath: "/mongodb/replica_sets/myrs_27017/log/mongod.pid"
net:
    #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
    #bindIpAll: true
    #服务实例绑定的IP
    bindIp: localhost,192.168.2.4
    #bindIp
    #绑定的端口
    port: 27017
replication:
    #副本集的名称
    replSetName: myrs
启动节点服务:
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf

第二步:创建副本节点

建立存放数据和日志的目录
#-----------myrs
#副本节点
mkdir -p /mongodb/replica_sets/myrs_27018/log 
mkdir -p /mongodb/replica_sets/myrs_27018/data/db
新建或修改配置文件:
vim /mongodb/replica_sets/myrs_27018/mongod.conf
myrs_27018
systemLog:
    #MongoDB发送所有日志输出的目标指定为文件
    destination: file
    #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
    path: "/mongodb/replica_sets/myrs_27018/log/mongod.log"
    #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
    logAppend: true
storage:
    #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
    dbPath: "/mongodb/replica_sets/myrs_27018/data/db"
processManagement:
    #启用在后台运行mongos或mongod进程的守护进程模式。
    fork: true
    #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
    pidFilePath: "/mongodb/replica_sets/myrs_27018/log/mongod.pid"
net:
    #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
    #bindIpAll: true
    #服务实例绑定的IP
    bindIp: localhost,192.168.2.4
    #bindIp
    #绑定的端口
    port: 27018
replication:
    #副本集的名称
    replSetName: myrs
启动节点服务:
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf

第三步:创建仲裁节点

建立存放数据和日志的目录
#-----------myrs
#仲裁节点
mkdir -p /mongodb/replica_sets/myrs_27019/log 
mkdir -p /mongodb/replica_sets/myrs_27019/data/db
仲裁节点:
新建或修改配置文件:
vim /mongodb/replica_sets/myrs_27019/mongod.conf
myrs_27019
systemLog:
    #MongoDB发送所有日志输出的目标指定为文件
    destination: file
    #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
    path: "/mongodb/replica_sets/myrs_27019/log/mongod.log"
    #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
    logAppend: true
storage:
    #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
    dbPath: "/mongodb/replica_sets/myrs_27019/data/db"
processManagement:
    #启用在后台运行mongos或mongod进程的守护进程模式。
    fork: true
    #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
    pidFilePath: "/mongodb/replica_sets/myrs_27019/log/mongod.pid"
net:
    #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
    #bindIpAll: true
    #服务实例绑定的IP
    bindIp: localhost,192.168.2.4
    #bindIp
    #绑定的端口
    port: 27019
replication:
    #副本集的名称
    replSetName: myrs
启动节点服务:
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf

第四步:初始化配置副本集和主节点

使用客户端命令连接任意一个节点,但这里尽量要连接主节点 (27017 节点 )
/usr/local/mongodb/bin/mongo --host=192.168.2.4 --port=27017
结果,连接上之后,很多命令无法使用,,比如 show dbs 等,必须初始化副本集才行
准备初始化新的副本集:
语法:
rs.initiate(configuration)
选项:
Parameter
Type
Description
configuration
document
Optional. A document that specifies configuration for the new replica set. If a configuration is not specified,MongoDB uses a default replica set configuration.
【示例】
使用默认的配置来初始化副本集:
rs.initiate()
执行结果:
> rs.initiate()
{
	"info2" : "no configuration specified. Using a default configuration for the set","me" : "192.168.2.4:27017","ok" : 1
}
myrs:SECONDARY> 
提示:
  1. 1“ok”的值为1,说明创建成功。
  2. 2)命令行提示符发生变化,变成了一个从节点角色,此时默认不能读写。稍等片刻,回车,变成主节点。

第五步:查看副本集的配置内容

说明:
返回包含当前副本集配置的文档。
语法:
rs.conf(configuration)
提示:
rs.config() 是该方法的别名。
configuration :可选,如果没有配置,则使用默认主节点配置。
【示例】
27017 上执行副本集中当前节点的默认节点配置
myrs:PRIMARY> rs.conf()
{
	"_id" : "myrs","version" : 1,"term" : 1,"members" : [
		{
			"_id" : 0,"host" : "192.168.2.4:27017","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("65896ce53a4a40258a007293")
	}
}
myrs:PRIMARY> 
说明:
  1. 1"_id" : "myrs" :副本集的配置数据存储的主键值,默认就是副本集的名字
  2. 2"members" :副本集成员数组,此时只有一个: "host" : "180.76.159.126:27017" ,该成员不是仲裁节点: "arbiterOnly" : false ,优先级(权重值): "priority" : 1,
  3. 3"settings" :副本集的参数配置。

提示:副本集配置的查看命令,本质是查询的是 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","members" : [ { "_id" : 0,"host" :
"180.76.159.126:27017","hidden" :
false,"tags" : { },"slaveDelay" : NumberLong(0),"votes" : 1
} ],"settings" : { "chainingAllowed" : true,"getLastErrorModes" : { },"getLastErrorDefaults" : { "w" : 1,"wtimeout" : 0
},"replicaSetId" : ObjectId("5d539bdcd6a308e600d126bb") } }
myrs:PRIMARY>

第六步:查看副本集状态

检查副本集状态。
说明:
返回包含状态信息的文档。此输出使用从副本集的其他成员发送的心跳包中获得的数据反映副本集的当前状态。
语法:
rs.status()
【示例】
27017 上查看副本集状态:
myrs:PRIMARY> rs.status()
{
	"set" : "myrs","date" : ISODate("2023-12-25T11:59:37.520Z"),"myState" : 1,"term" : NumberLong(1),"syncSourceHost" : "","syncSourceId" : -1,"heartbeatIntervalMillis" : NumberLong(2000),"majorityVoteCount" : 1,"writeMajorityCount" : 1,"votingMembersCount" : 1,"writableVotingMembersCount" : 1,"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1703505576,1),"t" : NumberLong(1)
		},"lastCommittedWallTime" : ISODate("2023-12-25T11:59:36.211Z"),"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1703505576,"appliedOpTime" : {
			"ts" : Timestamp(1703505576,"durableOpTime" : {
			"ts" : Timestamp(1703505576,"lastAppliedWallTime" : ISODate("2023-12-25T11:59:36.211Z"),"lastDurableWallTime" : ISODate("2023-12-25T11:59:36.211Z")
	},"lastStableRecoveryTimestamp" : Timestamp(1703505536,"electionCandidateMetrics" : {
		"lastElectionReason" : "electionTimeout","lastElectionDate" : ISODate("2023-12-25T11:52:05.810Z"),"electionTerm" : NumberLong(1),"lastCommittedOpTimeAtElection" : {
			"ts" : Timestamp(1703505125,"t" : NumberLong(-1)
		},"lastSeenOpTimeAtElection" : {
			"ts" : Timestamp(1703505125,"numVotesNeeded" : 1,"priorityAtElection" : 1,"electionTimeoutMillis" : NumberLong(10000),"newTermStartDate" : ISODate("2023-12-25T11:52:05.934Z"),"wMajorityWriteAvailabilityDate" : ISODate("2023-12-25T11:52:06.024Z")
	},"name" : "192.168.2.4:27017","health" : 1,"state" : 1,"stateStr" : "PRIMARY","uptime" : 1122,"optime" : {
				"ts" : Timestamp(1703505576,"t" : NumberLong(1)
			},"optimeDate" : ISODate("2023-12-25T11:59:36Z"),"lastDurableWallTime" : ISODate("2023-12-25T11:59:36.211Z"),"infoMessage" : "","electionTime" : Timestamp(1703505125,2),"electionDate" : ISODate("2023-12-25T11:52:05Z"),"configVersion" : 1,"configTerm" : 1,"self" : true,"lastHeartbeatMessage" : ""
		}
	],"ok" : 1,"$clusterTime" : {
		"clusterTime" : Timestamp(1703505576,"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)
		}
	},"operationTime" : Timestamp(1703505576,1)
}
myrs:PRIMARY> 
说明:
  1. 1"set" : "myrs" :副本集的名字
  2. 2"myState" : 1:说明状态正常
  3. 3"members" :副本集成员数组,此时只有一个: "name" : "180.76.159.126:27017" ,该成员的角色是 "stateStr" : "PRIMARY",该节点是健康的: "health" : 1

第七步:添加副本从节点

在主节点添加从节点,将其他成员加入到副本集
语法:
rs.add(host,arbiterOnly)
选项:
Parameter
Type
Description
host
string or
document
要添加到副本集的新成员。 指定为字符串或配置文档: 1 )如果是一个字符串,则需要指定新成员的主机名和可选的端口号;2 )如果是一个文档,请指定在 members 数组中找到的副本集成员配置文档。 您必须在成员配置文档中指定主机字段。有关文档配置字段的说明,详见下方文档:“ 主机成员的配置文
arbiterOnly
boolean
可选的。 仅在 <host> 值为字符串时适用。 如果为 true ,则添加的主机是仲裁者。
主机成员的配置文档:
{
    _id: <int>,host: <string>,// required
    arbiterOnly: <boolean>,buildIndexes: <boolean>,hidden: <boolean>,priority: <number>,tags: <document>,slaveDelay: <int>,votes: <number>
}
【示例】
27018 的副本节点添加到副本集中:
myrs:PRIMARY> rs.add("192.168.2.4:27018")
{
	"ok" : 1,"$clusterTime" : {
		"clusterTime" : Timestamp(1703505842,"operationTime" : Timestamp(1703505842,1)
}
myrs:PRIMARY> 
说明:
  1. 1"ok" : 1 :说明添加成功。
查看副本集状态:
myrs:PRIMARY> rs.status()
{
	"set" : "myrs","date" : ISODate("2023-12-25T12:04:43.560Z"),"majorityVoteCount" : 2,"writeMajorityCount" : 2,"votingMembersCount" : 2,"writableVotingMembersCount" : 2,"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1703505876,"lastCommittedWallTime" : ISODate("2023-12-25T12:04:36.274Z"),"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1703505876,"appliedOpTime" : {
			"ts" : Timestamp(1703505876,"durableOpTime" : {
			"ts" : Timestamp(1703505876,"lastAppliedWallTime" : ISODate("2023-12-25T12:04:36.274Z"),"lastDurableWallTime" : ISODate("2023-12-25T12:04:36.274Z")
	},"lastStableRecoveryTimestamp" : Timestamp(1703505844,"uptime" : 1428,"optime" : {
				"ts" : Timestamp(1703505876,"optimeDate" : ISODate("2023-12-25T12:04:36Z"),"lastDurableWallTime" : ISODate("2023-12-25T12:04:36.274Z"),"configVersion" : 3,"lastHeartbeatMessage" : ""
		},{
			"_id" : 1,"name" : "192.168.2.4:27018","state" : 2,"stateStr" : "SECONDARY","uptime" : 41,"optimeDurable" : {
				"ts" : Timestamp(1703505876,"optimeDurableDate" : ISODate("2023-12-25T12:04:36Z"),"lastHeartbeat" : ISODate("2023-12-25T12:04:42.065Z"),"lastHeartbeatRecv" : ISODate("2023-12-25T12:04:42.064Z"),"pingMs" : NumberLong(0),"lastHeartbeatMessage" : "","syncSourceHost" : "192.168.2.4:27017","syncSourceId" : 0,"configTerm" : 1
		}
	],"$clusterTime" : {
		"clusterTime" : Timestamp(1703505876,"operationTime" : Timestamp(1703505876,1)
}
myrs:PRIMARY> 
说明:
  1. 1"name" : "180.76.159.126:27018" 是第二个节点的名字,其角色是 "stateStr" :"SECONDARY"

第八步:添加仲裁从节点  

添加一个仲裁节点到副本集
语法:
rs.addArb(host)
27019 的仲裁节点添加到副本集中:

myrs:PRIMARY> db.adminCommand({
...    "setDefaultRWConcern" : 2,...    "defaultWriteConcern" : {
...      "w" : 3
...    }
...  })
{
	"defaultReadConcern" : {
		"level" : "local"
	},"defaultWriteConcern" : {
		"w" : 3,"wtimeout" : 0
	},"updateOpTime" : Timestamp(1703511727,"updateWallClockTime" : ISODate("2023-12-25T13:42:11.587Z"),"defaultWriteConcernSource" : "global","defaultReadConcernSource" : "implicit","localUpdateWallClockTime" : ISODate("2023-12-25T13:42:11.601Z"),"$clusterTime" : {
		"clusterTime" : Timestamp(1703511731,"operationTime" : Timestamp(1703511731,2)
}
myrs:PRIMARY> rs.addArb("192.168.2.4:27019")
{
	"ok" : 1,"$clusterTime" : {
		"clusterTime" : Timestamp(1703511741,"operationTime" : Timestamp(1703511741,1)
}
myrs:PRIMARY> 
说明:
  1. 1"ok" : 1 :说明添加成功。
查看副本集状态:
myrs:PRIMARY> rs.status()
{
	"set" : "myrs","date" : ISODate("2023-12-25T12:07:18.726Z"),"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1703506036,"lastCommittedWallTime" : ISODate("2023-12-25T12:07:16.298Z"),"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1703506036,"appliedOpTime" : {
			"ts" : Timestamp(1703506036,"durableOpTime" : {
			"ts" : Timestamp(1703506036,"lastAppliedWallTime" : ISODate("2023-12-25T12:07:16.298Z"),"lastDurableWallTime" : ISODate("2023-12-25T12:07:16.298Z")
	},"lastStableRecoveryTimestamp" : Timestamp(1703506016,"uptime" : 1583,"optime" : {
				"ts" : Timestamp(1703506036,"optimeDate" : ISODate("2023-12-25T12:07:16Z"),"lastDurableWallTime" : ISODate("2023-12-25T12:07:16.298Z"),"uptime" : 196,"optimeDurable" : {
				"ts" : Timestamp(1703506036,"optimeDurableDate" : ISODate("2023-12-25T12:07:16Z"),"lastHeartbeat" : ISODate("2023-12-25T12:07:18.327Z"),"lastHeartbeatRecv" : ISODate("2023-12-25T12:07:18.250Z"),"$clusterTime" : {
		"clusterTime" : Timestamp(1703506036,"operationTime" : Timestamp(1703506036,1)
}
myrs:PRIMARY> 
说明:
  1. 1"name" : "180.76.159.126:27019" 是第二个节点的名字,其角色是 "stateStr" : "ARBITER"

副本集的数据读写操作

目标:测试三个不同角色的节点的数据读写情况。
登录主节点 27017 ,写入和读取数据:
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host 192.168.2.4 --port 27017
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.2.4:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("198dc349-8b2d-4ca5-92de-0273fa719148") }
MongoDB server version: 7.0.4
WARNING: shell and server versions do not match
Server has startup warnings: 
{"t":{"$date":"2023-12-25T19:40:57.147+08:00"},"s":"W","c":"CONTROL","id":22120,"ctx":"initandlisten","msg":"Access control is not enabled for the database. Read and write access to data and configuration is unrestricted","tags":["startupWarnings"]}

{"t":{"$date":"2023-12-25T19:40:57.148+08:00"},"id":22138,"msg":"You are running this process as the root user,which is not recommended","tags":["startupWarnings"]}

{"t":{"$date":"2023-12-25T19:40:57.173+08:00"},"id":22178,"msg":"/sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'","id":22181,"msg":"/sys/kernel/mm/transparent_hugepage/defrag is 'always'. We suggest setting it to 'never'","id":22184,"msg":"Soft rlimits for open file descriptors too low","attr":{"currentValue":1024,"recommendedMinimum":64000},"tags":["startupWarnings"]}

myrs:PRIMARY> use articledb
switched to db articledb
myrs:PRIMARY> db
articledb
myrs:PRIMARY> db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光
2023-12-25T20:13:05.207+0800 E QUERY    [js] SyntaxError: unterminated string literal @(shell):1:50
myrs:PRIMARY> 明媚","userid":"1001","nickname":"Rose","createdatetime":new Date()})
2023-12-25T20:13:05.892+0800 E QUERY    [js] SyntaxError: missing ; before statement @(shell):1:2
myrs:PRIMARY> db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明媚","createdatetime":new Date()})
WriteResult({ "nInserted" : 1 })
myrs:PRIMARY> db.comment.find()
{ "_id" : ObjectId("658971ef4cf53b8b9ab5ff3d"),"articleid" : "100000","content" : "今天天气真好,阳光明媚","userid" : "1001","nickname" : "Rose","createdatetime" : ISODate("2023-12-25T12:13:35.462Z") }
myrs:PRIMARY> 
登录从节点 27018
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host 192.168.2.4 --port 27018
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.2.4:27018/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("5b58b846-923c-45e9-ab19-0898ad67e605") }
MongoDB server version: 7.0.4
WARNING: shell and server versions do not match
Server has startup warnings: 
{"t":{"$date":"2023-12-25T18:32:34.032+08:00"},"tags":["startupWarnings"]}

{"t":{"$date":"2023-12-25T18:32:34.033+08:00"},"tags":["startupWarnings"]}

{"t":{"$date":"2023-12-25T18:32:34.034+08:00"},"tags":["startupWarnings"]}

myrs:SECONDARY> show dbs;
2023-12-25T20:15:07.556+0800 E QUERY    [js] Error: listDatabases failed:{
	"topologyVersion" : {
		"processId" : ObjectId("65895a4170dd267d9b182983"),"counter" : NumberLong(4)
	},"ok" : 0,"errmsg" : "not master and slaveOk=false","code" : 13435,"codeName" : "NotPrimaryNoSecondaryOk","$clusterTime" : {
		"clusterTime" : Timestamp(1703506506,"operationTime" : Timestamp(1703506506,1)
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:139:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
myrs:SECONDARY> 
发现,不能读取集合的数据。当前从节点只是一个备份,不是奴隶节点,无法读取数据,写当然更不行。
因为默认情况下,从节点是没有读写权限的,可以增加读的权限,但需要进行设置。
设置读操作权限:
说明:
设置为奴隶节点,允许在从成员上运行读的操作
语法:
rs.slaveOk()
#或
rs.slaveOk(true)
提示:
该命令是 db.getMongo().setSlaveOk() 的简化命令。
【示例】
27018 上设置作为奴隶节点权限,具备读权限:
rs:SECONDARY> rs.slaveOk()
此时,在执行查询命令,运行成功!
但仍然不允许插入。
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host 192.168.2.4 --port 27018
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.2.4:27018/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("5b58b846-923c-45e9-ab19-0898ad67e605") }
MongoDB server version: 7.0.4
WARNING: shell and server versions do not match
Server has startup warnings: 
{"t":{"$date":"2023-12-25T18:32:34.032+08:00"},1)
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:139:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
myrs:SECONDARY> rs.slaveOk()
myrs:SECONDARY> show dbs;
admin      0.000GB
articledb  0.000GB
config     0.000GB
local      0.000GB
myrs:SECONDARY> use articledb
switched to db articledb
myrs:SECONDARY> show collections
comment
myrs:SECONDARY> db.comment.find()
{ "_id" : ObjectId("658971ef4cf53b8b9ab5ff3d"),"createdatetime" : ISODate("2023-12-25T12:13:35.462Z") }
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({
	"topologyVersion" : {
		"processId" : ObjectId("65895a4170dd267d9b182983"),"errmsg" : "not master","code" : 10107,"codeName" : "NotWritablePrimary","$clusterTime" : {
		"clusterTime" : Timestamp(1703506706,"operationTime" : Timestamp(1703506706,1)
})
myrs:SECONDARY> 
现在可实现了读写分离,让主插入数据,让从来读取数据。
如果要取消作为奴隶节点的读权限:
myrs:SECONDARY> rs.slaveOk(false)
myrs:SECONDARY> db.comment.find()
Error: error: {
"operationTime" : Timestamp(1568084459,"codeName" : "NotMasterNoSlaveOk","$clusterTime" : {
"clusterTime" : Timestamp(1568084459,"signature" : {
"hash" : BinData(0,"keyId" : NumberLong(0)
}
}
}
仲裁者节点,不存放任何业务数据的,可以登录查看
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host 192.168.2.4  --port 27019
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.2.4:27019/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("435d2917-656b-4933-af4a-dfb49822147e") }
MongoDB server version: 7.0.4
WARNING: shell and server versions do not match
Server has startup warnings: 
{"t":{"$date":"2023-12-25T18:34:54.196+08:00"},"tags":["startupWarnings"]}

{"t":{"$date":"2023-12-25T18:34:54.196+08:00"},"tags":["startupWarnings"]}

> shod db
2023-12-25T20:24:32.918+0800 E QUERY    [js] SyntaxError: missing ; before statement @(shell):1:5
> db
test
> show dbs
2023-12-25T20:24:50.896+0800 E QUERY    [js] Error: listDatabases failed:{
	"topologyVersion" : {
		"processId" : ObjectId("65895acde7863fee76efb32b"),"counter" : NumberLong(0)
	},"codeName" : "NotPrimaryNoSecondaryOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:139:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
> use local
switched to db local
> db
local
> show collections
replset.election
replset.minvalid
replset.oplogTruncateAfterPoint
startup_log
system.rollback.id
system.tenantMigration.oplogView
system.views
> 
发现,只存放副本集配置等数据。

主节点的选举原则

MongoDB 在副本集中,会自动进行主节点的选举,主节点选举的触发条件:
  1. 1) 主节点故障
  2. 2) 主节点网络不可达(默认心跳信息为10秒)
  3. 3) 人工干预(rs.stepDown(600)
一旦触发选举,就要根据一定规则来选主节点。
选举规则是根据票数来决定谁获胜:
  • 票数最高,且获得了大多数成员的投票支持的节点获胜。 大多数的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 + 1。例如:3个投票成员,则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary复制集将无法提供写服务,处于只读状态。
  • 若票数相同,且都获得了大多数成员的投票支持的,数据新的节点获胜。 数据的新旧是通过操作日志oplog来对比的。
在获得票数的时候,优先级( priority )参数影响重大。
可以通过设置优先级( priority )来设置额外票数。优先级即权重,取值为 0-1000 ,相当于可额外增加0-1000的票数,优先级的值越大,就越可能获得多数成员的投票( votes )数。指定较高的值可使成员更有资格成为主要成员,更低的值可使成员更不符合条件。
默认情况下,优先级的值是 1
myrs:SECONDARY> rs.conf()
{
	"_id" : "myrs","version" : 3,"votes" : 1
		},"host" : "192.168.2.4:27018","replicaSetId" : ObjectId("65896ce53a4a40258a007293")
	}
}
myrs:SECONDARY> 
可以看出,主节点和副本节点的优先级各为 1 ,即,默认可以认为都已经有了一票。但选举节点,优先级是0 ,(要注意是,官方说了,选举节点的优先级必须是 0 ,不能是别的值。即不具备选举权,但具有投票权)
【了解】修改优先级
比如,下面提升从节点的优先级:
1 )先将配置导入 cfg 变量
myrs:SECONDARY> cfg=rs.conf()
2 )然后修改值( ID 号默认从 0 开始):
myrs:SECONDARY> cfg.members[1].priority=2
2
3 )重新加载配置
myrs:SECONDARY> rs.reconfig(cfg)
{ "ok" : 1 }
稍等片刻会重新开始选举。

故障测试

副本节点故障测试

关闭 27018 副本节点:
发现,主节点和仲裁节点对 27018 的心跳失败。因为主节点还在,因此,没有触发投票选举。
如果此时,在主节点写入数据。
db.comment.insert({"_id":"1","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","state":"1"})
再启动从节点,会发现,主节点写入的数据,会自动同步给从节点。

主节点故障测试

关闭 27017 节点
发现,从节点和仲裁节点对 27017 的心跳失败,当失败超过 10 秒,此时因为没有主节点了,会自动发起投票。
而副本节点只有 27018 ,因此,候选人只有一个就是 27018 ,开始投票。
27019 27018 投了一票, 27018 本身自带一票,因此共两票,超过了 大多数
27019 是仲裁节点,没有选举权, 27018 不向其投票,其票数是 0.
最终结果, 27018 成为主节点。具备读写功能。
27018 写入数据查看。
db.comment.insert({"_id":"2","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"})
再启动 27017 节点,发现 27017 变成了从节点, 27018 仍保持主节点。
登录 27017 节点,发现是从节点了,数据自动从 27018 同步。
从而实现了高可用。

仲裁节点和主节点故障

先关掉仲裁节点 27019
关掉现在的主节点 27018
登录 27017 后,发现, 27017 仍然是从节点,副本集中没有主节点了,导致此时,副本集是只读状态, 无法写入。
为啥不选举了?因为 27017 的票数,没有获得大多数,即没有大于等于 2 ,它只有默认的一票(优先级是1
如果要触发选举,随便加入一个成员即可。
  • 如果只加入27019仲裁节点成员,则主节点一定是27017,因为没得选了,仲裁节点不参与选举,但参与投票。(不演示)
  • 如果只加入27018节点,会发起选举。因为2701727018都是两票,则按照谁数据新,谁当主节点。

仲裁节点和从节点故障

先关掉仲裁节点 27019
关掉现在的副本节点 27018
10 秒后, 27017 主节点自动降级为副本节点。(服务降级)
副本集不可写数据了,已经故障了。

Compass连接副本集

如果使用云服务器需要修改配置中的主节点ip

var config = rs.config();
config.members[0].host="192.168.2.4:27017";
rs.reconfig(config)
compass 连接:

SpringDataMongoDB连接副本集 

副本集语法:
mongodb://host1,host2,host3/articledb?
connect=replicaSet&slaveOk=true&replicaSet=副本集名字
其中:
  • slaveOk=true:开启副本节点读的功能,可实现读写分离。
  • connect=replicaSet:自动到副本集中选择读写的主机。如果slaveOK是打开的,则实现了读写分
【示例】
连接 replica set 三台服务器 ( 端口 27017,27018, 27019) ,直接连接第一个服务器,无论是 replicaset一部分或者主服务器或者从服务器,写入操作应用在主服务器 并且分布查询到从服务器。修改配置文件application.yml
spring:
    #数据源配置
    data:
        mongodb:
        # 主机地址
        # host: 192.168.2.4
        # 数据库
        # database: articledb
        # 默认端口是27017
        # port: 27017
        #也可以使用uri连接
        #uri: mongodb://192.168.40.134:27017/articledb
        # 副本集的连接字符串
          uri:mongodb://192.168.2.4:27017,192.168.2.4:27018,192.168.2.4:27019/article
db?connect=replicaSet&slaveOk=true&replicaSet=myrs
注意:
主机必须是副本集中所有的主机,包括主节点、副本节点、仲裁节点。
SpringDataMongoDB 自动实现了读写分离:
写操作时,只打开主节点连接:
2019-09-02 12:16:27.143 INFO 13336 --- [ main]
org.mongodb.driver.connection : Opened connection
[connectionId{localValue:4,serverValue:60}] to 180.76.159.126:27017
2019-09-02 12:16:27.376 INFO 13336 --- [ main]
c.i.article.service.CommentServiceTest : Started CommentServiceTest in 5.249
seconds (JVM running for 6.16)
2019-09-02 12:16:27.610 INFO 13336 --- [ Thread-2]
org.mongodb.driver.connection : Closed connection
[connectionId{localValue:4,serverValue:60}] to 180.76.159.126:27017 because the
pool has been closed.
读操作是,同时打开主节点和从节点连接,但使用从节点获取数据:
2019-09-02 12:18:20.254 INFO 4168 --- [ main]
org.mongodb.driver.connection : Opened connection
[connectionId{localValue:4,serverValue:62}] to 180.76.159.126:27017
2019-09-02 12:18:20.504 INFO 4168 --- [ main]
c.i.article.service.CommentServiceTest : Started CommentServiceTest in 5.111
seconds (JVM running for 5.95)
2019-09-02 12:18:20.694 INFO 4168 --- [ main]
org.mongodb.driver.connection : Opened connection
[connectionId{localValue:5,serverValue:39}] to 180.76.159.126:27018
[Comment{id='5d64930fd1c1dc4ccf71eeac',content='今天天气真好,阳光明媚',publishtime=null,userid='1001',nickname='Rose',createdatetime=2019-08-
27T10:18:55.768,likenum=null,replynum=null,state='null',parentid='null',articleid='100000'},Comment{id='1',content='我们不应该把清晨浪费在手机上,健康很重
要,一杯温水幸福你我他。',userid='1002',nickname='相忘于江湖',createdatetime=2019-08-06T06:08:15.522,likenum=1000,state='1',articleid='100001'},Comment{id='2',content='我夏天空腹喝凉开水,
冬天喝温开水',userid='1005',nickname='伊人憔悴',createdatetime=2019-08-06T07:58:51.485,likenum=888,Comment{id='5d6c93a866ecc73210d7d600',content='测试添加的数据2',userid='1003',nickname='凯撒大帝',createdatetime=2019-09-02T11:59:36.525,likenum=0,replynum=0,articleid='100000'}]
2019-09-02 12:18:20.740 INFO 4168 --- [ Thread-2]
org.mongodb.driver.connection : Closed connection
[connectionId{localValue:4,serverValue:62}] to 180.76.159.126:27017 because the
pool has been closed.
2019-09-02 12:18:20.740 INFO 4168 --- [ Thread-2]
org.mongodb.driver.connection : Closed connection
[connectionId{localValue:5,serverValue:39}] to 180.76.159.126:27018 because the
pool has been closed.
完整的连接字符串的参考(了解):
MongoDB 客户端连接语法:
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]]
[/[database][?options]]
  • mongodb:// 这是固定的格式,必须要指定。
  • username:password@ 可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登陆这个数据库
  • host1 必须的指定至少一个host,host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。
  • portX 可选的指定端口,如果不填,默认为27017
  • /database 如果指定username:password@,连接并验证登陆指定数据库。若不指定,默认打开
  • test 数据库。
  • ?options 是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过&;(分号)隔开

标准的连接格式包含了多个选项(options),如下所示:

选项
描述
replicaSet=name
验证 replica set 的名称。 Impliesconnect=replicaSet.
slaveOk=true|false
true: connect=direct 模式下,驱动会连接第一台机器,即使这台服务器不是主。在connect=replicaSet 模式下,驱动会发送所有的写请求到主并且把读取操作分布在其他从服务器。false: 在connect=direct模式下,驱动会自动找寻主服务器 . 在connect=replicaSet 模式下,驱动仅仅连接主服务器,并且所有的读写命令都连接到主服务器。
safe=true|false
true: 在执行更新操作之后,驱动都会发送 getLastError 命令来确保更新成功。( 还要参考 wtimeoutMS).false: 在每次更新之后,驱动不会发送getLastError 来确保更新成功。
w=n
驱动添加 { w : n } getLastError 命令 . 应用于 safe=true
wtimeoutMS=ms
驱动添加 { wtimeout : ms } getlasterror 命令 . 应用于 safe=true.
fsync=true|false
true: 驱动添加 { fsync : true } getlasterror 命令 . 应用于
safe=true.false: 驱动不会添加到 getLastError 命令中。
journal=true|false
如果设置为 true, 同步到 journal ( 在提交到数据库前写入到实体中 ). 应用于 safe=true
connectTimeoutMS=ms
可以打开连接的时间。
socketTimeoutMS=ms
发送和接受 sockets 的时间。

原文地址:https://blog.csdn.net/qq_63431773/article/details/135197710

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读552次。com.mongodb.MongoQueryException: Query failed with error code 292 and error message 'Executor error during find command :: caused by :: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting.' on server 11.51.141.63:27017 _mongodb 大文件 下载失败
文章浏览阅读635次,点赞9次,收藏8次。MongoDB 是一种 NoSQL 数据库,它将每个数据存储为一个文档,这里的文档类似于 JSON/BSON 对象,具体数据结构由键值(key/value)对组成。
文章浏览阅读2.1k次。和。_mongodb 日期类型
文章浏览阅读1.7k次。Scalestack等客户期待使用MongoDB Atlas Vector Search和Amazon Bedrock构建下一代应用程序
文章浏览阅读970次。SpringBoot整合中间件mongodb、ES_springboot3 elasticsearch json数据
文章浏览阅读673次。MongoDB 简介_尚医通sql
文章浏览阅读1k次,点赞8次,收藏9次。官网下载MongoDB安装包后进行解压(因了解并不深入,故暂不进行详细说明,自行查找其他安装方法,后期了解深入后将进行该教程的完善)在bin目录下使用命令启动:./mongod --config …/mongodb.conf。该文章任然处于完善中,如果存在错误遗漏的地方,欢迎私信联系。安装相关的nuget包后即可通过以下方法连接数据。YX9010_0@的第二十篇文章。
文章浏览阅读1.2k次,点赞17次,收藏26次。社交场景, 使用 MongoDB 存储存储用户信息, 以及用户发表的朋友圈信息, 通过地理位置索引实现附近的人, 地点等功能.游戏场景, 使用 MongoDB 存储游戏用户信息, 用户的装备, 积分等直接以内嵌文档的形式存储, 方便查询, 高效率存储和访问.物流场景, 使用 MongoDB 存储订单信息, 订单状态在运送过程中会不断更新, 以 MongoDB 内嵌数组的形式来存储, 一次查询就能将订单所有的变更读取出来.物联网场景, 使用 MongoDB 存储所有接入的智能设备信息, 以及设备汇报的日
文章浏览阅读686次。您可以使用 update_one() 方法来更新 MongoDB 中调用的记录或文档。update_one() 方法的第一个参数是 query 对象,用于定义要更新的文档。注释:如果查询找到多个记录,则仅更新第一个匹配项。第二个参数是定义文档新值的对象。_python 更新 mongodb 数据
文章浏览阅读1.3k次。首先来学习一下nosql这里安装就不进行介绍 只记录一下让自己了解mongodb。_nosql注入
文章浏览阅读4.1k次,点赞8次,收藏7次。在data的目录下,创建一个db文件。因为启动MongoDB服务之前必须创建数据库文件的存放文件夹,否则命令不会自动创建,而且不能启动成功。第一步:安装时,Custom是指可以自定义安装路径,然后傻瓜式安装即可(注意:先不要安装图形化工具,否则安装时间会特别长):如果要想连接成功,必须要开服务,即mongod -dbpath C:MongoDBdatadb的cmd要一直开着。然后回车,ctrl+F输入port找到端口号,一般为:27017。打开命令行,然后找到bin文件地址,并输入。_mongodb windows安装
文章浏览阅读5.1k次,点赞3次,收藏43次。详细介绍MongoDB数据库的基本知识,安装方法,基本操作,_mongodb数据库
文章浏览阅读3.2k次。安装教程翻看以往文章。_navicat 连接mongodb
文章浏览阅读426次,点赞9次,收藏12次。win10开放端口:https://blog.csdn.net/m0_43605481/article/details/119255256。我的是阿里云服务器,所以直接在安全组中加入规则,端口范围:27017,授权对象:0.0.0.0。windows在mongodb安装文件夹的bin文件夹中的mongod.cfg。数据库名字是test,打算创建一个用户,账号aaa,密码bbb,权限readWrite。因为该用户是创建在test数据库的,所以在最后要加上test。O了,然后恢复了test的数据。
文章浏览阅读1.1k次。聚合操作主要用于处理数据并返回计算结果。聚合操作将来自多个文档的值组合在一起,按条件分组后,再进行一系列操作(如求和、平均值、最大值、最小值)以返回单个结果。MongoDB的聚合查询​聚合是MongoDB的高级查询语言,它允许我们通过转化合并由多个文档的数据来生成新的在单个文档里不存在的文档信息。MongoDB中聚合(aggregate)主要用于处理数据(例如分组统计平均值、求和、最大值等),并返回计算后的数据结果,有点类似sql语句中的count(*)、groupby。..._如何将几个db的数据统整在一起做查询
文章浏览阅读680次,点赞7次,收藏8次。(2)application.properties配置文件。(4)UserService类。(5)测试和测试结果。
文章浏览阅读1k次,点赞17次,收藏25次。Studio 3T 2023.9 (macOS, Linux, Windows) - MongoDB 的专业 GUI、IDE 和 客户端,支持自然语言查询_mongodb客户端
文章浏览阅读1.1k次,点赞32次,收藏27次。插件式的存储引擎架构可以实现 Server 层和存储引擎层的解耦,可以支持多种存储引擎,如 MySQL 既可以支持 B-Tree 结构的 InnoDB 存储引擎,还可以支持 LSM 结构的 RocksDB 存储引擎。MongoDB 中的记录就是一个 BSON 文档,它是由键值对组成的数据结构,类似于 JSON 对象,是 MongoDB 中的基本数据单元。的简称,是 JSON 文档的二进制表示,支持将文档和数组嵌入到其他文档和数组中,还包含允许表示不属于 JSON 规范的数据类型的扩展。
文章浏览阅读5.1k次,点赞6次,收藏96次。本文设计了一种基于智能室内温度控制的自动调速风扇。以STM32系列单片机为核心主控板,通过程序代码驱动和使用温度传感器模块实现对环境温度的实时监测,并可以实时显示环境温度。同时,可以设置温度检测的上下警告值,根据需求自行调节。_stm32 温控风扇
文章浏览阅读898次,点赞13次,收藏21次。在MongoDB中,我们使用find()和find_one()方法来在集合中查找数据,就像在MySQL数据库中使用SELECT语句来在表中查找数据一样。_pymongo find_one