Replica Set是mongod的实例集合,它们有着同样的数据内容。包含三类角色:
[1]主节点(Primary)

接收所有的写请求,然后把修改同步到所有Secondary。一个Replica Set只能有一个Primary节点,当Primary挂掉后,其他Secondary或者Arbiter节点会重新选举出来一个主节点。默认读请求也是发到Primary节点处理的,需要转发到Secondary需要客户端修改一下连接配置。

[2]副本节点(Secondary)

与主节点保持同样的数据集。当主节点挂掉的时候,参与选主。

[3]仲裁者(Arbiter)

不保有数据,不参与选主,只进行选主投票。使用Arbiter可以减轻数据存储的硬件需求,Arbiter跑起来几乎没什么大的硬件资源需求,但重要的一点是,在生产环境下它和其他数据节点不要部署在同一台机器上。
注意,一个自动failover的Replica Set节点数必须为奇数,目的是选主投票的时候要有一个大多数才能进行选主决策。

[4]选主过程

其中Secondary宕机,不受影响,若Primary宕机,会进行重新选主



                                                             安装部署

部署安装3个mongodb实例;分别为master服务器Primary,和slave1服务器(备份服务器副本secondary),从slave2服务器(仲裁服务器arbiter)

[1].配置master

mkdir -p /app/mongodb/cluster/master_mongodb/{log,db,install}
wget -P /app/mongodb/cluster/master_mongodb/install/ https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.2.16.tgz
cd /app/mongodb/cluster/master_mongodb/install/ && tar -xvzf mongodb-linux-x86_64-3.2.16.tgz && rm -rf mongodb-linux-x86_64-3.2.16.tgz
mv mongodb-linux-x86_64-3.2.16 ../mongodb && cd  /app/mongodb/cluster/
cat > /app/mongodb/cluster/master_mongodb/mongodb/mongodb.conf << EOF
dbpath=/app/mongodb/cluster/master_mongodb/db
logpath=/app/mongodb/cluster/master_mongodb/log/mongodb.log
port=27017
fork=true
nohttpinterface=true
bind_ip = 0.0.0.0
replSet=Mgo_mt/127.0.0.1:27018
EOF

2.配置slave1(备份)

cp  -a /app/mongodb/cluster/master_mongodb  /app/mongodb/cluster/slave_mongodb1
cat > /app/mongodb/cluster/slave_mongodb1/mongodb/mongodb.conf<< EOF
dbpath=/app/mongodb/cluster/slave_mongodb1/db
logpath=/app/mongodb/cluster/slave_mongodb1/log/mongodb.log
port=27018
fork=true
nohttpinterface=true
bind_ip = 0.0.0.0
replSet=Mgo_mt/127.0.0.1:27017
EOF

3.配置slave2(仲裁)

cp  -a /app/mongodb/cluster/master_mongodb  /app/mongodb/cluster/slave_mongodb2
cat >/app/mongodb/cluster/slave_mongodb2/mongodb/mongodb.conf<< EOF
dbpath=/app/mongodb/cluster/slave_mongodb2/db
logpath=/app/mongodb/cluster/slave_mongodb2/log/mongodb.log
port=27019
fork=true
nohttpinterface=true
bind_ip = 0.0.0.0
replSet=Mgo_mt/127.0.0.1:27017
EOF

接下来启动指定主从即可。
4.开启master,slave1,slave2服务器

/app/mongodb/cluster/master_mongodb/mongodb/bin/mongod  -f  /app/mongodb/cluster/master_mongodb/mongodb/mongodb.conf
/app/mongodb/cluster/slave_mongodb1/mongodb/bin/mongod   -f /app/mongodb/cluster/slave_mongodb1/mongodb/mongodb.conf 
/app/mongodb/cluster/slave_mongodb2/mongodb/bin/mongod  -f /app/mongodb/cluster/slave_mongodb2/mongodb/mongodb.conf

5.登录master配置副本集

登录master执行如下命令:
/app/mongodb/cluster/master_mongodb/mongodb/bin/mongo 127.0.0.1:27017/admin
#添加从服务器和仲裁服务器;配置仲裁服务器:利用哨兵检查集群状态和仲裁投票。注意:哨兵不参与数据的同步,只参与投票和状态检查。
db.runCommand({"replSetInitiate":{ "_id":"Mgo_mt", "members":[ {"_id":1,"host":"127.0.0.1:27017"},{"_id":2,"host":"127.0.0.1:27018"}]}})  #添加从27018
rs.addArb("127.0.0.1:27019") #添加仲裁27019

6.查看状态:

