MongoDB_replication搭建

MongoDB复制集是一个带有故障转移的主从集群。是从现有的主从模式演变而来,增加了自动故障转移和节点成员自动恢复。

MongoDB复制集模式的好处:
• 一切自动化。首先,复制集模式本身做了大量的管理工作,自动管理从节点,确保数据不会不一致。
• 主节点挂掉后,会自动判断集群中的服务器并进行故障转移,推举新的主节点。
• 一个复制集集群支持1-7台服务器,在一个复制集中各个服务器数据保持完全一致。

在一个MongoDB复制集集群中,各个服务器有以下几种状态:
• Primary 主节点,一个复制集有且仅有一台服务器处于Primary状态,只有主节点才对外提供读写服务。如果主节点挂掉,复制集将投票选出一个备节点成为新的主节点。
• Secondary 备用节点,复制集允许有多台Secondary,每个备用节点的数据与主节点的数据是完全同步的。Recovering 恢复中,当复制集中某台服务器挂掉或者掉线后数据无法同步,重新恢复服务后从其他成员复制数据,这时就处于恢复过程,数据同步后,该节点又回到备用状态。
• Arbiter 仲裁节点,主要负责在复本集中监控其他节点状态,投票选出主节点。该节点将不会用于存放数据。如果没有仲裁节点,那么投票工作将由所有节点共同进行。
• Down 无效节点,当服务器挂掉或掉线时就会处于该状态。复制集的从节点读请求,也是在各个Driver层设置slaveOk的值来实现的。
如上介绍所知,mongodb中的复制可以在多台服务器中同步数据。复制提供了冗余和增加了数据的高可用性,防止单个节点易丢失数据的可能性,也可以用来进行读写分离提高客户端操作性能。复制集中各节点的mongodb实例有相同的数据集副本。主节点可以接收客户端所有写操作记录到日志中,从库复制主库的操作日志记录应用到其数据库中。一个客户端只能有一个主节点,如果主节点不可用,复制集中将选一个成员节点作为主节点。

 

下面简单介绍下MongoDB 副本集的部署过程:
1)服务器信息
[mongodb@mongo1 ~]$ cat /etc/hosts
10.10.10.1 mongo1
10.10.10.2 mongo2

两台服务器均设置好主机名,关闭iptables及selinux(略)


3)安装部署mongodb(三台机器都安装)

创建MongoDB用户:
[root@mongo1 data]# id mongodb
uid=801(mongodb) gid=801(mongodb) groups=801(mongodb)

[mongodb@mongo1 data]$ pwd
/data

[mongodb@mongo1 data]$ tar -zvxf mongodb-linux-x86_64-rhel62-v3.2-latest.tgz

[mongodb@mongo1 data]$ mv mongodb-linux-x86_64-rhel62-3.2.21-1-gb552f4281d mongodb

[mongodb@mongo1 mongodb]$ cd /data/mongodb

##创建相关目录,存放数据与日志
[mongodb@mongo1 mongodb]$ mkdir data
[mongodb@mongo1 mongodb]$ mkdir log

##编辑数据库配置文件
[mongodb@mongo1 mongodb]$ vi mongodb.conf
pidfilepath=/data/mongodb/log/mongod.pid
logpath=/data/mongodb/log/mongod.log
dbpath=/data/mongodb/data
logappend=true
bind_ip=10.10.10.1
port=27001
fork=true
replSet=test

备节点的mongodb.conf配置文件分别为:
[mongodb@mongo2 mongodb]$ vi mongodb.conf
pidfilepath=/data/mongodb/log/mongod.pid
logpath=/data/mongodb/log/mongod.log
dbpath=/data/mongodb/data
logappend=true
bind_ip=10.10.10.2
port=27001
fork=true
replSet=test

其中:replSet=test #表示复制集名称:test

启动主备服务器的mongodb
[mongodb@mongo1 mongodb]$ /data/mongodb/bin/mongod --config /data/mongodb/mongodb.conf
about to fork child process, waiting until server is ready for connections.
forked process: 18714
child process started successfully, parent exiting

[mongodb@mongo1 mongodb]$ ps -ef|grep mongodb
mongodb 18714 1 3 01:28 ? 00:00:01 /data/mongodb/bin/mongod --config /data/mongodb/mongodb.conf

