MongoDB 集群配置

news2024/11/25 10:27:26

一、副本集 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将写入其PID
  pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: 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将写入其PID
  pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: 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将写入其PID
  pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: 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 自动实现了读写分离。

        写操作时,只打开主节点连接;

        读操作时,同时打开主节点和从节点连接,但使用从节点获取数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1091571.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视觉里程计- 位姿

SLAM中的位姿概念对新手很难,这里讨论下。首先放出一张图,下文会反复说道这张图。 注意到位姿节点之间的变换并不是位姿,之前一直有误解;一般地有如下概念: 路标节点:也就是观测方程【数学形式下见】的观测…

运算放大器基本原理与参数解读-优先看

运算放大器基本原理与参数解读 运算放大器的出现,大大降低了硬件模拟前端电路设计的难度。但是对于高精度的模拟信号处理电路中,用好运放也不是一件容易的事,更不用说压着最低的物料成本设计出符合系统要求的运放电路了。高端的电路往往蕴含着…

第二证券:跨行转账为什么迟迟不到账?

现在,越来越多的人挑选使用跨行转账来结束日常资金生意。不过,有时候在进行跨行转账时,或许会出现迟迟不到账的状况。这种状况常常让人感到困惑和焦虑。所以,我们需求深入分析这个问题,找出原因,以便可以防…

光伏PV三相并网逆变器MATLAB/Simulink仿真分析

微❤关注“电击小子程高兴的MATLAB小屋”获得资料(专享优惠) 光伏PV三相并网逆变器Matlab/Simulink仿真 光伏PV三相并网逆变器MATLABf仿真下载 引言: 随着可再生能源的日益重视和发展,光伏发电系统在电力系统中的地位越来越重…

C/C++笔试易错题+图解知识点(二)—— C++部分(持续跟新中)

目录 1.构造函数初始化列表 1.1 构造函数初始化列表与函数体内初始化区别 1.2 必须在初始化列表初始化的成员 2. 引用初始化以后不能被改变,指针可以改变所指的对象 1.构造函数初始化列表 有一个类A,其数据成员如下: 则构造函数中&#xff0c…

vue项目打包,使用externals抽离公共的第三方库

封装了一个插件,用来vue打包抽离公共的第三方库,使用unplugin进行插件开发,vite对应的功能使用了vite-plugin-externals进行二次开发 github地址 npm地址 hfex-auto-externals-plugin 自动注入插件,使用 unplugin 和 html-webpack-plugin进…

01 | Spring Data JPA 初识

Spring Boot 和 Spring Data JPA 的 Demo演示 我们利用 JPA Spring Boot 简单做一个 RESTful API 接口,方便你来了解 Spring Data JPA 是干什么用的,具体步骤如下。 第一步:利用 IDEA 和 SpringBoot 2.3.3 快速创建一个案例项目。 点击“…

2.MySQL表的操作

个人主页:Lei宝啊 愿所有美好如期而遇 表的操作 (1)表的创建 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎; 存储引擎的不同会导致创建表的文件不同。 换个引擎。 t…

【C语言】结构体、位段、枚举、联合(共用体)

结构体 结构:一些值的集合,这些值称为成员变量。结构体的每个成员可以是不同类型的变量; 结构体声明:struct是结构体关键字,结构体声明不能省略struct; 匿名结构体:只能在声明结构体的时候声…

伦敦银单位转换很简单

伦敦银源自于英国伦敦的电子化的白银投资方式,高杠杆和高收益的它的基本属性,但有别于国内大家所熟悉的投资品种,伦敦银在交易过程中有很多不一样的地方,需要大家地去留意。 比如伦敦银的计价单位是盎司,而且具体来说…

【Qt上位机】打开本地表格文件并获取其中全部数据

前言 其实本文所实现的功能并非博主要实现的全部功能,只是全部功能中的一小部分,这里只是为了记录一下实现方法,防止后续忘记,仅供参考。 文章目录 一、实现效果二、UI设计三、程序设计3.1 选择本地表格文件3.2 获取表格总行列数3…

百度Echarts实现饼图,较官网示例更多项显示

本来是想直接使用官网示例修改几个地方就用起来,但是用户希望一眼就看到百分占比,但是官网示例没有使用lable的,找了半天都没找到,后来通过对比其他饼图发现lable这个项,再次记录一下 首先看效果图: 2. 代码…

国海证券:36氪(KRKR):新经济内容平台龙头,多元变现可期

来源:猛兽财经 作者:猛兽财经 猛兽财经获悉,国海证券今日发布了关于36氪的新经济内容平台龙头,多元变现可期研报。国海证券主要内容如下:1、新经济产业发展迅猛,36氪定位为以媒体为旗舰的新经济服务集团&a…

下载安装Ipa Guard

下载安装Ipa Guard 可以前往ipaguard工具官网下载,工具是免费下载,免费体验使用的。下载地址是https://www.ipaguard.com。 下载后解压工具便ok了,工具是绿色软件,无需其他安装流程。双击Ipa Guard.exe 启动ipaguard。 ipaguard…

【问题思考】如何通过参数式求出方向向量?(待深入本质)

问题 今天在做23李六第二套的时候看到了一道题: 答案里面说的直接再加一个yy和上面的两个方程就凑成了三个方程(x关于y的,y关于y的,z关于y的,最后每个方程都对y求导,再代入y1,就有了方向向量&…

Netapp数据恢复—Netapp存储误删除lun的数据恢复过程

Netapp存储数据恢复环境: 北京某公司一台netAPP存储,72块SAS硬盘划分了若干个lun。 Netapp存储故障: 工作人员误操作删除了12个lun。 Netapp存储数据恢复过程: 1、将故障存储中所有磁盘编号后取出,以只读方式做全盘镜…

C++入门指南:类和对象总结笔记(下)

C入门指南:类和对象总结笔记(下) 一、深度剖析构造函数1.1 构造函数体赋值1.2 初始化列表1.3 explicit关键字 二、static成员2.1 概念2.2 特性 三、友元3.1 友元函数3.2 友元类 四、 内部类4.1 概念4.2 特征 五、拷贝对象时的一些编译器优化六、深度剖析…

论文浅尝 | 深度神经网络的模型压缩

笔记整理:闵德海,东南大学硕士,研究方向为知识图谱 链接:https://arxiv.org/abs/1412.6550 动机 提高神经网络的深度通常可以提高网络性能,但它也使基于梯度的训练更加困难,因为更深的网络往往更加强的非线…

​人机交互中的反馈与前馈

人机交互中的反馈和前馈,是指在用户与机器进行交互的过程中,人机二者对输入的信息做出回应的方式。 反馈:反馈是从机器到人的信息传递过程,主要用于告知用户他们的操作或请求的结果。当用户执行某个操作时,机器通过适当…

nginx生成https 证书-基于docker-compose

申请的证书存放nginx的docker-compose.yml同一目录 [rootk8s-node1 nginx]# cat docker-compose.yml version: 2 services:nginx:container_name: nginximage: nginxrestart: alwaysvolumes:- "./default.conf:/etc/nginx/conf.d/default.conf"- "./nginx.conf…