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