[mongodb@mongo2 mongodb]$ lsof -i:27001
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mongod 5538 mongodb 6u IPv4 29132 0t0 TCP mongo2:27001 (LISTEN)


[mongodb@mongo2 mongodb]$ /data/mongodb/bin/mongod --config /data/mongodb/mongodb.conf
about to fork child process, waiting until server is ready for connections.
forked process: 5538
child process started successfully, parent exiting

[mongodb@mongo2 mongodb]$ lsof -i:27001
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mongod 5538 mongodb 6u IPv4 29132 0t0 TCP mongo2:27001 (LISTEN)

设置mongodb的环变量
[mongodb@mongo1 mongodb]$ vi /home/mongodb/.bash_profile
......
export PATH=$PATH:/data/mongodb/bin

[mongodb@mongo1 mongodb]$ source /home/mongodb/.bash_profile

登录到mongodb中:
[mongodb@mongo1 mongodb]$ mongo 10.10.10.1:27001
MongoDB shell version: 3.2.21-1-gb552f4281d
connecting to: 10.10.10.1:27001/test
>

##初始化复制集:(集合为:"test" ;第一个成员为:"sign-mongo01.wangshibo.cn:27001"
> rs.initiate({_id: "test",members: [{ _id: 0 , host: "mongo1:27001" }]})
{ "ok" : 1 }
test:OTHER> //接着回车,显示这个节点为Primary主节点
test:PRIMARY>

接着添加另1个成员:
test:PRIMARY> rs.add("mongo2:27001")
{ "ok" : 1 }

