搭建高可用MongoDB集群(Replica set)

本文涉及的产品
云数据库 MongoDB,通用型 2核4GB
简介:

MongoDB基础可参考http://blog.51cto.com/kaliarch/2044423

一、概述

1.1 MongoDB副本集

通俗来讲,mongodb的副本集相当于具有自动故障恢复的主从集群,主从集群和副本集最明显的特征为副本集没有固定的“主节点”,整个集群会通过一定的算法选举出主节点,目前MongoDB官方已经不建议使用主从模式了,在主从模式下,如果主数据库宕机,从数据库无法自动接管主数据库,从而无法接入数据,取而代之的就是MongoDB副本集模式,主服务器负责整个副本集的读写,副本集定期同步数据备份,副本集中的副本节点在主节点挂掉后通过心跳机制检测到后副本节点就会选举一个新的主服务器,这一切对于应用服务器无需关心。

1.2 架构图

图片.png

1.3 复制原理

  • mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。

  • mongodb各个节点常见的搭配方式为:一主一从、一主多从。

  • 主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。

1.4 副本集特征:

  • N 个节点的集群

  • 任何节点可作为主节点

  • 所有写入操作都在主节点上

  • 自动故障转移

  • 自动恢复

1.5 Bully算法

如果副本集中主节点宕掉后,需要使用bully算法进行选举主节点,其主要思想为每个成员均可以声明自己为主节点并通知其他节点,别的节点可以选择接受这个声明或是拒绝并进入主节点竞争,只有被其他节点接受的节点才可以当主节点,

节点按照一些属性来判断谁应该胜出。这个属性可以是一个静态ID,也可以是更新的度量像最近一次事务ID(最新的节点会胜出)

官方描述:

  1. 得到每个服务器节点的最后操作时间戳。每个mongodb都有oplog机制会记录本机的操作,方便和主服务器进行对比数据是否同步还可以用于错误恢复。

  2. 如果集群中大部分服务器down机了,保留活着的节点都为 secondary状态并停止,不选举了。

  3. 如果集群中选举出来的主节点或者所有从节点最后一次同步时间看起来很旧了,停止选举等待人来操作。

  4. 如果上面都没有问题就选择最后操作时间戳最新(保证数据是最新的)的服务器节点作为主节点。

1.6 Replica Set成员

一个Replica Set中的成员角色有三种:Primary,SecondaryArbiter

  • Primary:接收来自客户端的所有的写操作,一个Replica Set中有且只有一个Primary。Primary如果宕掉,Replica Set会自动选举一个Secondary成为Primary。Primary将它data sets的所有操作都记录到oplog中。

  • Secondary:Secondary从Primary复制oplog,然后将oplog中的操作应用到自己的data sets。Secondary和Primary之间是异步复制,也就是Secondary中的数据可能不是最新的。默认情况下,Secondary不可读不可写,但是可以通过设置运行客户端从Secondary读。

        Secondary配置的三种用途:

        1.在选举中阻止其成为Primary,只用作备份数据。通过设置优先级priority为0来实现

        2.阻止应用程序从它读,通过设置优先级priority为0和设置hidden为true来实现。(一个隐藏的成员同样复制Primary的数据,但是对于客户端应用程序来讲,它不可见。)

        3.保留历史镜像数据用于数据回档,比如如果误删除数据,可以使用Delayed Replica Set成员中的数据恢复。

  • Arbiter:Arbiter不需要维护自己的data sets,只是当Primary挂掉之后参与投票选择哪个Secondary可以升级为Primary

Replica Set中的成员个数为偶数个时,就需要添加一个Arbiter用于投票选举哪个可以升级为Primary,不能在Primary或者Secondary主机上运行Arbiter

一个Replica Set可以最多拥有12个成员,但是只有7个成员可以同时参与投票选举成为Primary,如果成员数量超过12,就需要使用Master-Slave主从复制方式。

部署一个Replica Set至少需要三个成员,一个Arbiter,一个Secondary和一个Primary或者一个Primary,两个Secondary。

二、搭建部署

2.1 基础环境

