目录
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 的多实例创建的知道,创建实例前需要创建数据文件和日志文件存储路径。
[[email protected] ~]# mkdir -p /data/mongodb/mongodb{2,3,4} ----(创建3个数据文件,因为自己 yum 安装了一个,所以也算一个。)
[[email protected] ~]# mkdir -p /data/mongodb/logs ----(创建日志文件路径)
[[email protected] ~]# cd /data/mongodb/logs/
[[email protected] logs]# touch mongodb{2,3,4}.log -----(创建日志文件夹)
[[email protected] logs]# chmod 777 *.log -----(给最大的权限)
2)修改主配置文件 ---- (需要注意的地方用加粗方式显示)
[[email protected] ~]# 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 ,并且修改数据存储路径和日志文件
[[email protected] ~]# cp -p /etc/mongod.conf /etc/mongod2.conf ----(把主配置文件复制一份)
[[email protected] ~]# 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 (和上一步都是一样,只是数据路径,和日志文件,还有端口号需要修改)
[[email protected] mongodb]# cp -p /etc/mongod2.conf /etc/mongod3.conf
[[email protected] mongodb]# cp -p /etc/mongod2.conf /etc/mongod4.conf
这里就不再分别演示修改方式,会以一张图来说明:修改数据路径、日志文件、端口号
下图是多实例修改样本:
5)当配置文件都 OK 后,就可以把4个实例全部启动:
[[email protected] ~]# mongod -f /etc/mongod.conf ---(第一台实例,是自己用YUM 装的,可以看作一台实例。)
[[email protected] ~]# mongod -f /etc/mongod2.conf ----(第二台实例,需要注意,如果有报错,很大一部分原因都是配置文件有问题,仔细检查配置文件的路径等问题)
[[email protected] ~]# mongod -f /etc/mongod3.conf ----(第三台实例)
[[email protected] ~]# mongod -f /etc/mongod4.conf ----(第4台实例)
6)进入第一台实例,初始化复制集配置 ---(以上步骤只是创建实例,并不是复制集哦。)
[[email protected] ~]# 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)到这里实验成功,那么需要验证它的功能性,下面会模拟故障转移,在这里是看不出实验效果,只给方法。
[[email protected] ~]# 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
[[email protected] ~]# kill -9 40778 ----(把进程 kill 掉 ,因为细心的朋友可以看到,40778 现在是主节点,把它 kill 掉,就是为了看其他节点会不会自动切换为主节点)
10)进入第二台实列,查看复制集状态
[[email protected] ~]# 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)从以上数据可以看出,当主节点挂掉后,从节点会自动切换为主节点,但是又不是按照顺序来推荐谁当主节点,这里的推荐的原理,后面会讲到。当然,这里是自动切换主从,我们也可以手动进行切换
[[email protected] ~]# mongod -f /etc/mongod.conf ----(把上个步骤停止的实例启动起来,方便我们实验)
[[email protected] ~]# 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) 命令启动复制集。
原文地址:http://blog.51cto.com/13746824/2175720