搭建高可用MongoDB集群——副本集部署

简介:

一、副本集(repl set)简介


    早期版本使用 master-slave 模式,一主一从和 MySQL 类似,但 slave 在此架构中为只读,当主库宕机后,从库不能自动切换为主。目前已经淘汰了 master-slave 模式,改为副本集,这种模式下有一个主(primary),和多个从(secondary)只读。支持给它们设置权重,当主宕掉后,权重最高的切换为主。

    在此架构中还可以建立一个仲裁(arbiter)的角色,它只负责裁决,而不存储数据。并且此架构读写数据都在主上,优点在于能够自动的切换角色,但是缺点在于不能实现让用户的访问由原来的主自动切换到现在的主,这个还需手动切换来实现负载均衡的目的;当然这个我们可以写一个监控脚本,让程序自动的帮我们切换到要访问的主的IP即可。

    最后应该注意一点,要想使用副本集,从的mongodb的数据必须都是空的,要不然执行  rs.initiate()命令时会提示因存在数据而导致初始化不成功(has data already, cannot initiate set)。

 


二、副本集的架构


1、主要流程

wKiom1ZoBZ2wO-JeAAGsLXU9Hqo857.png

2、裁决机制

wKiom1ZoBzuTazhQAALKnyTvjg0240.png

三、副本集的搭建


1、准备工作

准备好以下三台机器

主(primary):192.168.0.103

从(secondary1):192.168.0.109

从(secondary2):192.168.0.120

这三台机器全部都安装好 MongoDB ,安装的详细过程参考我上篇文章MongoDB的安装:

http://msiyuetian.blog.51cto.com/8637744/1720559


2、编辑配置文件

1)对三台机器的配置文件都进行以下修改

# vim /etc/mongod.conf

找到:

#replication:

修改为:

replication:

  oplogSizeMB: 20    

  replSetName: tpp

说明:oplogSizeMB 指 oplog 大小;replSetName 指副本集名称。注意格式是前面空两格,冒号后空一格。


2)然后重启三台 MongoDB

# /etc/init.d/mongod restart

若重启失败,用 mongod -f /etc/mongod.conf 命令开启。


3)连接主

[root@primary ~]# mongo

MongoDB shell version: 3.0.7

connecting to: test

> use admin

switched to db admin

> config={_id:"tpp",members:[{_id:0,host:"192.168.0.103:27017"},{_id:1,host:"192.168.0.109:27017"},{_id:2,host:"192.168.0.120:27017"}]}

{

        "_id" : "tpp",

        "members" : [

                {

                        "_id" : 0,

                        "host" : "192.168.0.103:27017"

                },

                {

                        "_id" : 1,

                        "host" : "192.168.0.109:27017"

                },

                {

                        "_id" : 2,

                        "host" : "192.168.0.120:27017"

                }

        ]

}

> rs.initiate(config)                                  //初始化

{ "ok" : 1 }

tpp:OTHER> rs.status()                             //查看状态

{

        "set" : "tpp",

        "date" : ISODate("2015-12-12T23:19:04.253Z"),

        "myState" : 1,

        "members" : [

                {

                        "_id" : 0,

                        "name" : "192.168.0.103:27017",

                        "health" : 1,

                        "state" : 1,

                        "stateStr" : "PRIMARY",

                        "uptime" : 10034,

                        "optime" : Timestamp(1449961495, 1),

                        "optimeDate" : ISODate("2015-12-12T23:04:55Z"),

                        "electionTime" : Timestamp(1449961497, 1),

                        "electionDate" : ISODate("2015-12-12T23:04:57Z"),

                        "configVersion" : 1,

                        "self" : true

                },

                {

                        "_id" : 1,

                        "name" : "192.168.0.109:27017",

                        "health" : 1,

                        "state" : 2,

                        "stateStr" : "SECONDARY",

                        "uptime" : 848,

                        "optime" : Timestamp(1449961495, 1),

                        "optimeDate" : ISODate("2015-12-12T23:04:55Z"),

                        "lastHeartbeat" : ISODate("2015-12-12T23:19:04.073Z"),

                        "lastHeartbeatRecv" : ISODate("2015-12-12T23:19:03.796Z"),

                        "pingMs" : 0,

                        "configVersion" : 1

                },

                {

                        "_id" : 2,

                        "name" : "192.168.0.120:27017",

                        "health" : 1,

                        "state" : 2,

                        "stateStr" : "SECONDARY",

                        "uptime" : 848,

                        "optime" : Timestamp(1449961495, 1),

                        "optimeDate" : ISODate("2015-12-12T23:04:55Z"),

                        "lastHeartbeat" : ISODate("2015-12-12T23:19:04.073Z"),

                        "lastHeartbeatRecv" : ISODate("2015-12-12T23:19:03.831Z"),

                        "pingMs" : 0,

                        "configVersion" : 1

                }

        ],

        "ok" : 1

}