Mgo_mt:PRIMARY> rs.status()
{
    "set" : "Mgo_mt",
    "date" : ISODate("2019-03-28T09:57:43.689Z"),
    "myState" : 1,
    "term" : NumberLong(1),
    "heartbeatIntervalMillis" : NumberLong(2000),
    "members" : [
        {
            "_id" : 1,
            "name" : "127.0.0.1:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 2379,
            "optime" : {
                "ts" : Timestamp(1553766986, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2019-03-28T09:56:26Z"),
            "electionTime" : Timestamp(1553766519, 1),
            "electionDate" : ISODate("2019-03-28T09:48:39Z"),
            "configVersion" : 2,
            "self" : true
        },
        {
            "_id" : 2,
            "name" : "127.0.0.1:27018",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 555,
            "optime" : {
                "ts" : Timestamp(1553766986, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2019-03-28T09:56:26Z"),
            "lastHeartbeat" : ISODate("2019-03-28T09:57:42.849Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-28T09:57:42.862Z"),
            "pingMs" : NumberLong(0),
            "syncingTo" : "127.0.0.1:27017",
            "configVersion" : 2
        },
        {
            "_id" : 3,
            "name" : "127.0.0.1:27019",
            "health" : 1,
            "state" : 7,
            "stateStr" : "ARBITER",
            "uptime" : 76,
            "lastHeartbeat" : ISODate("2019-03-28T09:57:42.850Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-28T09:57:41.892Z"),
            "pingMs" : NumberLong(0),
            "configVersion" : 2
        }
    ],
    "ok" : 1
}

7.查看

#stateStr:PRIMARY--27017,27017位
"stateStr" : "SECONDARY", 27018为从
"stateStr" : "ARBITER",27019为仲裁

8.登录从检查状态:

/app/mongodb/cluster/slave_mongodb1/mongodb/bin/mongo 127.0.0.1:27018
/app/mongodb/cluster/slave_mongodb2/mongodb/bin/mongo 127.0.0.1:27019
查看状态:
rs.status()是否与master一致。

9.测试1:master创建wyl测试库并插入数据。查看slave从库1和slave2哨兵

在master上面执行:
Mgo_mt:PRIMARY> use wyl;
switched to db wyl
Mgo_mt:PRIMARY> db.wyl_test.insert({"name":"wyl","age":"10"})
WriteResult({ "nInserted" : 1 })
Mgo_mt:PRIMARY> db.wyl_test.find()
{ "_id" : ObjectId("5c9c9dfdbca21d51a5bf78ac"), "name" : "wyl", "age" : "10" }
登录slave1查看:注意默认从库没有读操作:需要执行s.slaveOk()
Mgo_mt:SECONDARY> show dbs;
local  0.000GB
wyl    0.000GB
Mgo_mt:SECONDARY> rs.slaveOk()
Mgo_mt:SECONDARY> show dbs;
local  0.000GB
wyl    0.000GB
Mgo_mt:SECONDARY> use wyl;
switched to db wyl
Mgo_mt:SECONDARY> db.wyl_test.find()
{ "_id" : ObjectId("5c9c9dfdbca21d51a5bf78ac"), "name" : "wyl", "age" : "10" }
登录slave2哨兵查看:
Mgo_mt:ARBITER> rs.slaveOk()
Mgo_mt:ARBITER> show dbs;
local  0.000GB
#哨兵不参与数据的同步。所以并没有wyl数据库。

10.测试2:关闭master查看是否会切换

kill -2 57814 #kill掉master 进程
登录从1查看状态:
Mgo_mt:PRIMARY> rs.status()
可以看出:
"stateStr" : "(not reachable/healthy)"--27017已经不可达
"stateStr" : "PRIMARY",27018为主master [之前的从变成了主]
"stateStr" : "ARBITER",27019为仲裁不变

11.测试3:重新开启之前停掉的master

/app/mongodb/cluster/master_mongodb/mongodb/bin/mongod  -f  /app/mongodb/cluster/master_mongodb/mongodb/mongodb.conf
rs.status()#查看状态此时:
之前的主已经变成了从
rs.status()
{
    "set" : "Mgo_mt",
    "date" : ISODate("2019-03-28T10:35:29.257Z"),
    "myState" : 2,
    "term" : NumberLong(2),
    "syncingTo" : "127.0.0.1:27018",
    "heartbeatIntervalMillis" : NumberLong(2000),
    "members" : [
        {
            "_id" : 1,
            "name" : "127.0.0.1:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 176,
            "optime" : {
                "ts" : Timestamp(1553768702, 1),
                "t" : NumberLong(2)
            },
            "optimeDate" : ISODate("2019-03-28T10:25:02Z"),
            "syncingTo" : "127.0.0.1:27018",
            "configVersion" : 2,
            "self" : true
        },
        {
            "_id" : 2,
            "name" : "127.0.0.1:27018",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 174,
            "optime" : {
                "ts" : Timestamp(1553768702, 1),
                "t" : NumberLong(2)
            },
            "optimeDate" : ISODate("2019-03-28T10:25:02Z"),
            "lastHeartbeat" : ISODate("2019-03-28T10:35:28.488Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-28T10:35:28.198Z"),
            "pingMs" : NumberLong(0),
            "electionTime" : Timestamp(1553768701, 1),
            "electionDate" : ISODate("2019-03-28T10:25:01Z"),
            "configVersion" : 2
        },
        {
            "_id" : 3,
            "name" : "127.0.0.1:27019",
            "health" : 1,
            "state" : 7,
            "stateStr" : "ARBITER",
            "uptime" : 174,
            "lastHeartbeat" : ISODate("2019-03-28T10:35:28.486Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-28T10:35:27.125Z"),
            "pingMs" : NumberLong(0),
            "configVersion" : 2
        }
    ],
    "ok" : 1
}

此时可以配合keepalived和headbeaart实现vip切换