mongodb副本集的内部机制(借鉴lanceyan.com)

针对mongodb的内部机制提出如下几个引导性的问题:html

  • 副本集故障转移,主节点是如何选举的?可否手动干涉下架某一台主节点。
  • 官方说副本集数量最好是奇数,为何?
  • mongodb副本集是如何同步的?若是同步不及时会出现什么状况?会不会出现不一致性?
  • mongodb的故障转移会不会无端自动发生?什么条件会触发?频繁触发可能会带来系统负载加剧?

Bully算法 mongodb副本集故障转移功能得益于它的选举机制。选举机制采用了Bully算法,能够很方便从分布式节点中选出主节点。一个分布式集群架构中通常都有一个所谓的主节点,能够有不少用途,好比缓存机器节点元数据,做为集群的访问入口等等。主节点有就有吧,咱们干吗要什么Bully算法?要明白这个咱们先看看这两种架构:node

  1. 指定主节点的架构,这种架构通常都会申明一个节点为主节点,其余节点都是从节点,如咱们经常使用的mysql就是这样。可是这样架构咱们在第一节说了整个集群若是主节点挂掉了就得手工操做,上架一个新的主节点或者从从节点恢复数据,不太灵活。mysql

    mongodb4

  2. 不指定主节点,集群中的任意节点均可以成为主节点。mongodb也就是采用这种架构,一但主节点挂了其余从节点自动接替变成主节点。以下图:linux

    mongodb故障转移

好了,问题就在这个地方,既然全部节点都是同样,一但主节点挂了,怎么选择出来下一个节点是谁来作为主节点呢?这就是Bully算法解决的问题。算法

那什么是Bully算法,Bully算法是一种协调者(主节点)竞选算法,主要思想是集群的每一个成员均可以声明它是主节点并通知其余节点。别的节点能够选择接受这个声称或是拒绝并进入主节点竞争。被其余全部节点接受的节点才能成为主节点。节点按照一些属性来判断谁应该胜出。这个属性能够是一个静态ID,也能够是更新的度量像最近一次事务ID(最新的节点会胜出)。详情请参考NoSQL数据库分布式算法的协调者竞选还有维基百科的解释 。sql

选举 那mongodb是怎进行选举的呢?官方这么描述:mongodb

We use a consensus protocol to pick a primary. Exact details will be spared here but that basic process is:数据库

  1. get maxLocalOpOrdinal from each server.
  2. if a majority of servers are not up (from this server’s POV), remain in Secondary mode and stop.
  3. if the last op time seems very old, stop and await human intervention.
  4. else, using a consensus protocol, pick the server with the highest maxLocalOpOrdinal as the Primary.

大体翻译过来为使用一致协议选择主节点。基本步骤为:windows

  1. 获得每一个服务器节点的最后操做时间戳。每一个mongodb都有oplog机制会记录本机的操做,方便和主服务器进行对比数据是否同步还能够用于错误恢复。
  2. 若是集群中大部分服务器down机了,保留活着的节点都为 secondary状态并中止,不选举了。
  3. 若是集群中选举出来的主节点或者全部从节点最后一次同步时间看起来很旧了,中止选举等待人来操做。
  4. 若是上面都没有问题就选择最后操做时间戳最新(保证数据是最新的)的服务器节点做为主节点。

这里提到了一个一致协议(其实就是bully算法),这个和数据库的一致性协议仍是有些区别,一致协议主要强调的是经过一些机制保证你们达成共识;而一致性协议强调的是操做的顺序一致性,好比同时读写一个数据会不会出现脏数据。一致协议在分布式里有一个经典的算法叫“Paxos算法”,后续再介绍。缓存

上面有个问题,就是全部从节点的最后操做时间都是同样怎么办?就是谁先成为主节点的时间最快就选谁。

选举触发条件 选举不是什么时刻都会被触发的,有如下状况能够触发。

  1. 初始化一个副本集时。
  2. 副本集和主节点断开链接,多是网络问题。
  3. 主节点挂掉。

选举还有个前提条件,参与选举的节点数量必须大于副本集总节点数量的一半,若是已经小于一半了全部节点保持只读状态。
日志将会出现:

can't see a majority of the set, relinquishing primary

