MongoDB搭建高可用副本集群-Replica Set
前几天吧,开发的大哥问我本地还有没资源了,现在想要装一个mongodb用,因为这东西只是听说过,也没用过,更别说搭建了,然后找了一个服务器,在官网下了一个源码包,谷歌了一下,就装上了,也启动了,然后把地址给他发过去了,可以正常使用,哈哈。然后又和我说你有时间研究一下MongoDB的集群要怎么搭建,以后有项目可能会用这个,既然来事了,说搞就搞,大概查了一下,发现MongoDB做集群的方式大概是有三种,最常用的一种也就是我现在要写的这个,英文Replica Set,翻译过来叫副本集群,已经搞出来了,经过测试得到的结论是可以正常使用,哈哈,总结一下,具体方法如下。
首先需要三台服务器,分别为主节点,备节点,及仲裁节点,主备节点存储数据,仲裁节点不存储数据,客户端同时连接主备节点,不连接仲裁节点。默认情况下,主节点提供所有增删改查服务,备节点不提供任何服务,仲裁节点是一个特殊的节点,不存储数据,他的作用是决定哪个备节点在主节点挂掉之后提升为主节点,现在是一主一从,仍需要仲裁节点来提升备节点级别,如果没有它,主的挂了备的还是备的,不会提升为主的,所以仲裁节点必须得在,现有环境如下,使用centos6.9操作系统
192.168.1.213 mongodb-master
192.168.1.166 mongodb-slave
192.168.1.251 mongodb-arbiter
安装阶段
下载MongoDB
[root@mongodb-master ~]# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.4.7.tgz
下载可能会很慢,等吧。。。。
解压安装,配置变量
三个服务器同时操作即可,我存放的目录为/usr/local/
[root@mongodb-master ~]# tar zxf mongodb-linux-x86_64-rhel62-3.4.7.tgz -C /usr/local/
[root@mongodb-master ~]# mv /usr/local/mongodb-linux-x86_64-rhel62-3.4.7/ /usr/local/mongodb
[root@mongodb-master ~]# cat >>/etc/profile<<OEF
> export PATH=\$PATH:/usr/local/mongodb/bin
> OEF
[root@mongodb-master ~]# source /etc/profile
集群配置阶段
创建数据文件夹
创建数据文件夹,就放到MongoDB安装目录下吧,我就以一个为例子了,剩下的两个按着弄吧
[root@mongodb-master ~]# mkdir /usr/local/mongodb/data
创建配置文件,主节点,并启动
[root@mongodb-master ~]# cat >>/usr/local/mongodb/mongod.conf<<OEF
> dbpath=/usr/local/mongodb/data
> logpath=/usr/local/mongodb/log/master.log
> pidfilepath=/usr/local/mongodb/master.pid
> directoryperdb=true
> logappend=true
> replSet=rj_bai
> bind_ip=192.168.1.213
> port=27017
> oplogSize=10000
> fork=true
> noprealloc=true
> OEF
启动服务
[root@mongodb-master ~]# mongod -f /usr/local/mongodb/mongod.conf
```bash
如果你是按着我这个写的,这里会抛个错,原因是没有log那个文件夹,需要创建一下即可。

```bash
[root@mongodb-master ~]# mkdir /usr/local/mongodb/log && mongod -f /usr/local/mongodb/mongod.conf
[root@mongodb-master ~]# netstat -lntp | grep mongo
tcp 0 0 192.168.1.213:27017 0.0.0.0:* LISTEN 23016/mongod
备节点及仲裁节点配置文件如下,启动方式和以上一样,就不一一写了。
备节点
dbpath=/usr/local/mongodb/data
logpath=/usr/local/mongodb/log/slaver.log
pidfilepath=/usr/local/mongodb/log/slaver.pid
directoryperdb=true
logappend=true
replSet=rj_bai
bind_ip=192.168.1.166
port=27017
oplogSize=10000
fork=true
noprealloc=true
仲裁节点
dbpath=/usr/local/mongodb/data
logpath=/usr/local/mongodb/log/arbiter.log
pidfilepath=/usr/local/mongodb/arbiter.pid
directoryperdb=true
logappend=true
replSet=rj_bai
bind_ip=192.168.1.251
port=27017
oplogSize=10000
fork=true
noprealloc=true
参数解释
dbpath | 数据库存放目录 |
logpath | 日志存放目录 |
pidfilepath | pid文件 |
directoryperdb | 数据库按名独立存放 |
logappend | 以追加的方式记录日志 |
replSet | replica set 的名字 |
bind\_ip | 绑定的ip地址 |
port | 指定端口号,默认27017 |
oplogSize | 操作文件最大值,单位mb,默认硬盘百分之5 |
fork | 以后台方式运行 |
noprealloc | 不预先分配内存 |
集群配置
连接任意节点,我连接的213作为主节
[root@mongodb-master ~]# mongo 192.168.1.213:27017
连接后会出现几个警告,如下图
WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
看到这个不会影响使用,只是建议使用xfs文件系统,也就是centos7系列的默认文件系统,我用的6,EXT4的,所以会抛这个,不管
WARNING: Access control is not enabled for the database.
没有对数据库进行访问控制,对数据和配置的读写访问不受限制
最后两个的解决方法,重启后只要文件系统和访问控制的错了,先不管访问控制了。
[root@mongodb-master ~]# echo "never" > /sys/kernel/mm/transparent_hugepage/enabled
[root@mongodb-master ~]# echo "never" > /sys/kernel/mm/transparent_hugepage/defrag
开始创建集群
[root@mongodb-master ~]# mongo 192.168.1.213:27017 #登录到MongoDB
> use admin
> config={ _id:"rj_bai", members:[ {_id:0,host:'192.168.1.213:27017',priority:2}, {_id:1,host:'192.168.1.166:27017',priority:1},
... {_id:2,host:'192.168.1.251:27017',arbiterOnly:true}] }; #创建节点
> rs.initiate(config) #使配置生效
{ "ok" : 1 } #一定要看到这个1,如果不是1就失败了,检查是不是哪里搞错了
注意,id:的参数一定要与配置文件里的replSet名称一致,config这个名字是可以随意的
全部执行完后,生效可能需要几十秒,使用rs.status()查看信息,图太长了,就不截图了,把输出信息贴出来了
rj_bai:PRIMARY> rs.status()
{
"set" : "rj_bai",
"date" : ISODate("2017-08-22T07:31:09.071Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1503387066, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1503387066, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1503387066, 1),
"t" : NumberLong(1)
}
},
"members" : [
{
"_id" : 0,
"name" : "192.168.1.213:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1488,
"optime" : {
"ts" : Timestamp(1503387066, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2017-08-22T07:31:06Z"),
"electionTime" : Timestamp(1503386564, 1),
"electionDate" : ISODate("2017-08-22T07:22:44Z"),
"configVersion" : 1,
"self" : true
},
{
"_id" : 1,
"name" : "192.168.1.166:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 514,
"optime" : {
"ts" : Timestamp(1503387066, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1503387066, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2017-08-22T07:31:06Z"),
"optimeDurableDate" : ISODate("2017-08-22T07:31:06Z"),
"lastHeartbeat" : ISODate("2017-08-22T07:31:09.051Z"),
"lastHeartbeatRecv" : ISODate("2017-08-22T07:31:07.554Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "192.168.1.213:27017",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "192.168.1.251:27017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 514,
"lastHeartbeat" : ISODate("2017-08-22T07:31:09.051Z"),
"lastHeartbeatRecv" : ISODate("2017-08-22T07:31:06.338Z"),
"pingMs" : NumberLong(0),
"configVersion" : 1
}
],
"ok" : 1
}
看上面的信息,PRIMARY代表主节点,SECONDARY代表从节点,ARBITER代表仲裁节点,这是登陆MongoDB的提示符信息会变为你定义的replSet名字:所对应的节点,没做之前集群之前是什么都没有的。看图
同步测试
主库写入数据
创建数据库,名为lc
rj_bai:PRIMARY> use lc
switched to db lc
rj_bai:PRIMARY> db
lc
rj_bai:PRIMARY> show dbs
admin 0.000GB
local 0.000GB
rj_bai:PRIMARY>
想看到数据库的列表,使用show dbs命令,MongoDB是默认不显示为空的数据库,需要插入一点数据即可。
rj_bai:PRIMARY> db.lc.insert({"name":"其实,有时候疏远不是讨厌,而是太喜欢又很无奈。"})
WriteResult({ "nInserted" : 1 })
rj_bai:PRIMARY> show dbs
admin 0.000GB
local 0.000GB
lc 0.000GB
rj_bai:PRIMARY> db.lc.find()
{ "_id" : ObjectId("599bf11c27ac749672e148d7"), "name" : "其实,有时候疏远不是讨厌,而是太喜欢又很无奈。" }
查询从库
从库查询,但是会抛错,如图。
原因是SECONDARY是不允许读写的,执行一条命令即可解决这个问题。
rj_bai:SECONDARY> rs.slaveOk();
在从库查了一下刚刚添加的数据,存在的,说明同步没问题,下面模拟主库宕了从的会不会自动切换为主的。
切换测试
先看一下现在的情况,主库处于存活状态,查看集群信息如下。
看集群信息在仲裁节点看就可以,现在的情况是这样,要做的是吧192.168.1.213这个节点杀了,然后192.168.1.166会顶上去
现在已经杀掉了,在仲裁节点看一下,显示192.168.1.166已经成为主节点了。
然后在192.168.1.166这个服务器上查插点数据,一会看效果。
rj_bai:PRIMARY> use lc
switched to db lc
rj_bai:PRIMARY> db.lc.find()
{ "_id" : ObjectId("599bf11c27ac749672e148d7"), "name" : "其实,有时候疏远不是讨厌,而是太喜欢又很无奈。" }
rj_bai:PRIMARY> db.lc.insert({"name":"上句话是扯淡的,忽略,忽略,哈哈"})
WriteResult({ "nInserted" : 1 })
rj_bai:PRIMARY> db.lc.find()
{ "_id" : ObjectId("599bf11c27ac749672e148d7"), "name" : "其实,有时候疏远不是讨厌,而是太喜欢又很无奈。" }
{ "_id" : ObjectId("599b8447bb6efb1da54a5393"), "name" : "上句话是扯淡的,忽略,忽略,哈哈" }
试试证明也可以正常读写,最后启动192.168.1.213,会是什么样子。
[root@mongodb-master ~]# mongod -f /usr/local/mongodb/mongod.conf
查看集群信息,主节点已经又变回了192.168.1.213服务器。
而且之前在192.168.1.166上新建的数据也同步过去了。
从中得到了一个结论,当主节点宕了以后,备节点会变为主节点继续提供服务,当指定的主节点恢复后,也就是192.168.1.213服务器,备节点由现在的主节点恢复到之前的备节点状态,而不是继续充当主节点。由于这个是第一次搞,而且只是在本地做测试库用,正常跑了两天多了吧,到目前为止没出现过有什么问题,而且生产环境中也没有实际部署使用过,可能会有坑,暂时就这样吧,有坑了再说吧,哈哈,结束。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。