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

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介:

一、副本集(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,如需转载请自行联系原作者




相关实践学习
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
相关文章
|
30天前
|
存储 NoSQL 算法
MongoDB保姆级指南(中):从副本集群、分片集群起航,探索分布式存储的趋势!
本文一起来聊聊MongoDB集群,顺带以MongoDB集群为起点,共同探讨一下分布式存储的发展趋势~
78 15
|
22天前
|
存储 监控 NoSQL
震撼!揭秘高可用 MongoDB 分片集群搭建的神秘魔法,开启数据存储的无敌模式!
【8月更文挑战第9天】在数字化时代,数据至关重要。MongoDB作为流行非关系型数据库,通过搭建高可用分片集群确保系统稳定性和性能。分片技术将大数据集分布于多服务器以实现水平扩展。搭建集群需准备服务器资源,配置环境,启动配置服务器、路由服务器及分片服务器,并设置分片策略。例如,对特定数据库和集合启用分片。此架构适用于高流量应用如大型电商平台,确保数据高效处理和高可用性。搭建过程需持续监控和优化,合理规划分片策略以维持系统稳定运行。
27 3
|
8天前
|
存储 NoSQL MongoDB
今日分享MongoDB一键部署脚本
今日分享MongoDB一键部署脚本
14 0
|
18天前
|
存储 运维 NoSQL
轻松上手:逐步搭建你的高可用MongoDB集群(分片)
【8月更文挑战第13天】在数据激增的背景下,传统单机数据库难以胜任。MongoDB作为流行NoSQL数据库,采用分片技术实现水平扩展,有效处理海量数据。分片将数据分散存储,提高并发处理能力和容错性,是高可用架构基石。构建MongoDB集群需理解shard、config server和router三组件协同工作原理。通过具体实例演示集群搭建流程,包括各组件的启动及配置,确保数据高可用性和系统稳定性。合理规划与实践可构建高效稳定的MongoDB集群,满足业务需求并支持未来扩展。
34 0
|
19天前
|
NoSQL MongoDB Windows
MongoDB 读写分离——Windows MongoDB 副本集配置
MongoDB 读写分离——Windows MongoDB 副本集配置
31 0
|
2月前
|
自然语言处理 运维 NoSQL
MongoDB集群同步
实现 MongoDB Cluster-to-Cluster 即集群同步的工具是:mongosync 详情可参考如下官方文档: https://www.mongodb.com/zh-cn/docs/cluster-to-cluster-sync/current/quickstart/ 以上这个地址的文档一看就是机器翻译的,可能有不恰当的地方,但基本可参考使用。 以下是本次在某项目地配置集群同步的简要步骤,可参考使用。
60 6
|
3月前
|
存储 监控 NoSQL
MongoDB 副本集:构建可靠的数据备份与高可用性系统
MongoDB 副本集:构建可靠的数据备份与高可用性系统
|
7天前
|
运维 监控 NoSQL
【MongoDB 复制集秘籍】Secondary 同步慢怎么办?深度解析与实战指南,让你的数据库飞速同步!
【8月更文挑战第24天】本文通过一个具体案例探讨了MongoDB复制集中Secondary成员同步缓慢的问题。现象表现为数据延迟增加,影响业务运行。经分析,可能的原因包括硬件资源不足、网络状况不佳、复制日志错误等。解决策略涵盖优化硬件(如增加内存、升级CPU)、调整网络配置以减少延迟以及优化MongoDB配置(例如调整`oplogSize`、启用压缩)。通过这些方法可有效提升同步效率,保证系统的稳定性和性能。
22 4
|
11天前
|
监控 NoSQL MongoDB
MongoDB数据库的索引管理技巧
【8月更文挑战第20天】MongoDB数据库的索引管理技巧
34 1
|
11天前
|
监控 NoSQL MongoDB
mongodb数据库 使用技巧
【8月更文挑战第20天】mongodb数据库 使用技巧
29 1
下一篇
云函数