MongoDB 复制集(Replica Set)

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
日志服务 SLS,月写入数据量 50GB 1个月
简介: 复制集(replica Set)或者副本集是MongoDB的核心高可用特性之一,它基于主节点的oplog日志持续传送到辅助节点,并重放得以实现主从节点一致。

复制集(replica Set)或者副本集是MongoDB的核心高可用特性之一,它基于主节点的oplog日志持续传送到辅助节点,并重放得以实现主从节点一致。再结合心跳机制,当感知到主节点不可访问或宕机的情形下,辅助节点通过选举机制来从剩余的辅助节点中推选一个新的主节点从而实现自动切换。这个特性与MySQL MHA实现原理一样。本文主要描述MongoDB复制集并给出创建复制集示例以及完成自动切换。

一、复制集相关概念

复制集
    复制是在多台服务器之间同步数据的过程,由一组Mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点
    Mongodb Driver(客户端)的所有数据都写入Primary,Secondary从Primary同步写入的数据
    通过上述方式来保持复制集内所有成员存储相同的数据集,提供数据的高可用

复制的目的
        Failover (故障转移,故障切换,故障恢复)
        Redundancy(数据冗余)
        避免单点,用于灾难时恢复,报表处理,提升数据可用性
        读写分离,分担读压力
        对用户透明的系统维护升级

复制集的原理
        主节点记录所有的变更到oplog日志
        辅助节点(Secondary)复制主节点的oplog日志并且将这些日志在辅助节点进行重放(做)
        各个节点之间会定期发送心跳信息,一旦主节点宕机,则触发选举一个新的主节点,剩余的辅助节点指向新的主
        10s内各辅助节点无法感知主节点的存在,则开始触发选举
        通常1分钟内完成主辅助节点切换,10-30s内感知主节点故障,10-30s内完成选举及切换       

复制≠备份
        用户恢复数据,防止数据丢失,实现灾难恢复
        人为误操作导致数据删除,程序Bug导致数据损坏等

Primary
        首要复制节点,由选举产生,提供读写服务的节点,产生oplog日志

Secondary       
        备用(辅助)复制节点,Secondary可以提供读服务,增加Secondary节点可以提供复制集的读服务能力
        在故障时,备用节点可以根据设定的优先级别提升为首要节点。提升了复制集的可用性

Arbiter
        Arbiter节点只参与投票,不能被选为Primary,并且不从Primary同步数据     
        Arbiter本身不存储数据,是非常轻量级的服务。
        当复制集成员为偶数时,最好加入一个Arbiter节点,以提升复制集可用性

复制集示意图
这里写图片描述

二、创建复制集

# cat /etc/redhat-release 
CentOS release 6.7 (Final)
# mongod --version
db version v3.0.12
git version: 33934938e0e95d534cebbaff656cde916b9c3573

创建实例对应的数据目录
# mkdir -pv /data/{n1,n2,n3}

# mongod --replSet repSetTest --dbpath /data/n1 --logpath /data/n1/n1.log \
> --port 27000 --smallfiles --oplogSize 128 --fork
# mongod --replSet repSetTest --dbpath /data/n2 --logpath /data/n2/n2.log  \
> --port 27001 --smallfiles --oplogSize 128 --fork
# mongod --replSet repSetTest --dbpath /data/n3 --logpath /data/n3/n3.log  \
> --port 27002 --smallfiles --oplogSize 128 --fork

查看相应的端口
# netstat -nltp|grep mongod
tcp        0      0 0.0.0.0:27000               0.0.0.0:*                   LISTEN      5765/mongod         
tcp        0      0 0.0.0.0:27001               0.0.0.0:*                   LISTEN      5781/mongod         
tcp        0      0 0.0.0.0:27002               0.0.0.0:*                   LISTEN      5810/mongod  

