目录

1·MongoDB 复制集概述 2·MongoDB 复制集部署 3·MongoDB 复制集管理(添加、移除等) 4·复制集的总结


MongoDB 复制集是什么?

之前的一片文章讲了 MongoDB 的安装和日常的操作,有兴趣的朋友可以看看 MongoDB 的安装和简单操作


1)什么是复制集?

复制集是额外的一种数据副本,是跨多个服务器同步数据的过程,通俗的说就是可以在不同的服务器上备份数据,专业点说就是冗灾处理。通过复制集可以对硬件和终端的服务进行恢复。


2)复制集的优势如下:

  1-让数据更加安全---(肯定啊,都是备份了,能不安全吗!)
  2-数据的高可用性---(可以全年无休,7*24小时×××)
  3-灾难恢复 ----(不用多说,既然是数据,能没有恢复吗)
  4-无停机维护---(比如说,备份、索引的重建等,MySQL 备份就需要锁定 表 、或者行,而它不会)
  5-读缩放----(额外的副本读取)
  6-它对应用程序是透明的

3)复制集工作原理是什么?

1·既然是一个功能性的东西,那么存在肯定有它的工作原理和过程。MongoDB 的复制集至少需要两个节点,是至少。其中一个是主节点 (Primary),这个主节点主要负责处理客户端的请求,其他的都是从节点 (Secondary),负责复制主节点上的数据。


2·那么我们常用的搭配方式有:一主一丛或一主多从,因为复制集的主从的选举原理是从节点不允许选举为当主节点,但是在实际的生产环境中,主服务器是不可能单点挂上去的,这样要是主服务器挂掉了,那就凉凉。


3·客户端主节点写入数据,在从节点读取数据,主节点与从节点进行数据交互保障数据的统一性。如果其中一个节点出现故障,其他节点马上会把业务接过来而无需停机操作。


4·下图是 MongoDB 复制集结构图



它的特点如下:

N个节点的群集 任何节点可作为主节点 所有写入都是在主节点,读取是在从节点,实现读写分离 自动故障转移 自动恢复


MongoDB 复制集部署

先介绍下环境:CenOS 7.4 上部署 部署前提:安装 MongoDB ,了解什么是实列、和创建多个实例 这里安装 MongoDB 就不再演示。我是直接 YUM 装的。 需要了解 MongoDB 安装 和 多实例的创建 请访问:MongoDB 的安装和命令 需要了解 MongoDB 与 MySQL 的区别 请访问:MySQL - mmm 高可用集群 需要了解 MySQL 的读写分离 请访问:MySQL 主从复制 + 读写分离


1)看多 MongoDB 的多实例创建的知道,创建实例前需要创建数据文件和日志文件存储路径。

[root@localhost ~]# mkdir -p /data/mongodb/mongodb{2,3,4} ----(创建3个数据文件,因为自己 yum 安装了一个,所以也算一个。)


[root@localhost ~]# mkdir -p /data/mongodb/logs ----(创建日志文件路径) [root@localhost ~]# cd /data/mongodb/logs/ [root@localhost logs]# touch mongodb{2,3,4}.log -----(创建日志文件夹) [root@localhost logs]# chmod 777 *.log -----(给最大的权限)


2)修改主配置文件 ---- (需要注意的地方用加粗方式显示)

[root@localhost ~]# vim /etc/mongod.conf ----(修改主配置文件) 修改内容如下: #network interfaces net:

** port: 27017 ----(默认端口号)** bindIp: 0.0.0.0 # Listen to local interface only, comment to listen on all interfaces. ------------(修改监听地址)

#security:

#operationProfiling:

replication: -----------------(这里需要去掉注释) ** replSetName: kgcrs ------------(在这里需要添加复制集的名字)**


3)配置多实列 2 ,并且修改数据存储路径和日志文件

[root@localhost ~]# cp -p /etc/mongod.conf /etc/mongod2.conf ----(把主配置文件复制一份)


[root@localhost ~]# vim /etc/mongod2.conf -----(修改实列的配置文件) 修改内容如下: ---(修改内容以加粗方式显示) systemLog: destination: file logAppend: true

** path: /data/mongodb/logs/mongod2.log ----(日志文件的位子,这里需要注意路径,不能写错,之前创建的位置也不能有错)**

#Where and how to store data. storage:

