设为首页 收藏本站
查看: 862|回复: 0

[经验分享] 搭建高可用MongoDB集群——副本集部署

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-12-14 10:25:28 | 显示全部楼层 |阅读模式
一、副本集(repl set)简介

    早期版本使用 master-slave 模式,一主一从和 MySQL 类似,但 slave 在此架构中为只读,当主库宕机后,从库不能自动切换为主。目前已经淘汰了 master-slave 模式,改为副本集,这种模式下有一个主(primary),和多个从(secondary)只读。支持给它们设置权重,当主宕掉后,权重最高的切换为主。
    在此架构中还可以建立一个仲裁(arbiter)的角色,它只负责裁决,而不存储数据。并且此架构读写数据都在主上,优点在于能够自动的切换角色,但是缺点在于不能实现让用户的访问由原来的主自动切换到现在的主,这个还需手动切换来实现负载均衡的目的;当然这个我们可以写一个监控脚本,让程序自动的帮我们切换到要访问的主的IP即可。
    最后应该注意一点,要想使用副本集,主从的mongodb的数据必须都是空的,要不然执行  rs.initiate()命令时会提示因存在数据而不能初始化成功(has data already, cannot initiate set)。


二、副本集的架构

1、主要流程

wKiom1ZoBZ2wO-JeAAGsLXU9Hqo857.jpg
2、裁决机制
wKiom1ZoBzuTazhQAALKnyTvjg0240.jpg
三、副本集的搭建

1、准备工作

准备好以下三台机器
主(primary):192.168.0.103
从(secondary1):192.168.0.109
从(secondary2):192.168.0.120
这三台机器全部都安装好 MongoDB

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)连接主
[iyunv@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
[iyunv@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命令进入后查询仍会报错,所以可以修改文件
[iyunv@secondary2 ~]# vi ~/.mongorc.js                  //写入下面这行
rs.slaveOk();
[iyunv@secondary2 ~]# service mongod restart
[iyunv@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服务,模拟主宕机

[iyunv@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)删除规则,恢复原主

[iyunv@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)登入原主,查看数据库信息
[iyunv@primary ~]# mongo
MongoDB shell version: 3.0.7
connecting to: test
tpp:PRIMARY> show dbs
local  0.078GB
mydb   0.078GB
mydb2  0.078GB
说明:由上面可知,当权重更高的原主恢复运行了,在新主期间写入的新数据同样同步到了原主上,即副本集成功实现了负载均衡的目的。



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-150864-1-1.html 上篇帖子: MongoDB备份和恢复 下篇帖子: 实战mongodb3.06 Relica Sets+sharding集群
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表