连接到第一个实例
# mongo localhost:27000
MongoDB shell version: 3.0.12
connecting to: localhost:27000/test
> db.person.insert({name:'Fred', age:35})    //提示当前节点非master节点
WriteResult({ "writeError" : { "code" : undefined, "errmsg" : "not master" } })
> 
//下面我们添加复制集的配置文件
> cfg = {
...  '_id':'repSetTest',
...  'members':[
...  {'_id':0, 'host': 'localhost:27000'},
...  {'_id':1, 'host': 'localhost:27001'},
...  {'_id':2, 'host': 'localhost:27002'}
...  ]
... }
{
        "_id" : "repSetTest",
        "members" : [
                {
                        "_id" : 0,
                        "host" : "localhost:27000"
                },
                {
                        "_id" : 1,
                        "host" : "localhost:27001"
                },
                {
                        "_id" : 2,
                        "host" : "localhost:27002"
                }
        ]
}

//复制集通过replSetInitiate命令(或mongo shell的rs.initiate())进行初始化
//初始化后各个成员间开始发送心跳消息,并发起Priamry选举操作
//获得『大多数』成员投票支持的节点,会成为Primary,其余节点成为Secondary。
//通常建议将复制集成员数量设置为奇数,以确保在复制集故障的时候能够正确选举出Primary。
//对于复制集故障导致无法正确选举得到Primary的情形下,复制集将无法提供写服务,处于只读状态

> rs.initiate(cfg)  //初始化配置文件
{ "ok" : 1 }

//查看状态,以下提示27000为主节点,其余2个端口为辅助节点
repSetTest:OTHER> rs.status() 
{
        "set" : "repSetTest",
        "date" : ISODate("2016-08-30T05:41:15.302Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "localhost:27000",
                        "health" : 1,             //健康状态:OK
                        "state" : 1,
                        "stateStr" : "PRIMARY",  //当前为主节点
                        "uptime" : 118,
                        "optime" : Timestamp(1472535666, 1),
                        "optimeDate" : ISODate("2016-08-30T05:41:06Z"),
                        "electionTime" : Timestamp(1472535670, 1),
                        "electionDate" : ISODate("2016-08-30T05:41:10Z"),
                        "configVersion" : 1,
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "localhost:27001",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 9,
                        "optime" : Timestamp(1472535666, 1),
                        "optimeDate" : ISODate("2016-08-30T05:41:06Z"),
                        "lastHeartbeat" : ISODate("2016-08-30T05:41:14.030Z"),
                        "lastHeartbeatRecv" : ISODate("2016-08-30T05:41:14.048Z"),
                        "pingMs" : 0,
                        "configVersion" : 1
                },
                {
                        "_id" : 2,
                        "name" : "localhost:27002",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 9,
                        "optime" : Timestamp(1472535666, 1),
                        "optimeDate" : ISODate("2016-08-30T05:41:06Z"),
                        "lastHeartbeat" : ISODate("2016-08-30T05:41:14.030Z"),
                        "lastHeartbeatRecv" : ISODate("2016-08-30T05:41:14.057Z"),
                        "pingMs" : 0,
                        "configVersion" : 1
                }
        ],
        "ok" : 1
}


//使用isMaster()函数寻找谁是Master
repSetTest:PRIMARY> db.isMaster()  
{
        "setName" : "repSetTest",
        "setVersion" : 1,
        "ismaster" : true,
        "secondary" : false,
        "hosts" : [
                "localhost:27000",
                "localhost:27001",
                "localhost:27002"
        ],
        "primary" : "localhost:27000",
        "me" : "localhost:27000",
        "electionId" : ObjectId("57c51c76d5963b4abbd1d72f"),
        "maxBsonObjectSize" : 16777216,
        "maxMessageSizeBytes" : 48000000,
        "maxWriteBatchSize" : 1000,
        "localTime" : ISODate("2016-08-30T05:42:12.328Z"),
        "maxWireVersion" : 3,
        "minWireVersion" : 0,
        "ok" : 1
}

//连接到primary或者secondary
# mongo localhost:27000
# mongo localhost:27001
# mongo localhost:27002

//在主复制集上插入文档
repSetTest:PRIMARY> db.replTest.insert({_id:1, value:'abc'})
WriteResult({ "nInserted" : 1 })