注意:两个从上的状态为 "stateStr" : "SECONDARY",若为 "STARTUP",则需要进行如下操作:

> var config={_id:"tpp",members:[{_id:0,host:"192.168.0.103:27017"},{_id:1,host:"192.168.0.109:27017"},{_id:2,host:"192.168.0.120:27017"}]}

> rs.initiate(config)

查看到以上信息就说明配置成功了,我们也会发现主上前缀变为 tpp:PRIMARY

tpp:PRIMARY>

而两个从上都变为 tpp:SECONDARY

[root@secondary1 ~]# mongo

MongoDB shell version: 3.0.7

connecting to: test

tpp:SECONDARY>


三、副本集的测试


测试1:同步数据测试

1)主上建库、建集合

tpp:PRIMARY> use mydb

switched to db mydb

tpp:PRIMARY> db.createCollection('test1')

{ "ok" : 1 }

tpp:PRIMARY> show dbs

local  0.078GB

mydb   0.078GB

2)从上查看

tpp:SECONDARY> show dbs                                 //会报错,因为secondary节点默认不可读

2015-12-13T07:44:46.256+0800 E QUERY    Error: listDatabases failed:{ "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" }

    at Error (<anonymous>)

    at Mongo.getDBs (src/mongo/shell/mongo.js:47:15)

    at shellHelper.show (src/mongo/shell/utils.js:630:33)

    at shellHelper (src/mongo/shell/utils.js:524:36)

    at (shellhelp2):1:1 at src/mongo/shell/mongo.js:47

tpp:SECONDARY> rs.slaveOk()                               //执行该命令后就可以查询了

tpp:SECONDARY> show dbs

local  0.078GB

mydb   0.078GB

注意:通过上面的命令只能临时查询,下次再通过mongo命令进入后查询仍会报错,所以可以修改文件

[root@secondary2 ~]# vi ~/.mongorc.js                  //写入下面这行

rs.slaveOk();

[root@secondary2 ~]# service mongod restart

[root@secondary2 ~]# mongo

MongoDB shell version: 3.0.7

connecting to: test

tpp:SECONDARY> show dbs

local  0.078GB

mydb   0.078GB


测试2:模拟主宕机,从变成主

1)在主上查看所有机器的权重

tpp:PRIMARY> rs.config()

