最近处于不停的学习状态,这次需要的是MongoDB 高可用落地方案。此落地方案,用于实现高可用。
复制集这里部署相关的复制集,用于实现MongoDB的高可用。
介绍
MongoDB 复制集用于提供相关的数据副本,当发生硬件或者服务中断的时候,将会从副本中恢复数据,并进行自动化的故障转移用于实现MongoDB的高可用。本部分,将会介绍如何部署一个相关的复制集的环境,用3个Mongodb 实例建立一个由三节点组成的,已经安装好的Mongodb数据库。
部署复制集
本部分将会部署一个rs0的复制集
- 建立数据目录
mkdir -p /srv/mongodb/rs0-0 /srv/mongodb/rs0-1 /srv/mongodb/rs0-2
- 启动mongodb实例 启动第一个实例
mongod --port 27018 --dbpath /srv/mongodb/rs0-0 --replSet rs0
启动第二个实例
mongod --port 27019 --dbpath /srv/mongodb/rs0-1 --replSet rs0
启动第三个实例
mongod --port 27020 --dbpath /srv/mongodb/rs0-2 --replSet rs0
这里port选项指定了相关的端口号,用于设置不同的端口号,其-dbpath选项用于指定相关的数据目录,每个节点都有不同的repSet选项,用于指定复制集的名称,所有节点共同拥有相关的复制集的名称
- 设置主机名
hostname # 查看主机名
hostname mongodb-server # 修改主机名
hostname # 确认主机名为 mongodb-server
编辑文件/etc/hosts 添加下面一行
127.0.0.1 mongodb-server
- 通过命令,连接到mongod实例,需要指定所需要的端口
mongo --port 27018
- 执行命令,初始化复制集
> rs.initiate()
{
"info2" : "no configuration explicitly specified -- making one",
"me" : "mongodb-server:27018",
"ok" : 1
}
- 执行命令,查看复制集的配置
rs0:PRIMARY> rs.conf()
{
"_id" : "rs0",
"version" : 1,
"members" : [
{
"_id" : 0,
"host" : "mongodb-server:27018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : 0,
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatTimeoutSecs" : 10,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
}
}
}
- 添加相关的复制节点
rs0:PRIMARY> rs.add("mongodb-server:27019")
{ "ok" : 1 }
rs0:PRIMARY> rs.add("mongodb-server:27020")
{ "ok" : 1 }
- 检查相关的复制集的状态
rs0:PRIMARY> rs.status()
{
"set" : "rs0",
"date" : ISODate("2015-12-04T06:12:07.664Z"),
"myState" : 1,
"members" : [
{
"_id" : 0,
"name" : "mongodb-server:27018",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 3611,
"optime" : Timestamp(1449209487, 1),
"optimeDate" : ISODate("2015-12-04T06:11:27Z"),
"electionTime" : Timestamp(1449208829, 2),
"electionDate" : ISODate("2015-12-04T06:00:29Z"),
"configVersion" : 3,
"self" : true
},
{
"_id" : 1,
"name" : "mongodb-server:27019",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 41,
"optime" : Timestamp(1449209487, 1),
"optimeDate" : ISODate("2015-12-04T06:11:27Z"),
"lastHeartbeat" : ISODate("2015-12-04T06:12:07.338Z"),
"lastHeartbeatRecv" : ISODate("2015-12-04T06:12:06.005Z"),
"pingMs" : 0,
"configVersion" : 3
},
{
"_id" : 2,
"name" : "mongodb-server:27020",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 40,
"optime" : Timestamp(1449209487, 1),
"optimeDate" : ISODate("2015-12-04T06:11:27Z"),
"lastHeartbeat" : ISODate("2015-12-04T06:12:07.339Z"),
"lastHeartbeatRecv" : ISODate("2015-12-04T06:12:07.339Z"),
"pingMs" : 0,
"configVersion" : 3
}
],
"ok" : 1
}
测试复制集
测试数据同步。
[root@mongodb ~]# mongo --port 27020
MongoDB shell version: 3.0.7
connecting to: 127.0.0.1:27020/test
...
rs0:SECONDARY>
由于默认的Secondary节点不可读,所以这里要让Secondary节点可读。
rs0:SECONDARY> rs.slaveOk()
rs0:SECONDARY> show dbs
local 1.078GB
rs0:SECONDARY> show collections
rs0:SECONDARY>
然后在primary 节点插入数据,
rs0:PRIMARY> use testdb
switched to db testdb
rs0:PRIMARY> db.tc.insert({ name : "mongo" })
WriteResult({ "nInserted" : 1 })
rs0:PRIMARY> db.tc.insert({ x : 3 })
WriteResult({ "nInserted" : 1 })
rs0:PRIMARY> db.tc.find()
{ "_id" : ObjectId("5661345929d3c35bcbe64803"), "name" : "mongo" }
{ "_id" : ObjectId("5661346b29d3c35bcbe64804"), "x" : 3 }
rs0:PRIMARY>
然后在 Secon命令上的客户端执行。
rs0:SECONDARY> rs.slaveOk()
rs0:SECONDARY> show dbs
local 1.078GB
testdb 0.078GB
rs0:SECONDARY> use testdb
switched to db testdb
rs0:SECONDARY> show collections
system.indexes
tc
rs0:SECONDARY> db.tc.find()
{ "_id" : ObjectId("5661345929d3c35bcbe64803"), "name" : "mongo" }
{ "_id" : ObjectId("5661346b29d3c35bcbe64804"), "x" : 3 }
rs0:SECONDARY>
测试故障转移
在主节点的服务器按下Ctrl + C 键模拟主节点故障,此时命令提示符变成
rs0:SECONDARY>
rs0:PRIMARY>
这个时候查看状态,可以看到故障已经转移。
rs0:PRIMARY> rs.status()
{
"set" : "rs0",
"date" : ISODate("2015-12-04T06:52:09.191Z"),
"myState" : 1,
"members" : [
{
"_id" : 0,
"name" : "mongodb-server:27018",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : Timestamp(0, 0),
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2015-12-04T06:52:08.039Z"),
"lastHeartbeatRecv" : ISODate("2015-12-04T06:45:11.755Z"),
"pingMs" : 0,
"lastHeartbeatMessage" : "Failed attempt to connect to mongodb-server:27018; couldn't connect to server mongodb-server:27018 (127.0.0.1), connection attempt failed",
"configVersion" : -1
},
{
"_id" : 1,
"name" : "mongodb-server:27019",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 2441,
"optime" : Timestamp(1449210987, 1),
"optimeDate" : ISODate("2015-12-04T06:36:27Z"),
"lastHeartbeat" : ISODate("2015-12-04T06:52:07.857Z"),
"lastHeartbeatRecv" : ISODate("2015-12-04T06:52:08.567Z"),
"pingMs" : 0,
"configVersion" : 3
},
{
"_id" : 2,
"name" : "mongodb-server:27020",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 5984,
"optime" : Timestamp(1449210987, 1),
"optimeDate" : ISODate("2015-12-04T06:36:27Z"),
"electionTime" : Timestamp(1449211514, 1),
"electionDate" : ISODate("2015-12-04T06:45:14Z"),
"configVersion" : 3,
"self" : true
}
],
"ok" : 1
}
这样就完成了,节点的故障转移。
主从实现高可用这里使用主从实现高可用。主从结构如下所示
其有两种角色构成
主
可读可写,当数据有修改的时候,会将oplog同步到所有连接的salve上去。
从
只读不可写,自动从Master同步数据。
特别的,对于Mongodb来说,并不推荐使用Master-Slave架构,因为Master-Slave其中Master宕机后不能自动恢复,推荐使用Replica Set,后面会有介绍,除非Replica的节点数超过50,才需要使用Master-Slave架构,正常情况是不可能用那么多节点的。
还有一点,Master-Slave不支持链式结构,Slave只能直接连接Master。Redis的Master-Slave支持链式结构,Slave可以连接Slave,成为Slave的Slave。
主从搭建
主服务器
在主服务器上创建个存放数据的路径
mkdir -p /data/mongodb/master
然后通过mongo命令启动服务,加上master参数
mongod –dbpath /data/mongodb/master –master
从服务器
在从服务器上创建存放数据的路径
mkdir -p /data/mongodb/slave
以从模式进行启动
mongod -dbpath /data/mongodb/slave -slave -source 10.29.240.13:27017
这样就完成了一主,多从的mongodb的搭建
最复杂的 Replica Sets+Sharding启动配置服务器
- 启动配置服务器的副本集
mongod -f /u01/conf/config.cnf
- 查看配置服务器的状态
mongo localhost:27019/admin -uroot -p
rs.status()
启动相关的副本集
- 启动分片副本集
mongod -f /u01/conf/sd1.cnf
- 查看分片的副本集的状态
mongo localhost:27018/admin -uroot -p
rs.status()
启动服务器
- 启动所有的mongos
mongos -f /u01/conf/mongos.cnf
- 连接 mongos
mongo localhost:27017/admin -uroot -p
- 查看分片集群状态
sh.status()