主节点挂掉可否人为干预?答案是确定的。

  1. 能够经过replSetStepDown命令下架主节点。这个命令能够登陆主节点使用
    db.adminCommand({replSetStepDown : 1})

    若是杀不掉可使用强制开关

    db.adminCommand({replSetStepDown : 1, force : true})

    或者使用 rs.stepDown(120)也能够达到一样的效果,中间的数字指不能在中止服务这段时间成为主节点,单位为秒。

  2. 设置一个从节点有比主节点有更高的优先级。
    先查看当前集群中优先级,经过rs.conf()命令,默认优先级为1是不显示的,这里标示出来。

     

    rs.conf();
    {
            "_id" : "rs0",
            "version" : 9,
            "members" : [
                    {
                            "_id" : 0,
                            "host" : "192.168.1.136:27017"                },
                    {
                            "_id" : 1,
                            "host" : "192.168.1.137:27017"                },
                    {
                            "_id" : 2,
                            "host" : "192.168.1.138:27017"                }
            ]
            }

    咱们来设置,让id为1的主机能够优先成为主节点。

    cfg = rs.conf()
    cfg.members[0].priority = 1
    cfg.members[1].priority = 2
    cfg.members[2].priority = 1
    rs.reconfig(cfg)

    而后再执行rs.conf()命令查看优先级已经设置成功,主节点选举也会触发。

    {
            "_id" : "rs0",
            "version" : 9,
            "members" : [
                    {
                            "_id" : 0,
                            "host" : "192.168.1.136:27017"                },
                    {
                            "_id" : 1,
                            "host" : "192.168.1.137:27017",
                            "priority" : 2
                    },
                    {
                            "_id" : 2,
                            "host" : "192.168.1.138:27017"                }
              ]
             }

    若是不想让一个从节点成为主节点能够怎么操做?
    a、使用rs.freeze(120)冻结指定的秒数不能选举成为主节点。
    b、按照上一篇设置节点为Non-Voting类型。

  3. 当主节点不能和大部分从节点通信。把主机节点网线拔掉,嘿嘿:)

    优先级还能够这么用,若是咱们不想设置什么hidden节点,就用secondary类型做为备份节点也不想让他成为主节点怎么办?看下图,共三个节点分布在两个数据中心,数据中心2的节点设置优先级为0不能成为主节点,可是能够参与选举、数据复制。架构仍是很灵活吧!

    deeprepset1

奇数 官方推荐副本集的成员数量为奇数,最多12个副本集节点,最多7个节点参与选举。最多12个副本集节点是由于不必一份数据复制那么多份,备份太多反而增长了网络负载和拖慢了集群性能;而最多7个节点参与选举是由于内部选举机制节点数量太多就会致使1分钟内还选不出主节点,凡事只要适当就好。这个“12”、“7”数字还好,经过他们官方通过性能测试定义出来能够理解。具体还有哪些限制参考官方文档《 MongoDB Limits and Thresholds 》。 可是这里一直没搞懂整个集群为何要奇数,经过测试集群的数量为偶数也是能够运行的,参考这个文章http://www.itpub.net/thread-1740982-1-1.html。后来忽然看了一篇stackoverflow的文章终于顿悟了,mongodb自己设计的就是一个能够跨IDC的分布式数据库,因此咱们应该把它放到大的环境来看。

假设四个节点被分红两个IDC,每一个IDC各两台机器,以下图。但这样就出现了个问题,若是两个IDC网络断掉,这在广域网上很容易出现的问题,在上面选举中提到只要主节点和集群中大部分节点断开连接就会开始一轮新的选举操做,不过mongodb副本集两边都只有两个节点,可是选举要求参与的节点数量必须大于一半,这样全部集群节点都没办法参与选举,只会处于只读状态。可是若是是奇数节点就不会出现这个问题,假设3个节点,只要有2个节点活着就能够选举,5个中的3个,7个中的4个。。。

deeprepset2

心跳 综上所述,整个集群须要保持必定的通讯才能知道哪些节点活着哪些节点挂掉。mongodb节点会向副本集中的其余节点每两秒就会发送一次pings包,若是其余节点在10秒钟以内没有返回就标示为不能访问。每一个节点内部都会维护一个状态映射表,代表当前每一个节点是什么角色、日志时间戳等关键信息。若是是主节点,除了维护映射表外还须要检查本身可否和集群中内大部分节点通信,若是不能则把本身降级为secondary只读节点。

同步,副本集同步分为初始化同步和keep复制。初始化同步指全量从主节点同步数据,若是主节点数据量比较大同步时间会比较长。而keep复制指初始化同步事后,节点之间的实时同步通常是增量同步。初始化同步不仅是在第一次才会被触发,有如下两种状况会触发:

  1. secondary第一次加入,这个是确定的。
  2. secondary落后的数据量超过了oplog的大小,这样也会被全量复制。

那什么是oplog的大小?前面说过oplog保存了数据的操做记录,secondary复制oplog并把里面的操做在secondary执行一遍。可是oplog也是mongodb的一个集合,保存在local.oplog.rs里,可是这个oplog是一个capped collection也就是固定大小的集合,新数据加入超过集合的大小会覆盖。因此这里须要注意,跨IDC的复制要设置合适的oplogSize,避免在生产环境常常产生全量复制。oplogSize 能够经过–oplogSize设置大小,对于linux 和windows 64位,oplog size默认为剩余磁盘空间的5%。

同步也并不是只能从主节点同步,假设集群中3个节点,节点1是主节点在IDC1,节点二、节点3在IDC2,初始化节点二、节点3会从节点1同步数据。后面节点二、节点3会使用就近原则从当前IDC的副本集中进行复制,只要有一个节点从IDC1的节点1复制数据。

设置同步还要注意如下几点:

    1. secondary不会从delayed和hidden成员上复制数据。
    2. 只要是须要同步,两个成员的buildindexes必需要相同不管是不是true和false。buildindexes主要用来设置是否这个节点的数据用于查询,默认为true。
    3. 若是同步操做30秒都没有反应,则会从新选择一个节点进行同步。
相关文章
相关标签/搜索