** dbPath: /data/mongodb/mongodb2 ----(数据存储路径,之前创建的路径必须一样)** journal: enabled: true #engine: #mmapv1: #wiredTiger:

#how the process runs processManagement: fork: true # fork and run in background pidFilePath: /var/run/mongodb/mongod.pid # location of pidfile timeZoneInfo: /usr/share/zoneinfo

#network interfaces net:

port: 27018 -----(端口号需要修改为不一样的,自己能记住就行。) bindIp: 0.0.0.0 # Listen to local interface only, comment to listen on all interfaces.

#security:

#operationProfiling:

replication: ** replSetName: kgcrs ——(复制集的名称都需要一致,名字可以自己修改)**


4)配置多实例 3、4 (和上一步都是一样,只是数据路径,和日志文件,还有端口号需要修改)

[root@localhost mongodb]# cp -p /etc/mongod2.conf /etc/mongod3.conf [root@localhost mongodb]# cp -p /etc/mongod2.conf /etc/mongod4.conf 这里就不再分别演示修改方式,会以一张图来说明:修改数据路径、日志文件、端口号


下图是多实例修改样本:


5)当配置文件都 OK 后,就可以把4个实例全部启动:

[root@localhost ~]# mongod -f /etc/mongod.conf ---(第一台实例,是自己用YUM 装的,可以看作一台实例。)


[root@localhost ~]# mongod -f /etc/mongod2.conf ----(第二台实例,需要注意,如果有报错,很大一部分原因都是配置文件有问题,仔细检查配置文件的路径等问题)


[root@localhost ~]# mongod -f /etc/mongod3.conf ----(第三台实例)


[root@localhost ~]# mongod -f /etc/mongod4.conf ----(第4台实例)


6)进入第一台实例,初始化复制集配置 ---(以上步骤只是创建实例,并不是复制集哦。)

[root@localhost ~]# mongo ---(因为第一台的端口默认是 27017,所以这里不用跟端口号,如果是其他实例就需要 加上 --port 27018)


cfg={"_id":"kgcrs","members":[{"_id":0,"host":"192.168.198.128:27017"},{"_id":1,"host":"192.168.198.128:27018"},{"_id":2,"host":"192.168.198.128:27019"}]}

这里需要说明此代码:这里包含了3个节点的复制集,格式不需要变,因为这里是实验环境,所以 IP 是相同的,在生产环境中,IP 地址是不一样的。这里只需要修改端口号就行,还有就是我们一共是4个实例,但是这里只有3个,还剩下一个是为之后演示添加节点。


rs.initiate(cfg) ----(重新加载一下复制集,之后会有如下图的解释)


kgcrs:PRIMARY> rs.status() -----(查看复制集状态)