{

        "_id" : "tpp",

        "version" : 1,

        "members" : [

                {

                        "_id" : 0,

                        "host" : "192.168.0.103:27017",

                        "arbiterOnly" : false,

                        "buildIndexes" : true,

                        "hidden" : false,

                        "priority" : 1,

                        "tags" : {


                        },

                        "slaveDelay" : 0,

                        "votes" : 1

                },

                {

                        "_id" : 1,

                        "host" : "192.168.0.109:27017",

                        "arbiterOnly" : false,

                        "buildIndexes" : true,

                        "hidden" : false,

                        "priority" : 1,

                        "tags" : {


                        },

                        "slaveDelay" : 0,

                        "votes" : 1

                },

                {

                        "_id" : 2,

                        "host" : "192.168.0.120:27017",

                        "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,如果任何一个权重设置为比其他的高,则该台机器立马会切换为primary角色,所以要我们预设三台机器的权重。


2)设置权重

预设主(0.103)权重为3、从(0.109)权重为2、从(0.120)权重为1(默认值可不用重新赋值)。

在主上执行下面命令:

tpp:PRIMARY> cfg=rs.config()                            //重新赋值

tpp:PRIMARY> cfg.members[0].priority = 3

3

tpp:PRIMARY> cfg.members[1].priority = 2

2

tpp:PRIMARY> rs.reconfig(cfg)                           //重新加载配置

{ "ok" : 1 }

tpp:PRIMARY> rs.config()                                   //重新查看权重已改变

{

        "_id" : "tpp",

        "version" : 2,

        "members" : [

                {

                        "_id" : 0,

                        "host" : "192.168.0.103:27017",

                        "arbiterOnly" : false,

                        "buildIndexes" : true,

                        "hidden" : false,

                        "priority" : 3,

                        "tags" : {


                        },

                        "slaveDelay" : 0,

                        "votes" : 1

                },

                {

                        "_id" : 1,

                        "host" : "192.168.0.109:27017",

                        "arbiterOnly" : false,

                        "buildIndexes" : true,

                        "hidden" : false,

                        "priority" : 2,

                        "tags" : {


                        },

                        "slaveDelay" : 0,

                        "votes" : 1

                },

                {

                        "_id" : 2,

                        "host" : "192.168.0.120:27017",

                        "arbiterOnly" : false,

                        "buildIndexes" : true,

                        "hidden" : false,

                        "priority" : 1,

                        "tags" : {


                        },

                        "slaveDelay" : 0,

                        "votes" : 1

                }

        ],

        "settings" : {

                "chainingAllowed" : true,

                "heartbeatTimeoutSecs" : 10,

                "getLastErrorModes" : {


                },

                "getLastErrorDefaults" : {

                        "w" : 1,

                        "wtimeout" : 0

                }

        }

}

3)禁掉主上的mongod服务,模拟主宕机

[root@primary ~]# iptables -I INPUT -p tcp --dport 27017 -j DROP

执行上面命令以后,在权重大的从(0.109)上敲下回车,从的角色立马由SECONDARY变为PRIMARY:

tpp:SECONDARY>

tpp:PRIMARY>

tpp:PRIMARY> rs.status()                          //查看状态

{

        "set" : "tpp",

        "date" : ISODate("2015-12-13T00:29:11.161Z"),

        "myState" : 1,

        "members" : [

                {

                        "_id" : 0,

                        "name" : "192.168.0.103:27017",

                        "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-13T00:29:07.659Z"),

                        "lastHeartbeatRecv" : ISODate("2015-12-13T00:29:09.708Z"),

                        "pingMs" : 0,

                        "lastHeartbeatMessage" : "Failed attempt to connect to 192.168.0.103:27017; couldn't connect to server 192.168.0.103:27017 (192.168.0.103), connection attempt failed",

                        "configVersion" : -1

                },

                {

                        "_id" : 1,

                        "name" : "192.168.0.109:27017",

                        "health" : 1,

                        "state" : 1,

                        "stateStr" : "PRIMARY",

                        "uptime" : 5165,

                        "optime" : Timestamp(1449965758, 1),

                        "optimeDate" : ISODate("2015-12-13T00:15:58Z"),

                        "electionTime" : Timestamp(1449966238, 1),

                        "electionDate" : ISODate("2015-12-13T00:23:58Z"),

                        "configVersion" : 2,

                        "self" : true

                },

                {

                        "_id" : 2,

                        "name" : "192.168.0.120:27017",

                        "health" : 1,

                        "state" : 2,

                        "stateStr" : "SECONDARY",

                        "uptime" : 5053,

                        "optime" : Timestamp(1449965758, 1),

                        "optimeDate" : ISODate("2015-12-13T00:15:58Z"),

                        "lastHeartbeat" : ISODate("2015-12-13T00:29:09.922Z"),

                        "lastHeartbeatRecv" : ISODate("2015-12-13T00:29:09.980Z"),

                        "pingMs" : 0,

                        "configVersion" : 2

                }

        ],

        "ok" : 1

}

注意:由上面可发现原来的主(0.103)已处于不健康状态(失连),而原来权重高的从(0.109)的角色变为PRIMARY,权重低的从角色不变。不过要想让用户识别新主,还需手动指定读库的目标server。


测试3:原主恢复,新主写入的数据是否同步

1)新主建库、建集合

tpp:PRIMARY> use mydb2

switched to db mydb2

tpp:PRIMARY> db.createCollection('test2')

{ "ok" : 1 }

tpp:PRIMARY> show dbs

local  0.078GB

mydb   0.078GB

mydb2  0.078GB

2)删除规则,恢复原主

[root@primary ~]# iptables -D INPUT -p tcp --dport 27017 -j DROP      

新主上按下回车,新主角色由 PRIMARY 变为 SECONDARY,并输出如下信息:

tpp:PRIMARY>

2015-12-13T08:58:37.143+0800 I NETWORK  DBClientCursor::init call() failed

2015-12-13T08:58:37.145+0800 I NETWORK  trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed

2015-12-13T08:58:37.146+0800 I NETWORK  reconnect 127.0.0.1:27017 (127.0.0.1) ok

