Skip to content

复制集

如果所有的数据都存在一台MongoDB服务器,会存在什么问题?

  1. 不具备高可用性,一旦这台MongoDB服务器宕机了,那么用户就无法继续使用了
  2. 不具备数据安全性,一旦MongoDB服务器坏掉了,那么用户的数据丢失了
  3. 不能对数据进行分流,不能采用就近的原则进行访问

如何解决上述的问题?

在MongoDB中提供了一个叫做复制集的东西,我们可以通过复制集来解决上述问题

什么是复制集?

复制集就是将多台保存了相同内容的MongoDB服务器组成一个集群,我们就称为复制集

什么是复制集的节点?

在复制集中每台MongoDB服务器都是一个节点

特点

  1. 在一个复制集中最多只能有50个节点

  2. 在复制集中必须有一个主节点

    • 什么是主节点 在复制集中,只有一个节点可以同时读写数据,那么这个节点我们称之为主节点
  3. 在复制集中除了主节点以外的节点,我们都称之为副节点

    • 什么是副节点 在复制集中副节点只能读取数据,不能写入数据,那么这个节点我们称之为副节点
  4. 在复制集中,节点之间,每隔两秒就会相互发送心跳请求 为了相互检查有没有节点出现了问题,如果某一个节点10秒还没有响应其他节点的请求,那么就会视为这个节点出现了问题

  5. 如果主节点出现了问题(宕机、坏掉),副节点就会自动发起投票,重新选举主节点 因为在复制集中只有主节点可以写入数据,那么主节点挂了,就以为着不能写入数据了, 所以需要重新从其他的副节点中选举出一个作为主节点,这样才能保证既能写入也能读取数据

复制集选举的规则

  1. 发起选举的前提条件

    • 副节点发送心跳请求给主节点10秒之后还没有收到响应,这个时候副节点 就会认为主节点已经挂掉了,就会重新发起选举请求
  2. 在复制集中每一个节点都有一个选举计数器

  3. 在复制集中发起选举的节点我们称之为候选节点

  4. 开始选举

    • 候选节点会先给自己的选举计数器+1
    • 候选节点会给所有的节点发起选举请求 并将自己的选举计数器的值一天同时发送过去
    • 其他节点接收到选举请求之后会先利用选举请求中计数器的值更新自己的值
    • 更新完计数器的值之后,会对比自己保存的数据和候选节点的数据,谁的数据比较完整 如果自己的数据比候选节点完整,那么会透出反对票 如果自己的数据没有候选节点的数据完整,那么就会投出同意票
    • 所有的节点优盘完成之后,如果超过半数同意 那么候选节点就自动变为主节点 如果投票完成之后同意票的票数没有超过半数 那么其他的副节点就会重新再次发起选举 直到有一个节点有超过半数的节点同意为止

    如果某些节点挂掉了,不能参与投票,那么默认就是反对票

注意点:

在复制集中参与投票的节点最多只能有7个,由于需要有超过半数的节点同意才能成为主节点 所以在创建复制集的时候,最少需要3个节点

原因:由于需要有超过半数的节点同意才能成为主节点,所以在复制集中我们一般会创建奇数个节点

  • 触发选举的其他条件
  1. 初始化复制集时,会自动触发选举

  2. 有新节点加入的时候,会自动选举

  3. 当前主节点挂掉的时候,会自动选举

复制集同步规则

在复制集中如何保证所有节点保存的数据都相同

  1. 初始化同步
  • 当有一个新的节点加入到复制集之后,就会自动进行初始化同步 初始化同步会将主节点中所有的数据库、集合、文档、索引都拷贝一份给新的节点
  1. 同步写库记录
  • 在每一个MongoDB服务器上都有一个local数据库,这个数据库中有一个oplog集合,这个集合中就保存了当前服务器所有的操作 执行完初始化同步之后,副节点会定期的同步写库记录,会定期执行写库记录

搭建复制集

  1. 下载地址:MongoDB下载地址

  2. 解压MongoDB安装包

  3. 在安装目录下新建data/conf/log文件夹

  4. 在conf文件夹下新创建mongod.conf,配置文件如下

storage:
    dbPath: /Users/zhuzhengjian/Desktop/huanjing/mongo1/data
    journal:
        enabled: true
systemLog:
    destination: file
    path: /Users/zhuzhengjian/Desktop/huanjing/mongo1/log/mongodb.log
    logAppend: true
net:
    port: 27018
    bindIp: 127.0.0.1
replication:
    replSetName: mongotest
  

其他电脑做相同的配置即可

  1. 启动多个mongod并使用当前文件夹下面的配置
shell

./mongod -f ../conf/mongod.conf

  1. 测试连接所有mongo数据库
mongo --host 127.0.0.1 --port 27018
mongo --host 127.0.0.1 --port 27019
mongo --host 127.0.0.1 --port 27020
  1. 在任何一个mongo复制集中启动mongoDB,配置复制集