"set" : "kgcrs",  ----(复制集名称)
"date" : ISODate("2018-09-16T04:29:54.105Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
	"lastCommittedOpTime" : {
		"ts" : Timestamp(1537072188, 1),
		"t" : NumberLong(1)
	},
	"readConcernMajorityOpTime" : {
		"ts" : Timestamp(1537072188, 1),
		"t" : NumberLong(1)
	},
	"appliedOpTime" : {
		"ts" : Timestamp(1537072188, 1),
		"t" : NumberLong(1)
	},
	"durableOpTime" : {
		"ts" : Timestamp(1537072188, 1),
		"t" : NumberLong(1)
	}
},
"members" : [
	{
		"_id" : 0, 
		"name" : "192.168.198.128:27017",    -----(节点详细信息)
		"health" : 1,  -----(健康值为 “1” 说明是在线状态。“0” 为宕机状态)
		"state" : 1,
		"stateStr" : "PRIMARY",  ------(主节点 PRIMARY)
		"uptime" : 848,
		"optime" : {
			"ts" : Timestamp(1537072188, 1),
			"t" : NumberLong(1)
		},
		"optimeDate" : ISODate("2018-09-16T04:29:48Z"),
		"syncingTo" : "",
		"syncSourceHost" : "",
		"syncSourceId" : -1,
		"infoMessage" : "could not find member to sync from",
		"electionTime" : Timestamp(1537072157, 1),
		"electionDate" : ISODate("2018-09-16T04:29:17Z"),
		"configVersion" : 1,
		"self" : true,
		"lastHeartbeatMessage" : ""
	},
	{
		"_id" : 1,
		"name" : "192.168.198.128:27018",------(第二台节点)
		"health" : 1,
		"state" : 2,
		"stateStr" : "SECONDARY",  -----(**从节点SECONDARY )**
		"uptime" : 47,
		"optime" : {
			"ts" : Timestamp(1537072188, 1),
			"t" : NumberLong(1)
		},
		"optimeDurable" : {
			"ts" : Timestamp(1537072188, 1),
			"t" : NumberLong(1)
		},
		"optimeDate" : ISODate("2018-09-16T04:29:48Z"),
		"optimeDurableDate" : ISODate("2018-09-16T04:29:48Z"),
		"lastHeartbeat" : ISODate("2018-09-16T04:29:53.346Z"),
		"lastHeartbeatRecv" : ISODate("2018-09-16T04:29:53.725Z"),
		"pingMs" : NumberLong(0),
		"lastHeartbeatMessage" : "",
		"syncingTo" : "192.168.198.128:27017",
		"syncSourceHost" : "192.168.198.128:27017",
		"syncSourceId" : 0,
		"infoMessage" : "",
		"configVersion" : 1
	},
	{
		"_id" : 2,
		"name" : "192.168.198.128:27019",------(第三台节点)
		"health" : 1,
		"state" : 2,
		"stateStr" : "SECONDARY", ------(从节点)
		"uptime" : 47,
		"optime" : {
			"ts" : Timestamp(1537072188, 1),
			"t" : NumberLong(1)
		},
		"optimeDurable" : {
			"ts" : Timestamp(1537072188, 1),
			"t" : NumberLong(1)
		},
		"optimeDate" : ISODate("2018-09-16T04:29:48Z"),
		"optimeDurableDate" : ISODate("2018-09-16T04:29:48Z"),
		"lastHeartbeat" : ISODate("2018-09-16T04:29:53.346Z"),
		"lastHeartbeatRecv" : ISODate("2018-09-16T04:29:53.725Z"),
		"pingMs" : NumberLong(0),
		"lastHeartbeatMessage" : "",
		"syncingTo" : "192.168.198.128:27017",
		"syncSourceHost" : "192.168.198.128:27017",
		"syncSourceId" : 0,
		"infoMessage" : "",
		"configVersion" : 1
	}
],
"ok" : 1,
"operationTime" : Timestamp(1537072188, 1),
"$clusterTime" : {
	"clusterTime" : Timestamp(1537072188, 1),
	"signature" : {
		"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
		"keyId" : NumberLong(0)
	}
}

}


7)到此复制集创建完毕,但是我们还有一台实例没有添加到复制集中,所以现在演示复制集的添加:

kgcrs:PRIMARY> rs.add("192.168.198.128:27020") ----(添加一台实列到复制集中)


{ ** "ok" : 1, ----(添加成功)** "operationTime" : Timestamp(1537072738, 2), "$clusterTime" : { "clusterTime" : Timestamp(1537072738, 2), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }


8)有添加,那么就有移除,下面会演示移除的命令:

kgcrs:PRIMARY> rs.remove("192.168.198.128:27020")


{ ** "ok" : 1, -----(移除成功)** "operationTime" : Timestamp(1537072949, 1), "$clusterTime" : { "clusterTime" : Timestamp(1537072949, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }


9)到这里实验成功,那么需要验证它的功能性,下面会模拟故障转移,在这里是看不出实验效果,只给方法。

[root@localhost ~]# ps aux | grep mongod ---(查看mongod的进程) root 40778 0.6 6.4 1581996 64908 ? Sl 12:15 0:12 mongod -f /etc/mongod.conf root 40822 0.6 6.1 1469704 61216 ? Sl 12:17 0:12 mongod -f /etc/mongod2.conf root 40884 0.7 5.9 1504232 59000 ? Sl 12:18 0:11 mongod -f /etc/mongod3.conf root 40912 0.5 5.3 1440660 53752 ? Sl 12:19 0:09 mongod -f /etc/mongod4.conf


** [root@localhost ~]# kill -9 40778** ----(把进程 kill 掉 ,因为细心的朋友可以看到,40778 现在是主节点,把它 kill 掉,就是为了看其他节点会不会自动切换为主节点)


10)进入第二台实列,查看复制集状态

[root@localhost ~]# mongo --port 27018 ----(进入第二台实例,这里需要跟上端口) kgcrs:SECONDARY> rs.status() ------(再次查看复制集状态)


