MongoDB复制集

什么是MongoDB复制集?

复制集是由一组拥有相同数据集的mongodb实例所组成的集群,在多台服务器之间同步数据,(差不多跟MySQL的主从复制一个概念)

复制集的优点:

  • 数据安全性更高,灾难恢复
  • 数据可用性大,无需停机维护(比如备份、索引重建、故障转移)
  • 读缩放(额外的副本读取),副本集对应用程序是透明的

MongoDB的复制集由多个节点构成(至少两个节点),其中一个是主节点,负责处理客户端的请求,其余的都是从节点,负责复制主节点上的数据
MongoDB一般由一主一从或者一主多从的方式搭配,主节点记录所有操作到oplog上,从节点再定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,保证和主节点的数据保持一致

复制集的选举原理(如下图)
mongo.001
节点类型分为三种:
标准节点(host):存储数据,可能被选为活跃(primary)节点,有选举权
被动节点(passive):被动节点有完整副本,不可能成为活跃节点,有选举权
仲裁节点(arbiter):负责选举,不存储数据,不能充当主从节点

选举的规则:
1.只有标准节点才会被选举为活跃节点(passive),有选举权,被动节点有完整副本,但是不能被选举为活跃节点,有选举权,仲裁节点不会复制数据,不可能被选举成为活跃节点,只有选举权
2.标准节点和被动节点的区别:priority的值高的是标准节点,低的是被动节点
3.选举最后得票高的人获胜,priority的优先权为0~1000之间,相当于额外增加这么多票

TOC

一、MongoDB复制集搭建

★准备工作★

一共需要3台服务器
Primary:192.168.31.101
Secondary1:192.168.31.102
Secondary2:192.168.31.103

安装包:mongodb-linux-x86_64-rhel70-4.0.28.tgz

三台服务器安装mongodb

1.三台服务器安装mongodb

yum -y install openssl-devel
tar zxf mongodb-linux-x86_64-rhel70-4.0.28.tgz
mv mongodb-linux-x86_64-rhel70-4.0.28 /mongodb
mkdir -p /mongodb/{data,logs,run,conf}
touch /mongodb/logs/mongo.log

2.配置三台mongodb服务配置文件并启动服务
Primary(192.168.31.101)、Secondary1(192.168.31.102)、Secondary2(192.168.31.103):
replSet参数指定集群名字

vim /mongodb/conf/mongo.conf
---------------------------------
port=27017
bind_ip=0.0.0.0
dbpath=/mongodb/data
logpath=/mongodb/logs/mongo.log
logappend=true
pidfilepath=/mongodb/run/mongo.pid
fork=true
maxConns=5000
storageEngine=wiredTiger
replSet=kgcrs

三台mongodb启动服务

/mongodb/bin/mongod -f /mongodb/conf/mongo.conf

验证启动是否成功:

netstat -anptu |grep mongo
ps -aux |grep mongod |grep -v grep

配置复制集

创建和查看集群

> cfg={"_id":"kgcrs","members":[{"_id":0,"host":"192.168.31.101:27017"},{"_id":1,"host":"192.168.31.102:27017"},{"_id":2,"host":"192.168.31.103:27017"}]}
{
	"_id" : "kgcrs",
	"members" : [
		{
			"_id" : 0,
			"host" : "192.168.31.101:27017"
		},
		{
			"_id" : 1,
			"host" : "192.168.31.102:27017"
		},
		{
			"_id" : 2,
			"host" : "192.168.31.103:27017"
		}
	]
}
> rs.initiate(cfg)
{ "ok" : 1 }
kgcrs:OTHER> 
kgcrs:PRIMARY>

查看选举状态