tpp:SECONDARY>



3)登入原主,查看数据库信息


[root@primary ~]# mongo

MongoDB shell version: 3.0.7

connecting to: test

tpp:PRIMARY> show dbs

local  0.078GB

mydb   0.078GB

mydb2  0.078GB

说明:由上面可知,当权重更高的原主恢复运行了,在新主期间写入的新数据同样同步到了原主上,即副本集成功实现了负载均衡的目的。








      本文转自 M四月天 51CTO博客,原文链接:http://blog.51cto.com/msiyuetian/1722406,如需转载请自行联系原作者




相关文章
|
11月前
|
存储 NoSQL 安全
客户说|知乎核心业务MongoDB集群的平滑上云迁移实践
客户说|知乎核心业务MongoDB集群的平滑上云迁移实践
419 0
|
存储 NoSQL MongoDB
MongoDB 复制(副本集)
10月更文挑战第17天
229 2
MongoDB 复制(副本集)
|
NoSQL 容灾 MongoDB
MongoDB主备副本集方案:两台服务器使用非对称部署的方式实现高可用与容灾备份
在资源受限的情况下,为了实现MongoDB的高可用性,本文探讨了两种在两台服务器上部署MongoDB的方案。方案一是通过主备身份轮换,即一台服务器作为主节点,另一台同时部署备节点和仲裁节点;方案二是利用`priority`设置实现自动主备切换。两者相比,方案二自动化程度更高,适合追求快速故障恢复的场景,而方案一则提供了更多的手动控制选项。文章最后对比了这两种方案与标准三节点副本集的优缺点,指出三节点方案在高可用性和数据一致性方面表现更佳。
1285 5
|
存储 NoSQL Shell
MongoDB复制(副本集)总结
这篇文章是关于MongoDB副本集的总结,包括复制原理、设置副本集、案例分析等内容。
389 1
|
存储 NoSQL MongoDB
【赵渝强老师】部署MongoDB复制集
本文介绍了如何在单个节点上搭建MongoDB复制集环境,通过监听不同端口实现多节点配置。详细步骤包括创建数据目录、编辑配置文件、启动节点、初始化复制集、查看状态以及测试主从库的读写操作。文中还提供了视频讲解和代码示例,帮助读者更好地理解和操作。
357 0
|
存储 NoSQL MongoDB
今日分享MongoDB一键部署脚本
今日分享MongoDB一键部署脚本
169 0
|
存储 运维 NoSQL
轻松上手:逐步搭建你的高可用MongoDB集群(分片)
【8月更文挑战第13天】在数据激增的背景下,传统单机数据库难以胜任。MongoDB作为流行NoSQL数据库,采用分片技术实现水平扩展,有效处理海量数据。分片将数据分散存储,提高并发处理能力和容错性,是高可用架构基石。构建MongoDB集群需理解shard、config server和router三组件协同工作原理。通过具体实例演示集群搭建流程,包括各组件的启动及配置,确保数据高可用性和系统稳定性。合理规划与实践可构建高效稳定的MongoDB集群,满足业务需求并支持未来扩展。
864 0
|
6月前
|
NoSQL MongoDB 数据库
数据库数据恢复—MongoDB数据库数据恢复案例
MongoDB数据库数据恢复环境: 一台操作系统为Windows Server的虚拟机上部署MongoDB数据库。 MongoDB数据库故障: 工作人员在MongoDB服务仍然开启的情况下将MongoDB数据库文件拷贝到其他分区,数据复制完成后将MongoDB数据库原先所在的分区进行了格式化操作。 结果发现拷贝过去的数据无法使用。管理员又将数据拷贝回原始分区,MongoDB服务仍然无法使用,报错“Windows无法启动MongoDB服务(位于 本地计算机 上)错误1067:进程意外终止。”
|
6月前
|
缓存 NoSQL Linux
在CentOS 7系统中彻底移除MongoDB数据库的步骤
以上步骤完成后,MongoDB应该会从您的CentOS 7系统中被彻底移除。在执行上述操作前,请确保已经备份好所有重要数据以防丢失。这些步骤操作需要一些基本的Linux系统管理知识,若您对某一步骤不是非常清楚,请先进行必要的学习或咨询专业人士。在执行系统级操作时,推荐在实施前创建系统快照或备份,以便在出现问题时能够恢复到原先的状态。
568 79

推荐镜像

更多