repSetTest:PRIMARY> db.replTest.findOne()
{ "_id" : 1, "value" : "abc" }


//连接到从库查询,提示not master
# mongo localhost:27001
MongoDB shell version: 3.0.12
connecting to: localhost:27001/test

repSetTest:SECONDARY> db.replTest.find()
Error: error: { "$err" : "not master and slaveOk=false", "code" : 13435 }

//开启slave查询
repSetTest:SECONDARY> rs.slaveOk(true)    
repSetTest:SECONDARY> db.replTest.find()
{ "_id" : 1, "value" : "abc" }

//辅助复制集不支持CUD
repSetTest:SECONDARY> db.replTest.insert({_id:2,value:"cde"})
WriteResult({ "writeError" : { "code" : undefined, "errmsg" : "not master" } })

三、复制集自动故障转移

# netstat -nltp|grep 27000
tcp        0      0 0.0.0.0:27000               0.0.0.0:*                   LISTEN      13555/mongod        

# kill -9 13555
# mongo localhost:27000
connecting to: localhost:27000/test
2016-08-30T13:44:55.671+0800 W NETWORK  Failed to connect to 127.0.0.1:27000,
 reason: errno:111 Connection refused
2016-08-30T13:44:55.672+0800 E QUERY    Error: couldn't connect to server localhost:27000 (127.0.0.1), 
connection attempt failed
    at connect (src/mongo/shell/mongo.js:181:14)
    at (connect):1:6 at src/mongo/shell/mongo.js:181
exception: connect failed

//连接到27001端口,如下面的查询,27000连接失败,27001已经提升为PRIMARY
# mongo localhost:27001
MongoDB shell version: 3.0.12
connecting to: localhost:27001/test
repSetTest:PRIMARY> rs.status()
{
        "set" : "repSetTest",
        "date" : ISODate("2016-08-30T05:45:39.018Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "localhost:27000",
                        "health" : 0,
                        "state" : 8,
                        "stateStr" : "(not reachable/healthy)", //此时提示27000不可达
                        "uptime" : 0,
                        "optime" : Timestamp(0, 0),
                        "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                        "lastHeartbeat" : ISODate("2016-08-30T05:45:38.378Z"),
                        "lastHeartbeatRecv" : ISODate("2016-08-30T05:44:48.263Z"),
                        "pingMs" : 0,
                        "lastHeartbeatMessage" : "Failed attempt to connect to localhost:27000; 
                        couldn't connect to server localhost:27000 (127.0.0.1), connection attempt failed",
                        "configVersion" : -1
                },
                {
                        "_id" : 1,
                        "name" : "localhost:27001",   // Author : Leshami
                        "health" : 1,                 // Blog   : http://blog.csdn.net/leshami
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 372,
                        "optime" : Timestamp(1472535845, 2),
                        "optimeDate" : ISODate("2016-08-30T05:44:05Z"),
                        "electionTime" : Timestamp(1472535890, 1),
                        "electionDate" : ISODate("2016-08-30T05:44:50Z"),
                        "configVersion" : 1,
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "localhost:27002",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 272,
                        "optime" : Timestamp(1472535845, 2),
                        "optimeDate" : ISODate("2016-08-30T05:44:05Z"),
                        "lastHeartbeat" : ISODate("2016-08-30T05:45:38.356Z"),
                        "lastHeartbeatRecv" : ISODate("2016-08-30T05:45:38.356Z"),
                        "pingMs" : 0,
                        "configVersion" : 1
                }
        ],
        "ok" : 1
}

//重新启动27000实例
# mongod --replSet repSetTest --dbpath /data/n1 --logpath /data/n1/n1.log --port \
> 27000 --smallfiles --oplogSize 128 --fork
about to fork child process, waiting until server is ready for connections.
forked process: 16473
child process started successfully, parent exiting