主机名
IP地址
系统
mongodb-1
172.20.6.10 CentOS release 6.9 
mongodb-2 172.20.6.11 CentOS release 6.9 
mongodb-3 172.20.6.10 CentOS release 6.9 

2.2 软件安装

在三台服务器上依次安装mongodb

1
2
3
4
5
6
7
wget -c https: //fastdl .mongodb.org /linux/mongodb-linux-x86_64-rhel62-3 .4.10.tgz
tar  -zxvf mongodb-linux-x86_64-rhel62-3.4.10.tgz
ln  -sv mongodb-linux-x86_64-rhel62-3.4.10 mongodb
mkdir  /usr/local/mongodb/ {conf,mongoData,mongoLog}
touch  /usr/local/mongodb/mongoLog/mongodb .log
echo  "export PATH=$PAHT:/usr/local/mongodb/bin" > /etc/profile .d /mongodb .sh
source  etc /profile .d /mongodb .sh

定义配置文件

1
2
3
4
5
6
7
8
9
10
11
12
cat  > /usr/local/mongodb/conf/mongodb .conf<<EOF
dbpath= /usr/local/mongodb/mongoData
logpath= /usr/local/mongodb/mongoLog/mongodb .log
logappend= true 
journal= true
quiet= true
port=27017
replSet=RS                             #副本集名称
maxConns=20000
httpinterface= true
fork= true
EOF

依次启动三个mongodb

1
mongodb -f  /usr/local/mongodb/conf/mongodb .conf

图片.png

2.3 副本集部署

挑选任意一台mongodb进行登录

1
2
3
4
5
6
7
use admin                 #切换到admin数据库
config = {_id: "RS" ,members:[                 #定义副本集配置
{_id:0,host: "172.20.6.10:27017" },
{_id:1,host: "172.20.6.11:27017" },
{_id:2,host: "172.20.6.12:27017" },]
}
rs.initiate(config);         #初始化副本集配置

图片.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
RS:PRIMARY> rs.status();                 #查看副本集状态
{
     "set"  "RS" ,
     "date"  : ISODate( "2017-11-26T14:09:00.054Z" ),
     "myState"  : 1,
     "term"  : NumberLong(1),
     "heartbeatIntervalMillis"  : NumberLong(2000),
     "optimes"  : {
         "lastCommittedOpTime"  : {
             "ts"  : Timestamp(1511705333, 1),
             "t"  : NumberLong(1)
         },
         "appliedOpTime"  : {
             "ts"  : Timestamp(1511705333, 1),
             "t"  : NumberLong(1)
         },
         "durableOpTime"  : {
             "ts"  : Timestamp(1511705333, 1),
             "t"  : NumberLong(1)
         }
     },
     "members"  : [
         {
             "_id"  : 0,
             "name"  "172.20.6.10:27017" ,
             "health"  : 1,
             "state"  : 1,
             "stateStr"  "PRIMARY" ,                         #主节点
             "uptime"  : 377,
             "optime"  : {
                 "ts"  : Timestamp(1511705333, 1),
                 "t"  : NumberLong(1)
             },
             "optimeDate"  : ISODate( "2017-11-26T14:08:53Z" ),
             "infoMessage"  "could not find member to sync from" ,
             "electionTime"  : Timestamp(1511705241, 1),
             "electionDate"  : ISODate( "2017-11-26T14:07:21Z" ),
             "configVersion"  : 1,
             "self"  true
         },
         {
             "_id"  : 1,
             "name"  "172.20.6.11:27017" ,
             "health"  : 1,
             "state"  : 2,
             "stateStr"  "SECONDARY" ,                 #secondary节点
             "uptime"  : 109,
             "optime"  : {
                 "ts"  : Timestamp(1511705333, 1),
                 "t"  : NumberLong(1)
             },
             "optimeDurable"  : {
                 "ts"  : Timestamp(1511705333, 1),
                 "t"  : NumberLong(1)
             },
             "optimeDate"  : ISODate( "2017-11-26T14:08:53Z" ),
             "optimeDurableDate"  : ISODate( "2017-11-26T14:08:53Z" ),
             "lastHeartbeat"  : ISODate( "2017-11-26T14:09:00.053Z" ),
             "lastHeartbeatRecv"  : ISODate( "2017-11-26T14:08:59.072Z" ),
             "pingMs"  : NumberLong(0),
             "syncingTo"  "172.20.6.10:27017" ,
             "configVersion"  : 1
         },
         {
             "_id"  : 2,
             "name"  "172.20.6.12:27017" ,                
             "health"  : 1,
             "state"  : 2,
             "stateStr"  "SECONDARY" ,                     #secondary节点
             "uptime"  : 109,
             "optime"  : {
                 "ts"  : Timestamp(1511705333, 1),
                 "t"  : NumberLong(1)
             },
             "optimeDurable"  : {
                 "ts"  : Timestamp(1511705333, 1),
                 "t"  : NumberLong(1)
             },
             "optimeDate"  : ISODate( "2017-11-26T14:08:53Z" ),
             "optimeDurableDate"  : ISODate( "2017-11-26T14:08:53Z" ),
             "lastHeartbeat"  : ISODate( "2017-11-26T14:09:00.053Z" ),
             "lastHeartbeatRecv"  : ISODate( "2017-11-26T14:08:59.054Z" ),
             "pingMs"  : NumberLong(0),
             "syncingTo"  "172.20.6.10:27017" ,
             "configVersion"  : 1
         }
     ],
     "ok"  : 1
}