查看成员信息 (或者使用 db.isMaster() )
test:PRIMARY> rs.status()
{
"set" : "test",
"date" : ISODate("2020-08-23T17:37:44.800Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "mongo1:27001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 575,
"optime" : {
"ts" : Timestamp(1531244248, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-08-23T17:37:28Z"),
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1531244158, 2),
"electionDate" : ISODate("2020-08-23T17:35:58Z"),
"configVersion" : 2,
"self" : true
},
{
"_id" : 1,
"name" : "mongo2:27001",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 15,
"optime" : {
"ts" : Timestamp(1531244248, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-08-23T17:37:28Z"),
"lastHeartbeat" : ISODate("2020-08-23T17:37:42.874Z"),
"lastHeartbeatRecv" : ISODate("2020-08-23T17:37:41.167Z"),
"pingMs" : NumberLong(2),
"configVersion" : 2
}
],
"ok" : 1
}

##看一下备库的状态,是否加入集群:

[mongodb@mongo2 mongodb]$ mongo 10.10.10.2:27001
MongoDB shell version: 3.2.21-1-gb552f4281d
connecting to: 10.10.10.2:27001/test
test:SECONDARY>
test:SECONDARY> rs.status()rs.status()
{
"set" : "test",
"date" : ISODate("2020-08-23T12:02:18.133Z"),
"myState" : 2,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "mongo1:27001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 298,
"optime" : {
"ts" : Timestamp(1531244248, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-08-23T17:37:28Z"),
"lastHeartbeat" : ISODate("2020-08-23T12:02:17.389Z"),
"lastHeartbeatRecv" : ISODate("2020-08-23T12:02:16.598Z"),
"pingMs" : NumberLong(2),
"electionTime" : Timestamp(1531244158, 2),
"electionDate" : ISODate("2020-08-23T17:35:58Z"),
"configVersion" : 2
},
{
"_id" : 1,
"name" : "mongo2:27001",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 859,
"optime" : {
"ts" : Timestamp(1531244248, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-08-23T17:37:28Z"),
"infoMessage" : "could not find member to sync from",
"configVersion" : 2,
"self" : true
}
],
"ok" : 1
}

详细说明如下:
"_id" : #集群中节点编号
"name" : #成员服务器名称及端口
"health" : #表示成员中的健康状态(0:down;1:up)
"state" : #为0~10,表示成员的当前状态
"stateStr" : #描述该成员是主库(PRIMARY)还是备库(SECONDARY)
"uptime" : #该成员在线时间(秒)
"optime" : #成员最后一次应用日志(oplog)的信息
"optimeDate" : #成员最后一次应用日志(oplog)的时间
"electionTime" : #当前primary从操作日志中选举信息
"electionDate" : #当前primary被选定为primary的日期
"configVersion" : #mongodb版本
"self" : #为true 表示当前节点

4)测试操作。在主库中,可以任意操作:
test:PRIMARY> show dbs
local 0.000GB
test:PRIMARY> use mydb //切换到要创建的数据库,原来该库未存在也可切换
switched to db mydb
test:PRIMARY> show dbs //use只是转到相关数据库,此时并没有做任何操作,所以并不会创建相应的数据库,只有当真正的操作了一次数据库就会自动创建。
local 0.000GB

test:PRIMARY> db.stats();
{
"db" : "mydb",
"collections" : 0,
"objects" : 0,
"avgObjSize" : 0,
"dataSize" : 0,
"storageSize" : 0,
"numExtents" : 0,
"indexes" : 0,
"indexSize" : 0,
"fileSize" : 0,
"ok" : 1
}

##当插入数据库后,会自动创建该DB
test:PRIMARY> db.coll.insert({"id":1})
WriteResult({ "nInserted" : 1 })

test:PRIMARY> db.coll.find()
{ "_id" : ObjectId("5a162222991b83743942d169"), "id" : 1 }
##已经存在数据
test:PRIMARY> db.stats();db.stats();
{
"db" : "mydb",
"collections" : 1,
"objects" : 1,
"avgObjSize" : 34,
"dataSize" : 34,
"storageSize" : 4096,
"numExtents" : 0,
"indexes" : 1,
"indexSize" : 4096,
"ok" : 1
}


##该数据库自动创建
test:PRIMARY> show dbs
local 0.000GB
mydb 0.000GB


##现在到备库中,查看分库数据库目录,发现多了数据库,数据库与主库一致!是主库同步过来的。
MongoDB shell version: 3.2.21-1-gb552f4281d
connecting to: 10.10.10.2:27001/test
test:SECONDARY>

从库开启读操作(此时可以测试主库插入,从库查看,同步正常):
test:SECONDARY> rs.slaveOk(); //为何要先执行这个命令???
test:SECONDARY> show dbs
local 0.000GB
mydb 0.000GB

##数据已经从主库同步到备库
test:SECONDARY> rs.slaveOk();
test:SECONDARY> use mydb
switched to db mydb
test:SECONDARY> db.coll.find()
{ "_id" : ObjectId("5b44f16973cb5a8d493427da"), "id" : 1 }


5)现在模拟主库不可用,将主节点服务停止:
[mongodb@mongo1 mongodb]$ pkill -9 mongod
[mongodb@mongo1 mongodb]$ ps -ef|grep mongodb
app 9524 9398 0 09:32 pts/0 00:00:00 grep mongodb

到备节点中登录mongodb,查看复制集状态:
[mongodb@mongo2 mongodb]$ mongo 10.10.10.2:27001
MongoDB shell version: 3.2.21-1-gb552f4281d
connecting to: 10.10.10.2:27001/test
test:SECONDARY> rs.status()
{
"set" : "test",
"date" : ISODate("2020-08-23T12:15:41.794Z"),
"myState" : 2,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "mongo1:27001",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2020-08-23T12:15:41.701Z"),
"lastHeartbeatRecv" : ISODate("2020-08-23T12:14:50.479Z"),
"pingMs" : NumberLong(2),
"lastHeartbeatMessage" : "Connection refused",
"configVersion" : -1
},
{
"_id" : 1,
"name" : "mongo2:27001",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1662,
"optime" : {
"ts" : Timestamp(1531244905, 2),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-08-23T17:48:25Z"),
"infoMessage" : "could not find member to sync from",
"configVersion" : 2,
"self" : true
}
],
"ok" : 1
}

有上面可看出,主节点删除服务进程,primary并没有切换到备节点上:
再次启动主节点的mongodb服务,发现primary才自动切换回到主节点:
[mongodb@mongo1 mongodb]$ /data/mongodb/bin/mongod --config /data/mongodb/mongodb.conf

[mongodb@mongo1 mongodb]$ ps -ef|grep mongo
mongodb 19124 1 5 01:57 ? 00:00:35 /data/mongodb/bin/mongod --config /data/mongodb/mongodb.conf

[mongodb@mongo1 mongodb]$ mongo 10.10.10.1:27001
MongoDB shell version: 3.2.21-1-gb552f4281d
connecting to: 10.10.10.1:27001/test
test:PRIMARY> rs.status()rs.status()
{
"set" : "test",
"date" : ISODate("2020-08-23T18:08:25.013Z"),
"myState" : 1,
"term" : NumberLong(4),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "mongo1:27001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 663,
"optime" : {
"ts" : Timestamp(1541074798, 3),
"t" : NumberLong(4)
},
"optimeDate" : ISODate("2020-08-23T12:19:58Z"),
"electionTime" : Timestamp(1541074798, 2),
"electionDate" : ISODate("2020-08-23T12:19:58Z"),
"configVersion" : 2,
"self" : true
},
{
"_id" : 1,
"name" : "mongo2:27001",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 199,
"optime" : {
"ts" : Timestamp(1541074798, 3),
"t" : NumberLong(4)
},
"optimeDate" : ISODate("2020-08-23T12:19:58Z"),
"lastHeartbeat" : ISODate("2020-08-23T18:08:23.402Z"),
"lastHeartbeatRecv" : ISODate("2020-08-23T18:08:24.302Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "mongo1:27001",
"configVersion" : 2
}
],
"ok" : 1
}


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