//再次查看复制集的状态,此时27000为辅助副本
repSetTest:PRIMARY> rs.status()
{
        "set" : "repSetTest",
        "date" : ISODate("2016-08-30T05:47:25.220Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "localhost:27000",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",  //此时该节点变成了辅助节点
                        "uptime" : 12,
                        "optime" : Timestamp(1472535845, 2),
                        "optimeDate" : ISODate("2016-08-30T05:44:05Z"),
                        "lastHeartbeat" : ISODate("2016-08-30T05:47:24.819Z"),
                        "lastHeartbeatRecv" : ISODate("2016-08-30T05:47:25.061Z"),
                        "pingMs" : 0,
                        "configVersion" : 1
                },
                {
                        "_id" : 1,
                        "name" : "localhost:27001",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 478,
                        "optime" : Timestamp(1472535845, 2),
                        "optimeDate" : ISODate("2016-08-30T05:44:05Z"),
                        "electionTime" : Timestamp(1472535890, 1),
                        "electionDate" : ISODate("2016-08-30T05:44:50Z"),
                        "configVersion" : 1,
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "localhost:27002",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 379,
                        "optime" : Timestamp(1472535845, 2),
                        "optimeDate" : ISODate("2016-08-30T05:44:05Z"),
                        "lastHeartbeat" : ISODate("2016-08-30T05:47:24.816Z"),
                        "lastHeartbeatRecv" : ISODate("2016-08-30T05:47:24.816Z"),
                        "pingMs" : 0,
                        "configVersion" : 1
                }
        ],
        "ok" : 1
}

四、获取复制集的帮助