此时replica set集群已结搭建成功

三、副本集测试

3.1 数据复制测试

在主节点创建数据库,并创建集合,插入文档,在secondary查看文档

图片.png

此时已经完成在主节点创建数据,接下来在secondary查看数据是否已经同步过去。

mongodb默认是从主节点读写数据的,副本节点上不允许读,需要设置副本节点可以读。

1
db.getMongo().setSlaveOk();             #设置副本节点可读

图片.png

此时我们可以测试得到数据,数据已经同步到secondary上,但是无法在secondary上进行数据的增删改操作。

3.2 故障转移测试

目前mongodb-1为主节点,mongdb-2、mongodb-3为副本集节点,此时停掉主节点的mongod服务,进行故障转移测试。

图片.png

宕掉主节点mongodb-1的服务后,我们登录mongodb-2,查看副本集状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
RS:PRIMARY> rs.status()
{
     "set"  "RS" ,
     "date"  : ISODate( "2017-11-26T14:35:03.422Z" ),
     "myState"  : 1,
     "term"  : NumberLong(2),
     "heartbeatIntervalMillis"  : NumberLong(2000),
     "optimes"  : {
         "lastCommittedOpTime"  : {
             "ts"  : Timestamp(1511706901, 1),
             "t"  : NumberLong(2)
         },
         "appliedOpTime"  : {
             "ts"  : Timestamp(1511706901, 1),
             "t"  : NumberLong(2)
         },
         "durableOpTime"  : {
             "ts"  : Timestamp(1511706901, 1),
             "t"  : NumberLong(2)
         }
     },
     "members"  : [
         {
             "_id"  : 0,
             "name"  "172.20.6.10:27017" ,
             "health"  : 0,
             "state"  : 8,
             "stateStr"  "(not reachable/healthy)" ,                 #mongodb-1已经失去连接
             "uptime"  : 0,
             "optime"  : {
                 "ts"  : Timestamp(0, 0),
                 "t"  : NumberLong(-1)
             },
             "optimeDurable"  : {
                 "ts"  : Timestamp(0, 0),
                 "t"  : NumberLong(-1)
             },
             "optimeDate"  : ISODate( "1970-01-01T00:00:00Z" ),
             "optimeDurableDate"  : ISODate( "1970-01-01T00:00:00Z" ),
             "lastHeartbeat"  : ISODate( "2017-11-26T14:35:02.502Z" ),
             "lastHeartbeatRecv"  : ISODate( "2017-11-26T14:32:20.434Z" ),
             "pingMs"  : NumberLong(0),
             "lastHeartbeatMessage"  "Connection refused" ,
             "configVersion"  : -1
         },
         {
             "_id"  : 1,
             "name"  "172.20.6.11:27017" ,
             "health"  : 1,
             "state"  : 1,
             "stateStr"  "PRIMARY" ,                         #mongodb-2为新的主节点
             "uptime"  : 1842,
             "optime"  : {
                 "ts"  : Timestamp(1511706901, 1),
                 "t"  : NumberLong(2)
             },
             "optimeDate"  : ISODate( "2017-11-26T14:35:01Z" ),
             "electionTime"  : Timestamp(1511706750, 1),
             "electionDate"  : ISODate( "2017-11-26T14:32:30Z" ),
             "configVersion"  : 1,
             "self"  true
         },
         {
             "_id"  : 2,
             "name"  "172.20.6.12:27017" ,
             "health"  : 1,
             "state"  : 2,
             "stateStr"  "SECONDARY" ,                     #mongodb-3为secondary节点
             "uptime"  : 1671,
             "optime"  : {
                 "ts"  : Timestamp(1511706901, 1),
                 "t"  : NumberLong(2)
             },
             "optimeDurable"  : {
                 "ts"  : Timestamp(1511706901, 1),
                 "t"  : NumberLong(2)
             },
             "optimeDate"  : ISODate( "2017-11-26T14:35:01Z" ),
             "optimeDurableDate"  : ISODate( "2017-11-26T14:35:01Z" ),
             "lastHeartbeat"  : ISODate( "2017-11-26T14:35:02.354Z" ),
             "lastHeartbeatRecv"  : ISODate( "2017-11-26T14:35:02.730Z" ),
             "pingMs"  : NumberLong(0),
             "syncingTo"  "172.20.6.11:27017" ,
             "configVersion"  : 1
         }
     ],
     "ok"  : 1
}