现在开始部署仲裁节点,直接在 备机 部署仲裁节点:
[mongodb@mongo2 mongodb]$ pwd
/data/mongodb
[mongodb@mongo2 mongodb]$ mkdir -p arbiter

##仲裁节点的配置:
[mongodb@mongo2 mongodb]$ vi /data/mongodb/arbiter.conf
pidfilepath=/data/mongodb/log/arbiter.pid
logpath=/data/mongodb/log/arbiter.log
dbpath=/data/mongodb/arbiter
logappend=false
bind_ip=10.10.10.2
port=27002
fork=true
replSet=test

接着启动仲裁服务:
[mongodb@mongo2 mongodb]$ mongod --config /data/mongodb/arbiter.conf
about to fork child process, waiting until server is ready for connections.
forked process: 4808
child process started successfully, parent exiting

[mongodb@mongo2 mongodb]$
[mongodb@mongo2 mongodb]$ ps -ef|grep mongo
mongodb 4711 1 2 20:24 ? 00:00:10 /data/mongodb/bin/mongod --config /data/mongodb/mongodb.conf
mongodb 4808 1 4 20:32 ? 00:00:00 mongod --config /data/mongodb/arbiter.conf

[mongodb@mongo2 mongodb]$
[mongodb@mongo2 mongodb]$ lsof -i:27002
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mongod 4808 mongodb 6u IPv4 28754 0t0 TCP mongo2:27002 (LISTEN)


然后在Paimary主节点的mongodb中添加仲裁节点并查看结果
[mongodb@mongo1 mongodb]$ mongo 10.10.10.1:27001
MongoDB shell version: 3.2.21-1-gb552f4281d
connecting to: 10.10.10.1:27001/test
test:PRIMARY> test:PRIMARY> rs.addArb("mongo2:27002")
{ "ok" : 1 }

test:PRIMARY> db.isMaster()
test:PRIMARY> db.isMaster()
{
"hosts" : [
"mongo1:27001",
"mongo2:27001"
],
"arbiters" : [
"mongo2:27002"
],
"setName" : "test",
"setVersion" : 3,
"ismaster" : true,
"secondary" : false,
"primary" : "mongo1:27001",
"me" : "mongo1:27001",
"electionId" : ObjectId("7fffffff0000000000000004"),
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2020-08-23T18:16:55.609Z"),
"maxWireVersion" : 4,
"minWireVersion" : 0,
"ok" : 1
}