repSetTest:PRIMARY> rs.help()  //获取副本集相关的帮助命令
    rs.status()                        { replSetGetStatus : 1 } checks repl set status
    rs.initiate()                      { replSetInitiate : null } initiates set with default settings
    rs.initiate(cfg)                   { replSetInitiate : cfg } initiates set with configuration cfg
    rs.conf()                          get the current configuration object from local.system.replset
    rs.reconfig(cfg)                   updates the configuration of a running replica set with cfg (disconnects)
    rs.add(hostportstr)                add a new member to the set with default attributes (disconnects)
    rs.add(membercfgobj)               add a new member to the set with extra attributes (disconnects)
    rs.addArb(hostportstr)             add a new member which is arbiterOnly:true (disconnects)
    rs.stepDown([stepdownSecs, catchUpSecs])   step down as primary (disconnects)
    rs.syncFrom(hostportstr)                   make a secondary sync from the given member
    rs.freeze(secs)                            make a node ineligible to become primary for the time specified
    rs.remove(hostportstr)                     remove a host from the replica set (disconnects)
    rs.slaveOk()                               allow queries on secondary nodes

    rs.printReplicationInfo()                  check oplog size and time range
    rs.printSlaveReplicationInfo()             check replica set members and replication lag
    db.isMaster()                              check who is primary

    reconfiguration helpers disconnect from the database so the shell will display
    an error, even if the command succeeds.
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
4月前
|
运维 监控 NoSQL
【MongoDB 复制集秘籍】Secondary 同步慢怎么办?深度解析与实战指南,让你的数据库飞速同步!
【8月更文挑战第24天】本文通过一个具体案例探讨了MongoDB复制集中Secondary成员同步缓慢的问题。现象表现为数据延迟增加,影响业务运行。经分析,可能的原因包括硬件资源不足、网络状况不佳、复制日志错误等。解决策略涵盖优化硬件(如增加内存、升级CPU)、调整网络配置以减少延迟以及优化MongoDB配置(例如调整`oplogSize`、启用压缩)。通过这些方法可有效提升同步效率,保证系统的稳定性和性能。
100 4
|
29天前
|
存储 NoSQL MongoDB
【赵渝强老师】部署MongoDB复制集
本文介绍了如何在单个节点上搭建MongoDB复制集环境,通过监听不同端口实现多节点配置。详细步骤包括创建数据目录、编辑配置文件、启动节点、初始化复制集、查看状态以及测试主从库的读写操作。文中还提供了视频讲解和代码示例,帮助读者更好地理解和操作。
|
29天前
|
存储 NoSQL MongoDB
【赵渝强老师】MongoDB复制集的体系架构
MongoDB的复制集是一种集群技术,由一个Primary节点和多个Secondary节点组成,实现数据的高可用性。Primary节点处理写入请求,Secondary节点同步数据。当Primary节点故障时,Secondary节点可通过选举成为新的Primary节点。视频讲解和示意图详见正文。
|
4月前
|
C# UED 开发者
WPF与性能优化:掌握这些核心技巧,让你的应用从卡顿到丝滑,彻底告别延迟,实现响应速度质的飞跃——从布局到动画全面剖析与实例演示
【8月更文挑战第31天】本文通过对比优化前后的方法,详细探讨了提升WPF应用响应速度的策略。文章首先分析了常见的性能瓶颈,如复杂的XAML布局、耗时的事件处理、不当的数据绑定及繁重的动画效果。接着,通过具体示例展示了如何简化XAML结构、使用后台线程处理事件、调整数据绑定设置以及利用DirectX优化动画,从而有效提升应用性能。通过这些优化措施,WPF应用将更加流畅,用户体验也将得到显著改善。
275 1
|
4月前
|
监控 NoSQL 大数据
【MongoDB复制集瓶颈】高频大数据写入引发的灾难,如何破局?
【8月更文挑战第24天】在MongoDB复制集中,主节点处理所有写请求,从节点通过复制保持数据一致性。但在大量高频数据插入场景中,会出现数据延迟增加、系统资源过度消耗、复制队列积压及从节点性能不足等问题,影响集群性能与稳定性。本文分析这些问题,并提出包括优化写入操作、调整写入关注级别、采用分片技术、提升从节点性能以及持续监控调优在内的解决方案,以确保MongoDB复制集高效稳定运行。
94 2
|
4月前
|
C# 开发者 Windows
全面指南:WPF无障碍设计从入门到精通——让每一个用户都能无障碍地享受你的应用,从自动化属性到焦点导航的最佳实践
【8月更文挑战第31天】为了确保Windows Presentation Foundation (WPF) 应用程序对所有用户都具备无障碍性,开发者需关注无障碍设计原则。这不仅是法律要求,更是社会责任,旨在让技术更人性化,惠及包括视障、听障及行动受限等用户群体。
89 0
|
4月前
|
Kubernetes 容器 Perl
在K8S中,Replica Set和Replication Controller之间有什么区别?
在K8S中,Replica Set和Replication Controller之间有什么区别?
|
7月前
|
监控 NoSQL 安全
【MongoDB 专栏】MongoDB 的复制集:高可用性配置
【5月更文挑战第10天】MongoDB的复制集是实现数据高可用性的重要机制,由主节点和次节点构成,主节点处理写操作,次节点同步数据确保一致。在主节点故障时,次节点自动提升接替,保证服务不间断。通过复制集,可实现数据保护、持续服务,适用于关键业务系统和数据备份。配置时需关注网络稳定性、节点性能和数据一致性。案例显示,复制集能有效保障服务高可用,防止数据丢失和业务中断,是现代数据库管理的关键工具。在数据驱动的世界,复制集为高可用性提供了坚实保障。
144 0
【MongoDB 专栏】MongoDB 的复制集:高可用性配置
|
1天前
|
存储 NoSQL 关系型数据库
阿里云数据库MongoDB版助力信也科技 打造互联网金融企业样板
我们的风控系统引入阿里云数据库MongoDB版后,解决了特征类字段灵活加减的问题,大大提高了开发效率,极大的提升了业务用户体验,获得了非常好的效果
阿里云数据库MongoDB版助力信也科技 打造互联网金融企业样板
|
1月前
|
NoSQL Cloud Native atlas
探索云原生数据库:MongoDB Atlas 的实践与思考
【10月更文挑战第21天】本文探讨了MongoDB Atlas的核心特性、实践应用及对云原生数据库未来的思考。MongoDB Atlas作为MongoDB的云原生版本,提供全球分布式、完全托管、弹性伸缩和安全合规等优势,支持快速部署、数据全球化、自动化运维和灵活定价。文章还讨论了云原生数据库的未来趋势,如架构灵活性、智能化运维和混合云支持,并分享了实施MongoDB Atlas的最佳实践。