{ "set" : "kgcrs", "date" : ISODate("2018-09-16T04:51:37.669Z"), "myState" : 2, "term" : NumberLong(2), "syncingTo" : "192.168.198.128:27019", "syncSourceHost" : "192.168.198.128:27019", "syncSourceId" : 2, "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1537073492, 1), "t" : NumberLong(2) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1537073492, 1), "t" : NumberLong(2) }, "appliedOpTime" : { "ts" : Timestamp(1537073492, 1), "t" : NumberLong(2) }, "durableOpTime" : { "ts" : Timestamp(1537073492, 1), "t" : NumberLong(2) } }, "members" : [ { "_id" : 0, "name" : "192.168.198.128:27017", ----(第一台节点) "health" : 0, ----(原来的健康值变为 “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("2018-09-16T04:51:36.332Z"), "lastHeartbeatRecv" : ISODate("2018-09-16T04:47:29.932Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "Connection refused", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : -1 }, { "_id" : 1, ----(第二台实例) "name" : "192.168.198.128:27018", "health" : 1, ----(健康值为 “1”) "state" : 2, "stateStr" : "SECONDARY", ----(节点状态是:从几从节点) "uptime" : 2060, "optime" : { "ts" : Timestamp(1537073492, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2018-09-16T04:51:32Z"), "syncingTo" : "192.168.198.128:27019", "syncSourceHost" : "192.168.198.128:27019", "syncSourceId" : 2, "infoMessage" : "", "configVersion" : 3, "self" : true, "lastHeartbeatMessage" : "" }, { ** "_id" : 2, -----(第三台节点)** "name" : "192.168.198.128:27019", ** "health" : 1, -----(健康值为 ‘1’)** "state" : 1, "stateStr" : "PRIMARY", -----(现在是第三台节点为主节点) "uptime" : 1349, "optime" : { "ts" : Timestamp(1537073492, 1), "t" : NumberLong(2) }, "optimeDurable" : { "ts" : Timestamp(1537073492, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2018-09-16T04:51:32Z"), "optimeDurableDate" : ISODate("2018-09-16T04:51:32Z"), "lastHeartbeat" : ISODate("2018-09-16T04:51:36.289Z"), "lastHeartbeatRecv" : ISODate("2018-09-16T04:51:37.431Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1537073261, 1), "electionDate" : ISODate("2018-09-16T04:47:41Z"), "configVersion" : 3 } ], "ok" : 1, "operationTime" : Timestamp(1537073492, 1), "$clusterTime" : { "clusterTime" : Timestamp(1537073492, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }


11)从以上数据可以看出,当主节点挂掉后,从节点会自动切换为主节点,但是又不是按照顺序来推荐谁当主节点,这里的推荐的原理,后面会讲到。当然,这里是自动切换主从,我们也可以手动进行切换

[root@localhost ~]# mongod -f /etc/mongod.conf ----(把上个步骤停止的实例启动起来,方便我们实验) [root@localhost ~]# mongo --port 27019 ----(进入主节点服务器,因为我们需要来进行手动切换主从。)


kgcrs:PRIMARY> rs.freeze(30) ----(暂停30秒不参加选举) kgcrs:PRIMARY> rs.stepDown(60,30) ----(让主节点交出位子,维持从节点状态不少于60秒,同时等待30秒使主节点和从节点日志同步) kgcrs:SECONDARY> rs.status() ----(再次查看复制集状态)


12)在从节点默认的情况下,我们是无法在从节点上读取数据的,只有执行以下命令:

kgcrs:SECONDARY> rs.slaveOk() ----(执行此命令才可以在从节点上读取数据,否则是不允许读取)


总结:

1·复制集信息要点说明:health 为 “1” 代表健康,“0” 代表宕机。state 为 “1” 代表主节点,为 “2” 代表从节点


2·在配置实例时需要特别注意修改的数据存储路径,日志存储位子,端口号的修改。


3·复制集最少需要两个节点,这里主节点复制处理客户端请求,从节点复制主节点上的数据


4·它可以实现群集的高可用,当故障时会自动切换,管理员也可以手动切换。


5·在复制集初始化配置时要保证从节点上没有数据。


6·在初始化完复制集参数后,需要通过命令 :rs.initate(cfg) 命令启动复制集。