rs.initiate({
 _id:'mongotest', 
members:[ 
{_id:0,host:'127.0.0.1:27018'}, 
{_id:1,host:'127.0.0.1:27019'}, 
{_id:2,host:'127.0.0.1:27020'}] 
})

  • 其他配置项说明
    1. _id 整数 节点的唯一标识。
    2. host 字符串 节点的IP地址,包含端口号。
    3. arbiterOnly 布尔值 是否为投票节点,默认是false。是设置投票(选举)节点有关的参数
    4. priority 整数 选举为主节点的权值,默认是1,范围0-1000。
    5. hidden 布尔值 是否隐藏,默认false,是设置隐藏节点有关的参数。
    6. votes 整数 投票数,默认为1,取值是0或1,是设置”投票“节点有关的参数。
    7. slaveDelay 整数 延时复制,是设置延时节点有关的参数。单位秒(s)
  1. 执行完成后查看当前复制集的状态
rs.status()

### 状态信息 ###
{
	"set" : "mongotest",
	"date" : ISODate("2020-08-22T05:10:03.213Z"),
	"myState" : 1,
	"term" : NumberLong(1),
	"syncSourceHost" : "",
	"syncSourceId" : -1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"majorityVoteCount" : 2,
	"writeMajorityCount" : 2,
	"votingMembersCount" : 3,
	"writableVotingMembersCount" : 3,
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1598073002, 1),
			"t" : NumberLong(1)
		},
		"lastCommittedWallTime" : ISODate("2020-08-22T05:10:02.079Z"),
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1598073002, 1),
			"t" : NumberLong(1)
		},
		"readConcernMajorityWallTime" : ISODate("2020-08-22T05:10:02.079Z"),
		"appliedOpTime" : {
			"ts" : Timestamp(1598073002, 1),
			"t" : NumberLong(1)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1598073002, 1),
			"t" : NumberLong(1)
		},
		"lastAppliedWallTime" : ISODate("2020-08-22T05:10:02.079Z"),
		"lastDurableWallTime" : ISODate("2020-08-22T05:10:02.079Z")
	},
	"lastStableRecoveryTimestamp" : Timestamp(1598072982, 1),
	"electionCandidateMetrics" : {
		"lastElectionReason" : "electionTimeout",
		"lastElectionDate" : ISODate("2020-08-22T05:09:41.971Z"),
		"electionTerm" : NumberLong(1),
		"lastCommittedOpTimeAtElection" : {
			"ts" : Timestamp(0, 0),
			"t" : NumberLong(-1)
		},
		"lastSeenOpTimeAtElection" : {
			"ts" : Timestamp(1598072970, 1),
			"t" : NumberLong(-1)
		},
		"numVotesNeeded" : 2,
		"priorityAtElection" : 1,
		"electionTimeoutMillis" : NumberLong(10000),
		"numCatchUpOps" : NumberLong(0),
		"newTermStartDate" : ISODate("2020-08-22T05:09:42.041Z"),
		"wMajorityWriteAvailabilityDate" : ISODate("2020-08-22T05:09:42.695Z")
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "127.0.0.1:27018",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 685,
			"optime" : {
				"ts" : Timestamp(1598073002, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2020-08-22T05:10:02Z"),
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1598072981, 1),
			"electionDate" : ISODate("2020-08-22T05:09:41Z"),
			"configVersion" : 1,
			"configTerm" : 1,
			"self" : true,
			"lastHeartbeatMessage" : ""
		},
		{
			"_id" : 1,
			"name" : "127.0.0.1:27019",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 32,
			"optime" : {
				"ts" : Timestamp(1598072982, 5),
				"t" : NumberLong(1)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1598072982, 5),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2020-08-22T05:09:42Z"),
			"optimeDurableDate" : ISODate("2020-08-22T05:09:42Z"),
			"lastHeartbeat" : ISODate("2020-08-22T05:10:02.029Z"),
			"lastHeartbeatRecv" : ISODate("2020-08-22T05:10:03.055Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncSourceHost" : "127.0.0.1:28018",
			"syncSourceId" : 0,
			"infoMessage" : "",
			"configVersion" : 1,
			"configTerm" : 1
		},
		{
			"_id" : 2,
			"name" : "127.0.0.1:27020",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 32,
			"optime" : {
				"ts" : Timestamp(1598072982, 5),
				"t" : NumberLong(1)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1598072982, 5),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2020-08-22T05:09:42Z"),
			"optimeDurableDate" : ISODate("2020-08-22T05:09:42Z"),
			"lastHeartbeat" : ISODate("2020-08-22T05:10:02.028Z"),
			"lastHeartbeatRecv" : ISODate("2020-08-22T05:10:03.055Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncSourceHost" : "127.0.0.1:28018",
			"syncSourceId" : 0,
			"infoMessage" : "",
			"configVersion" : 1,
			"configTerm" : 1
		}
	],
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1598073002, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1598073002, 1)
}
  1. 在副节点读取rs.slaveOk()

Released under the MIT License.