MongoDB副本集
一、MongoDB简介
MongoDB是一个面向文档的数据库,其实是一个介于关系型与非关系型之间的数据库。在MongoDB的世界里,没有行(row)的概念,取而代之的是文档(document)模型,文档内还能嵌入文档、数组等,非常灵活。它支持json和bson的数据格式,可以存储比较复杂的数据类型,因而也受到广大DBA的青睐。
在生产环境中,很少用单节点来支撑业务流量,主要是节点性能与数据安全性方面的考虑,MongoDB可以用副本集来实现数据备份、故障恢复等功能,使用分片技术来使集群存储更多的数据,实现更大的负载,也能保证存储的负载均衡。本文主要介绍的是副本集,有关分片技术会在后面的文章中来进行介绍。
二、什么是副本集
副本集是一组运行着mongod进程的服务器,维护着同一个数据集,其中有一个是主服务器(primary),用于处理客户端请求,其他节点为备份服务器(secondary),用于保存数据库副本。当主服务器挂掉的时候,其他备份服务器会自动选取一个节点作为新的主服务器,保证数据安全性、业务可用性。
下面是官方提供的一张架构图:
主服务器(primary)接受所有客户端的读写请求(可以通过配置使得备份服务器也能接受读请求,在要求数据强一致性的环境中不建议这样做),主服务器会将对数据的改动记录到operation log中,即oplog(类似MySQL中的binlog),备份服务器会从主服务器中复制此日志,然后应用到自身数据库中,以保证数据与主库中一致。副本集中各个节点之间会互相发送心跳报文来获取各个节点的信息。
当主服务器(primary)宕机或者由于网络故障与其它节点失去联系之后(10秒),其中一个备份服务器会发起选举流程来将自己提升为新的主服务器。整个过程一般在一分钟之内完成。
三、副本集成员
在介绍复制原理之前先来看一下整个副本集中会有哪些成员,它们的功能分别是什么。
1、主服务器(primary)
主服务器用于处理客户端请求,默认情况下,客户端的读写请求都到达主服务器。
2、备份服务器(secondary)
保存数据副本,在主服务器故障时参与选举。用于保障集群高可用。默认情况下备份服务器不接受读请求。
3、仲裁者(arbiter)
MongoDB支持一种特殊类型的成员--仲裁者(arbiter)。它不用于保存数据,唯一能施展拳脚的地方就是参与选举过程,履行投票的义务。如果应用数据比较小,但又想使用副本集来预防数据意外丢失的风险,使用多个数据节点比较浪费资源,这时仲裁者将是不二之选。它可以作为一个轻量级的进程运行在一台配置比较差的服务器上。可以将其部署在与数据节点不同的故障域内,这样将会增强副本集的健壮性。
在使用仲裁者的时候应该注意以下两个限制:
- 1、一个副本集中只能有一个仲裁者
- 2、如果条件允许,能使用数据节点的时候就不要使用仲裁者
在小副本集中,比如三个节点的副本集,使用一个主服务器、一个备份服务器、一个仲裁者,假设主服务器挂掉(连数据都损坏),另外一个备份服务器升为主服务器,这个时候如果新的主服务器也挂掉,而仲裁者又不保存数据,那将是毁灭性的打击。所以选择使用仲裁者之前一定要作各方面考虑。
以上三种即是一个副本集中主要的成员类型,下面两种其实也是备份节点,但由于有一些特别的功能,所以单独介绍。
4、隐藏成员
隐藏成员不会作为一个副本集中的复制源,而且对于客户端来说,它是不可见的(只有当其优先级为0时才能设置为隐藏成员)。很多朋友喜欢将一些性能不那么强大的服务器隐藏起来。
5、延迟备份节点
顾名思义,延迟备份节点是比主服务器数据落后某一段时间的节点。此节点的目的是为了防止出现重大故障,比如DBA朋友小手一抖将某些数据给删掉了,执行完删除命令之后顿悟,这个时候主服务器上数据没了,跑得快的备份服务器上数据也没有了,但由于延迟备份节点配置为落后主服务器一段时间,它上面的数据还在,这个副本集就还能一救。
延迟备份节点的优先级也需为0,并且为了保证数据一致性,还需要将延迟备份节点设置为隐藏成员。
四、数据同步
MongoDB的复制功能通过操作日志oplog来实现。客户端对数据的更改操作会写进oplog中,它其实也是一个集合,存放于local数据库中,比较特殊的是它是一个固定大小的集合(capped collection),也就是说它并不是保存了所有对数据库的更改操作,只是一部分,当记录占满了这个集合时,新的操作日志会将老的冲掉。副本集中每一个成员都会维护一份自己的oplog。
另外,如果将oplog中的某一个操作在节点上执行多次,其实与执行一次的效果是一样的。这样设计的好处是为了避免备份节点同步过程中主服务器挂掉,从新的主服务器上拷贝过来的oplog中与从旧的主服务器上拷贝过来的oplog有重叠。
MongoDB的数据同步大体也可分为两种:初始化同步(Initial Syncing)和增量同步。
1、初始化同步
我们也可以将其理解为全量同步。一般在副本集中成员启动后或者新加入成员就会进入这一个阶段。
触发初始化同步有以下三个条件:
- local数据库中的oplog.rs 集合为空。
- minValid集合里面存储的是_initialSyncFlag(用于init sync失败处理)
- initialSyncRequested是true(用于resync命令,resync适用于主从架构,副本集不适用)
整个初始化同步阶段包括以下几个步骤:
- 选择同步源。此时它会在local.me中创建一个属于自己的标识符,然后会将自己所有的数据都删除掉(local数据库除外),以一个全新的自己来进行同步。
- 克隆(clone)。简单理解,就是将同步源上的所有数据复制到本地。
- 克隆完成之后就开始进入oplog同步阶段,这个阶段分两步,第一步:如果克隆过程中文档被移动,重新进行克隆;第二步:将第一步中的操作记录下来。
- 创建索引。
- 将创建索引期间主服务器发生的数据更改进行同步。
- 初始化同步结束,节点变成备份服务器。
2、增量同步
当初始化同步完成之后,就进入增量同步阶段,备份节点在初始化同步结束后的第一时间就通过tailable cursor来不断从主服务器上拉取oplog,然后应用到自身的数据库中。tailable cursor游标类似linux里的tailf命令。增量同步会用几个线程来协作完成,具体过程在以后的文章的介绍。
五、成员状态
我们已经知道副本集中各个节点之间每隔2秒(可通过抓包看出)会发送心跳报文,报文中会包含节点自身的状态信息,下面来看看成员会有哪些状态,什么情况下会进入这些状态。
- RPIMARY:主服务器专属。
- SECONDARY:备份服务器专属。
- ARBITER:仲裁者专属。
- STARTUP:当成员刚启动时就进入这个状态,本状态会加载一些副本集配置信息,等到加载完毕就进入STARTUP2阶段。
- STARTUP2:我们在上一节提到了初始化同步,在整个初始化同步过程中成员的状态都是STARTUP2。
- RECOVERING:每个成员成为备份节点之前都会先进入这个状态。这个状态表明节点是在正常运转的,但是还需进一步对自身做一些检查,处于此状态的成员不能处理读请求。
- DOWN:成员失联的情况下会处于DOWN状态。
- UNKNOWN:副本集中某个成员连不上其他成员,其他成员无法获知它的状态信息,那它就会被置为UNKNOWN状态。
- REMOVED:成员被移出副本集,即被置为此状态。
- ROLLBACK:成员进入回滚阶段,即会被置为此状态,回滚完成之后进入RECOVERING状态,随后变成备份服务器。
- FATAL:成员出现无法自动修复的故障之后会被置为此状态。
官方将这11个状态分为三大类:
Core States(包含RPIMARY、SECONDARY和ARBITER)、Other States(包含STARTUP、STARTUP2和RECOVERING)、Error States(包含UNKNOWN、DOWN、REMOVED、ROLLBACK和FATAL)。