小小最近处于不停的学习状态,这次需要的是MongoDB 高可用落地方案。
此落地方案,用于实现高可用。

复制集

这里部署相关的复制集,用于实现MongoDB的高可用。

介绍

MongoDB 复制集用于提供相关的数据副本,当发生硬件或者服务中断的时候,将会从副本中恢复数据,并进行自动化的故障转移用于实现MongoDB的高可用。
本部分,将会介绍如何部署一个相关的复制集的环境,用3个Mongodb 实例建立一个由三节点组成的,已经安装好的Mongodb数据库。

部署复制集

本部分将会部署一个rs0的复制集
1. 建立数据目录

mkdir -p /srv/mongodb/rs0-0 /srv/mongodb/rs0-1 /srv/mongodb/rs0-2
  1. 启动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选项,用于指定复制集的名称,所有节点共同拥有相关的复制集的名称

  1. 设置主机名
hostname                    # 查看主机名
hostname mongodb-server     # 修改主机名
hostname                    # 确认主机名为 mongodb-server

编辑文件/etc/hosts 添加下面一行

127.0.0.1       mongodb-server
  1. 通过命令,连接到mongod实例,需要指定所需要的端口
mongo --port 27018
  1. 执行命令,初始化复制集
> rs.initiate()
{
"info2" : "no configuration explicitly specified -- making one",
"me" : "mongodb-server:27018",
"ok" : 1
}
  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
        }
    }
}
  1. 添加相关的复制节点
rs0:PRIMARY> rs.add("mongodb-server:27019")
{ "ok" : 1 }
rs0:PRIMARY> rs.add("mongodb-server:27020")
{ "ok" : 1 }
  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
}

这样就完成了,节点的故障转移。

主从实现高可用

这里使用主从实现高可用。
主从结构如下所示

方案 | Mongodb 高可用落地方案插图

其有两种角色构成

可读可写,当数据有修改的时候,会将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

方案 | Mongodb 高可用落地方案插图1

从服务器

在从服务器上创建存放数据的路径

mkdir -p /data/mongodb/slave

以从模式进行启动

mongod -dbpath /data/mongodb/slave -slave -source 10.29.240.13:27017

这样就完成了一主,多从的mongodb的搭建

最复杂的 Replica Sets+Sharding

启动配置服务器

  1. 启动配置服务器的副本集
mongod -f /u01/conf/config.cnf
  1. 查看配置服务器的状态
mongo localhost:27019/admin -uroot -p
rs.status()

启动相关的副本集

  1. 启动分片副本集
mongod -f /u01/conf/sd1.cnf

  1. 查看分片的副本集的状态
mongo localhost:27018/admin -uroot -p
rs.status()

启动服务器

  1. 启动所有的mongos
mongos -f /u01/conf/mongos.cnf
  1. 连接 mongos
mongo localhost:27017/admin -uroot -p
  1. 查看分片集群状态
sh.status()