查看mongodb-2的日志,发现mongodb-1心跳检查已经失去连接,重新进行了主节点选举

图片.png

此时在新节点mongodb-2进行文档插入操作

图片.png

此时上线mongodb-1,查看集群状态与数据是否正常同步到mongodb-1上。

启动mongodb-1的服务,查看集群状态,此时mongodb-1已结成为新的secondary节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
RS:PRIMARY> rs.status()
{
     "set"  "RS" ,
     "date"  : ISODate( "2017-11-27T02:13:41.683Z" ),
     "myState"  : 1,
     "term"  : NumberLong(2),
     "heartbeatIntervalMillis"  : NumberLong(2000),
     "optimes"  : {
         "lastCommittedOpTime"  : {
             "ts"  : Timestamp(1511748812, 1),
             "t"  : NumberLong(2)
         },
         "appliedOpTime"  : {
             "ts"  : Timestamp(1511748812, 1),
             "t"  : NumberLong(2)
         },
         "durableOpTime"  : {
             "ts"  : Timestamp(1511748812, 1),
             "t"  : NumberLong(2)
         }
     },
     "members"  : [
         {
             "_id"  : 0,
             "name"  "172.20.6.10:27017" ,
             "health"  : 1,
             "state"  : 2,
             "stateStr"  "SECONDARY" ,                         #mongodb-1为secondary节点
             "uptime"  : 1945,
             "optime"  : {
                 "ts"  : Timestamp(1511748812, 1),
                 "t"  : NumberLong(2)
             },
             "optimeDurable"  : {
                 "ts"  : Timestamp(1511748812, 1),
                 "t"  : NumberLong(2)
             },
             "optimeDate"  : ISODate( "2017-11-27T02:13:32Z" ),
             "optimeDurableDate"  : ISODate( "2017-11-27T02:13:32Z" ),
             "lastHeartbeat"  : ISODate( "2017-11-27T02:13:41.373Z" ),
             "lastHeartbeatRecv"  : ISODate( "2017-11-27T02:13:40.854Z" ),
             "pingMs"  : NumberLong(0),
             "syncingTo"  "172.20.6.12:27017" ,
             "configVersion"  : 1
         },
         {
             "_id"  : 1,
             "name"  "172.20.6.11:27017" ,
             "health"  : 1,
             "state"  : 1,
             "stateStr"  "PRIMARY" ,                         #mongodb-2为主节点
             "uptime"  : 43760,
             "optime"  : {
                 "ts"  : Timestamp(1511748812, 1),
                 "t"  : NumberLong(2)
             },
             "optimeDate"  : ISODate( "2017-11-27T02:13:32Z" ),
             "electionTime"  : Timestamp(1511706750, 1),
             "electionDate"  : ISODate( "2017-11-26T14:32:30Z" ),
             "configVersion"  : 1,
             "self"  true
         },
         {
             "_id"  : 2,
             "name"  "172.20.6.12:27017" ,                     #mongodb-3为secondary节点
             "health"  : 1,
             "state"  : 2,
             "stateStr"  "SECONDARY" ,
             "uptime"  : 43589,
             "optime"  : {
                 "ts"  : Timestamp(1511748812, 1),
                 "t"  : NumberLong(2)
             },
             "optimeDurable"  : {
                 "ts"  : Timestamp(1511748812, 1),
                 "t"  : NumberLong(2)
             },
             "optimeDate"  : ISODate( "2017-11-27T02:13:32Z" ),
             "optimeDurableDate"  : ISODate( "2017-11-27T02:13:32Z" ),
             "lastHeartbeat"  : ISODate( "2017-11-27T02:13:41.220Z" ),
             "lastHeartbeatRecv"  : ISODate( "2017-11-27T02:13:41.209Z" ),
             "pingMs"  : NumberLong(0),
             "syncingTo"  "172.20.6.11:27017" ,
             "configVersion"  : 1
         }
     ],
     "ok"  : 1
}

