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

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: MongoDB基础可参考http://blog.51cto.com/kaliarch/2044423一、概述1.1 MongoDB副本集通俗来讲,mongodb的副本集相当于具有自动故障恢复的主从集群,主从集群和副本集最明显的特征为副本集没有固定的“主节点”,整个集群会通过一定...

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

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

定义配置文件

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

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

图片.png

2.3 副本集部署

挑选任意一台mongodb进行登录

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

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默认是从主节点读写数据的,副本节点上不允许读,需要设置副本节点可以读。

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

图片.png

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

3.2 故障转移测试

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

图片.png

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

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节点。

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

四、其他

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

删除节点:

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

添加节点

rs.add("172.20.6.12:27017")                #添加节点
rs.addArb("172.20.6.12:27017")               #添加arbiter节点
        {
            "_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
        }


相关实践学习
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
目录
相关文章
|
2月前
|
Kubernetes Cloud Native 流计算
Flink-12 Flink Java 3分钟上手 Kubernetes云原生下的Flink集群 Rancher Stateful Set yaml详细 扩容缩容部署 Docker容器编排
Flink-12 Flink Java 3分钟上手 Kubernetes云原生下的Flink集群 Rancher Stateful Set yaml详细 扩容缩容部署 Docker容器编排
77 3
|
4月前
|
存储 NoSQL 算法
MongoDB保姆级指南(中):从副本集群、分片集群起航,探索分布式存储的趋势!
本文一起来聊聊MongoDB集群,顺带以MongoDB集群为起点,共同探讨一下分布式存储的发展趋势~
259 15
|
4月前
|
存储 监控 NoSQL
震撼!揭秘高可用 MongoDB 分片集群搭建的神秘魔法,开启数据存储的无敌模式!
【8月更文挑战第9天】在数字化时代,数据至关重要。MongoDB作为流行非关系型数据库,通过搭建高可用分片集群确保系统稳定性和性能。分片技术将大数据集分布于多服务器以实现水平扩展。搭建集群需准备服务器资源,配置环境,启动配置服务器、路由服务器及分片服务器,并设置分片策略。例如,对特定数据库和集合启用分片。此架构适用于高流量应用如大型电商平台,确保数据高效处理和高可用性。搭建过程需持续监控和优化,合理规划分片策略以维持系统稳定运行。
40 3
|
5月前
|
自然语言处理 运维 NoSQL
MongoDB集群同步
实现 MongoDB Cluster-to-Cluster 即集群同步的工具是:mongosync 详情可参考如下官方文档: https://www.mongodb.com/zh-cn/docs/cluster-to-cluster-sync/current/quickstart/ 以上这个地址的文档一看就是机器翻译的,可能有不恰当的地方,但基本可参考使用。 以下是本次在某项目地配置集群同步的简要步骤,可参考使用。
91 6
|
4月前
|
存储 运维 NoSQL
轻松上手:逐步搭建你的高可用MongoDB集群(分片)
【8月更文挑战第13天】在数据激增的背景下,传统单机数据库难以胜任。MongoDB作为流行NoSQL数据库,采用分片技术实现水平扩展,有效处理海量数据。分片将数据分散存储,提高并发处理能力和容错性,是高可用架构基石。构建MongoDB集群需理解shard、config server和router三组件协同工作原理。通过具体实例演示集群搭建流程,包括各组件的启动及配置,确保数据高可用性和系统稳定性。合理规划与实践可构建高效稳定的MongoDB集群,满足业务需求并支持未来扩展。
106 0
|
6月前
|
存储 负载均衡 NoSQL
MongoDB的架构设计基于三种集群模式
【6月更文挑战第5天】MongoDB的架构设计基于三种集群模式
234 3
|
2月前
|
存储 关系型数据库 MySQL
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB区别,适用场景
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB——特点、性能、扩展性、安全性、适用场景比较
|
3月前
|
存储 NoSQL 关系型数据库
非关系型数据库-MongoDB技术(二)
非关系型数据库-MongoDB技术(二)
|
1月前
|
NoSQL Cloud Native atlas
探索云原生数据库:MongoDB Atlas 的实践与思考
【10月更文挑战第21天】本文探讨了MongoDB Atlas的核心特性、实践应用及对云原生数据库未来的思考。MongoDB Atlas作为MongoDB的云原生版本,提供全球分布式、完全托管、弹性伸缩和安全合规等优势,支持快速部署、数据全球化、自动化运维和灵活定价。文章还讨论了云原生数据库的未来趋势,如架构灵活性、智能化运维和混合云支持,并分享了实施MongoDB Atlas的最佳实践。
|
2月前
|
NoSQL Cloud Native atlas
探索云原生数据库:MongoDB Atlas 的实践与思考
【10月更文挑战第20天】本文探讨了MongoDB Atlas的核心特性、实践应用及对未来云原生数据库的思考。MongoDB Atlas作为云原生数据库服务,具备全球分布、完全托管、弹性伸缩和安全合规等优势,支持快速部署、数据全球化、自动化运维和灵活定价。文章还讨论了实施MongoDB Atlas的最佳实践和职业心得,展望了云原生数据库的发展趋势。