kgcrs:PRIMARY> rs.isMaster()
{
	"hosts" : [
		"192.168.31.101:27017",
		"192.168.31.102:27017",
		"192.168.31.103:27017"
	],
	"setName" : "kgcrs",
	"setVersion" : 1,
	"ismaster" : true,
	"secondary" : false,
	"primary" : "192.168.31.101:27017",
	"me" : "192.168.31.101:27017",
	"electionId" : ObjectId("7fffffff0000000000000001"),
	"lastWrite" : {
		"opTime" : {
			"ts" : Timestamp(1658147299, 1),
			"t" : NumberLong(1)
		},
		"lastWriteDate" : ISODate("2022-07-18T12:28:19Z"),
		"majorityOpTime" : {
			"ts" : Timestamp(1658147299, 1),
			"t" : NumberLong(1)
		},
		"majorityWriteDate" : ISODate("2022-07-18T12:28:19Z")
	},
	"maxBsonObjectSize" : 16777216,
	"maxMessageSizeBytes" : 48000000,
	"maxWriteBatchSize" : 100000,
	"localTime" : ISODate("2022-07-18T12:28:22.200Z"),
	"logicalSessionTimeoutMinutes" : 30,
	"minWireVersion" : 0,
	"maxWireVersion" : 7,
	"readOnly" : false,
	"ok" : 1,
	"operationTime" : Timestamp(1658147299, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1658147299, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

查看复制集状态信息

kgcrs:PRIMARY> rs.status()
{
	"set" : "kgcrs",
	"date" : ISODate("2022-07-18T12:30:01.753Z"),
	"myState" : 1,
	"term" : NumberLong(1),
	"syncingTo" : "",
	"syncSourceHost" : "",
	"syncSourceId" : -1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1658147399, 1),
			"t" : NumberLong(1)
		},
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1658147399, 1),
			"t" : NumberLong(1)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1658147399, 1),
			"t" : NumberLong(1)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1658147399, 1),
			"t" : NumberLong(1)
		}
	},
	"lastStableCheckpointTimestamp" : Timestamp(1658147389, 1),
	"electionCandidateMetrics" : {
		"lastElectionReason" : "electionTimeout",
		"lastElectionDate" : ISODate("2022-07-18T12:25:49.103Z"),
		"electionTerm" : NumberLong(1),
		"lastCommittedOpTimeAtElection" : {
			"ts" : Timestamp(0, 0),
			"t" : NumberLong(-1)
		},
		"lastSeenOpTimeAtElection" : {
			"ts" : Timestamp(1658147137, 1),
			"t" : NumberLong(-1)
		},
		"numVotesNeeded" : 2,
		"priorityAtElection" : 1,
		"electionTimeoutMillis" : NumberLong(10000),
		"numCatchUpOps" : NumberLong(0),
		"newTermStartDate" : ISODate("2022-07-18T12:25:49.109Z"),
		"wMajorityWriteAvailabilityDate" : ISODate("2022-07-18T12:25:50.049Z")
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "192.168.31.101:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 1896,
			"optime" : {
				"ts" : Timestamp(1658147399, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2022-07-18T12:29:59Z"),
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1658147149, 1),
			"electionDate" : ISODate("2022-07-18T12:25:49Z"),
			"configVersion" : 1,
			"self" : true,
			"lastHeartbeatMessage" : ""
		},
		{
			"_id" : 1,
			"name" : "192.168.31.102:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 263,
			"optime" : {
				"ts" : Timestamp(1658147399, 1),
				"t" : NumberLong(1)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1658147399, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2022-07-18T12:29:59Z"),
			"optimeDurableDate" : ISODate("2022-07-18T12:29:59Z"),
			"lastHeartbeat" : ISODate("2022-07-18T12:30:01.474Z"),
			"lastHeartbeatRecv" : ISODate("2022-07-18T12:30:00.497Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "192.168.31.101:27017",
			"syncSourceHost" : "192.168.31.101:27017",
			"syncSourceId" : 0,
			"infoMessage" : "",
			"configVersion" : 1
		},
		{
			"_id" : 2,
			"name" : "192.168.31.103:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 263,
			"optime" : {
				"ts" : Timestamp(1658147399, 1),
				"t" : NumberLong(1)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1658147399, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2022-07-18T12:29:59Z"),
			"optimeDurableDate" : ISODate("2022-07-18T12:29:59Z"),
			"lastHeartbeat" : ISODate("2022-07-18T12:30:01.474Z"),
			"lastHeartbeatRecv" : ISODate("2022-07-18T12:30:00.470Z"),
			"pingMs" : NumberLong(1),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "192.168.31.101:27017",
			"syncSourceHost" : "192.168.31.101:27017",
			"syncSourceId" : 0,
			"infoMessage" : "",
			"configVersion" : 1
		}
	],
	"ok" : 1,
	"operationTime" : Timestamp(1658147399, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1658147399, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

“stateStr” : "PRIMARY"表示该id服务器为主服务器,“stateStr” : "SECONDARY"表示该id的服务器为从服务器
health为1代表健康,0代表宕机,state为1代表主节点,为2代表从节点

添加和删除节点

添加节点

kgcrs:PRIMARY> rs.add("192.168.31.104:27017")
{ "ok" : 1 }

删除节点

kgcrs:PRIMARY> rs.remove("192.168.31.104:27017")
{ "ok" : 1 }

故障测试

停止Primary(192.168.31.101)的mongodb服务,登录mongodb查看群集状态(如下所示)

kgcrs:PRIMARY> rs.status()
{
	"set" : "kgcrs",
	"date" : ISODate("2022-07-18T12:42:40.784Z"),
	"myState" : 1,
	"term" : NumberLong(2),
	"syncingTo" : "",
	"syncSourceHost" : "",
	"syncSourceId" : -1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1658148153, 1),
			"t" : NumberLong(2)
		},
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1658148153, 1),
			"t" : NumberLong(2)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1658148153, 1),
			"t" : NumberLong(2)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1658148153, 1),
			"t" : NumberLong(2)
		}
	},
	"lastStableCheckpointTimestamp" : Timestamp(1658148109, 1),
	"electionCandidateMetrics" : {
		"lastElectionReason" : "stepUpRequestSkipDryRun",
		"lastElectionDate" : ISODate("2022-07-18T12:41:53.324Z"),
		"electionTerm" : NumberLong(2),
		"lastCommittedOpTimeAtElection" : {
			"ts" : Timestamp(1658148109, 1),
			"t" : NumberLong(1)
		},
		"lastSeenOpTimeAtElection" : {
			"ts" : Timestamp(1658148109, 1),
			"t" : NumberLong(1)
		},
		"numVotesNeeded" : 2,
		"priorityAtElection" : 1,
		"electionTimeoutMillis" : NumberLong(10000),
		"priorPrimaryMemberId" : 0,
		"numCatchUpOps" : NumberLong(0),
		"newTermStartDate" : ISODate("2022-07-18T12:41:53.331Z"),
		"wMajorityWriteAvailabilityDate" : ISODate("2022-07-18T12:41:54.378Z")
	},
	"electionParticipantMetrics" : {
		"votedForCandidate" : true,
		"electionTerm" : NumberLong(1),
		"lastVoteDate" : ISODate("2022-07-18T12:25:49.101Z"),
		"electionCandidateMemberId" : 0,
		"voteReason" : "",
		"lastAppliedOpTimeAtElection" : {
			"ts" : Timestamp(1658147137, 1),
			"t" : NumberLong(-1)
		},
		"maxAppliedOpTimeInSet" : {
			"ts" : Timestamp(1658147137, 1),
			"t" : NumberLong(-1)
		},
		"priorityAtElection" : 1
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "192.168.31.101:27017",
			"health" : 0,
			"state" : 8,
			"stateStr" : "(not reachable/healthy)",
			"uptime" : 0,
			"optime" : {
				"ts" : Timestamp(0, 0),
				"t" : NumberLong(-1)
			},
			"optimeDurable" : {
				"ts" : Timestamp(0, 0),
				"t" : NumberLong(-1)
			},
			"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
			"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
			"lastHeartbeat" : ISODate("2022-07-18T12:42:39.421Z"),
			"lastHeartbeatRecv" : ISODate("2022-07-18T12:41:52.548Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "Error connecting to 192.168.31.101:27017 :: caused by :: Connection refused",
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"configVersion" : -1
		},
		{
			"_id" : 1,
			"name" : "192.168.31.102:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 1034,
			"optime" : {
				"ts" : Timestamp(1658148153, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2022-07-18T12:42:33Z"),
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1658148113, 1),
			"electionDate" : ISODate("2022-07-18T12:41:53Z"),
			"configVersion" : 1,
			"self" : true,
			"lastHeartbeatMessage" : ""
		},
		{
			"_id" : 2,
			"name" : "192.168.31.103:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 1020,
			"optime" : {
				"ts" : Timestamp(1658148153, 1),
				"t" : NumberLong(2)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1658148153, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2022-07-18T12:42:33Z"),
			"optimeDurableDate" : ISODate("2022-07-18T12:42:33Z"),
			"lastHeartbeat" : ISODate("2022-07-18T12:42:39.400Z"),
			"lastHeartbeatRecv" : ISODate("2022-07-18T12:42:39.697Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "192.168.31.102:27017",
			"syncSourceHost" : "192.168.31.102:27017",
			"syncSourceId" : 1,
			"infoMessage" : "",
			"configVersion" : 1
		}
	],
	"ok" : 1,
	"operationTime" : Timestamp(1658148153, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1658148153, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

发现192.168.31.102:27017变成了主节点PRIMARY则说明成功!!!

二、复制集的认证

认证方式:
通过配置auth参数来开启权限认证,但这种认证方式只适合单机节点,当我们使用复制集时应该怎么开启权限认证来保证复制集的

单点认证

vim /mongodb/conf/mongo.conf
---------------------------------------------
auth=true

群集keyFile认证

1.修改配置文件

vim /usr/local/mongodb/bin/mongodb1.conf
----------------------------------------
clusterAuthMode=keyFile
keyFile=/mongodb/run/mongo-keyfile

2.创建kgcrskey文件加入内容

touch /mongodb/run/mongo-keyfile

3.配置keyFile文件再给权限
文件中的具体内容其实就是一行字符串,但复制集对keyFile文件有所要求
内容:以base64编码集中中的字符进行编写,即字符串只能包含a-z、A-Z、+、/
长度不能超过1000字节
权限最多到600 ,权限至少 chmod 600 keyFile

openssl rand -base64 102 > /mongodb/run/mongo-keyfile
chmod 600 /mongodb/run/mongo-keyfile

注意:每个节点都要进行该操作