查看mongodb-1数据已经正常同步。

图片.png

四、其他

如果考虑到主服务器的复制压力过大,可以制作仲裁节点,其中的仲裁节点不存储数据,只是负责故障转移的群体投票,这样就少了数据复制的压力。

删除节点:

1
rs.remove( "172.20.6.12:27017" )             #删除节点

添加节点

1
2
rs.add( "172.20.6.12:27017" )                 #添加节点
rs.addArb( "172.20.6.12:27017" )                #添加arbiter节点
1
2
3
4
5
6
7
8
9
10
11
12
13
         {
             "_id"  : 2,
             "name"  "172.20.6.12:27017" ,
             "health"  : 1,
             "state"  : 7,
             "stateStr"  "ARBITER" ,                 #arbiter节点
             "uptime"  : 4,
             "lastHeartbeat"  : ISODate( "2017-11-27T02:35:01.634Z" ),
             "lastHeartbeatRecv"  : ISODate( "2017-11-27T02:35:00.637Z" ),
             "pingMs"  : NumberLong(0),
             "syncingTo"  "172.20.6.11:27017" ,
             "configVersion"  : 9
         }










本文转自 KaliArch 51CTO博客,原文链接:http://blog.51cto.com/kaliarch/2044618,如需转载请自行联系原作者
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
存储 NoSQL 网络协议
MongoDB系列-复制集(Replica Set)应用部署(生产、测试、开发环境)
通过在不同的计算机上托管mongod实例来尽可能多地保持成员之间的分离。将虚拟机用于生产部署时,应将每个mongod实例放置在由冗余电源电路和冗余网络路径提供服务的单独主机服务器上,而且尽可能的将副本集的每个成员部署到自己的计算机绑定到标准的MongoDB端口27017。
426 0
|
存储 NoSQL Shell
(1)解锁MongoDB replica set核心姿势
本文倒腾目前大热的MongoDB Replica Set集群,在倒腾的同时串讲一些 MongoDB特性。
(1)解锁MongoDB replica set核心姿势
|
NoSQL 算法 Linux
搭建高可用MongoDB集群(Replica set)
MongoDB基础可参考http://blog.51cto.com/kaliarch/2044423 一、概述 1.1 MongoDB副本集 通俗来讲,mongodb的副本集相当于具有自动故障恢复的主从集群,主从集群和副本集最明显的特征为副本集没有固定的“主节点”,整个集群会通过一定...
10267 0
|
NoSQL Shell MongoDB
【Mongodb】 Replica set 的读写分离
在写多读少的应用中,使用Replica Sets来实现读写分离。通过在连接时指定或者在主库指定slaveOk,由Secondary来分担读的压力,Primary只承担写操作。
742 0