test:PRIMARY> rs.status()rs.status()
{
"set" : "test",
"date" : ISODate("2020-08-23T18:17:17.964Z"),
"myState" : 1,
"term" : NumberLong(4),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "mongo1:27001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1195,
"optime" : {
"ts" : Timestamp(1541074798, 4),
"t" : NumberLong(4)
},
"optimeDate" : ISODate("2020-08-23T12:19:58Z"),
"electionTime" : Timestamp(1541074798, 2),
"electionDate" : ISODate("2020-08-23T12:19:58Z"),
"configVersion" : 3,
"self" : true
},
{
"_id" : 1,
"name" : "mongo2:27001",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 731,
"optime" : {
"ts" : Timestamp(1541074798, 4),
"t" : NumberLong(4)
},
"optimeDate" : ISODate("2020-08-23T12:19:58Z"),
"lastHeartbeat" : ISODate("2020-08-23T18:17:17.108Z"),
"lastHeartbeatRecv" : ISODate("2020-08-23T18:17:17.110Z"),
"pingMs" : NumberLong(2),
"syncingTo" : "mongo1:27001",
"configVersion" : 3
},
{
"_id" : 2,
"name" : "mongo2:27002",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 105,
"lastHeartbeat" : ISODate("2020-08-23T18:17:17.106Z"),
"lastHeartbeatRecv" : ISODate("2020-08-23T18:17:13.009Z"),
"pingMs" : NumberLong(1),
"configVersion" : 3
}
],
"ok" : 1
}


至此,添加完成!!
再次测试主备切换。关闭(primary)中删除服务进程:
[mongodb@mongo1 mongodb]$ pkill -9 mongod
[mongodb@mongo1 mongodb]$ ps -ef|grep mongo
app 9664 9398 0 09:50 pts/0 00:00:00 grep mongod


然后到(secondary)查看,发现primary已经切换为备机
[mongodb@mongo2 mongodb]$ mongo 10.10.10.2:27001
MongoDB shell version: 3.2.21-1-gb552f4281d
connecting to: 10.10.10.2:27001/test
test:SECONDARY>
test:SECONDARY>
test:SECONDARY>
test:PRIMARY>
test:PRIMARY>
test:PRIMARY> rs.status()
{
"set" : "test",
"date" : ISODate("2020-08-23T12:39:19.930Z"),
"myState" : 1,
"term" : NumberLong(5),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "mongo1:27001",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2020-08-23T12:39:19.050Z"),
"lastHeartbeatRecv" : ISODate("2020-08-23T12:38:06.189Z"),
"pingMs" : NumberLong(2),
"lastHeartbeatMessage" : "Connection refused",
"configVersion" : -1
},
{
"_id" : 1,
"name" : "mongo2:27001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 867,
"optime" : {
"ts" : Timestamp(1541075896, 2),
"t" : NumberLong(5)
},
"optimeDate" : ISODate("2020-08-23T12:38:16Z"),
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1541075896, 1),
"electionDate" : ISODate("2020-08-23T12:38:16Z"),
"configVersion" : 3,
"self" : true
},
{
"_id" : 2,
"name" : "mongo2:27002",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 236,
"lastHeartbeat" : ISODate("2020-08-23T12:39:18.788Z"),
"lastHeartbeatRecv" : ISODate("2020-08-23T12:39:18.989Z"),
"pingMs" : NumberLong(0),
"configVersion" : 3
}
],
"ok" : 1
}

test:PRIMARY> show dbs
local 0.000GB
mydb 0.000GB

有上面信息可知,添加仲裁节点后,primary能正常启动切换了!~

现在看看arbiter,连接到进去仲裁几点看看:
[mongodb@mongo2 mongodb]$ mongo 10.10.10.2:27002
MongoDB shell version: 3.2.21-1-gb552f4281d
connecting to: 10.10.10.2:27002/test
test:ARBITER>
test:ARBITER> rs.slaveOk();
test:ARBITER> db.isMaster()
{
"hosts" : [
"mongo1:27001",
"mongo2:27001"
],
"arbiters" : [
"mongo2:27002"
],
"setName" : "test",
"setVersion" : 3,
"ismaster" : false,
"secondary" : false,
"primary" : "mongo2:27001",
"arbiterOnly" : true,
"me" : "mongo2:27002",
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2020-08-23T12:41:09.336Z"),
"maxWireVersion" : 4,
"minWireVersion" : 0,
"ok" : 1
}

test:ARBITER> show dbs
local 0.000GB

arbiter 最为仲裁者,没有数据副本存储在本地,能读取复制集的信息。

 

posted @ 2020-08-24 10:13  咿呀咿呀哟9614  阅读(552)  评论(0)    收藏  举报