Mongodb源码分析--Replication之主从模式--Slave

    在上文中介绍了主从(master-slave)模式下的一些基本概念及master的执行流程。今天接着介绍一下从(slave)结点是如何发起请求,并通过请求获取的oplog信息来构造本地数据的。

    不过开始今天的正文前,需要介绍一下mongodb在slave结点上进行数据同步时的一个大致流程:
    
    1. 当一个从结点启动时,它会对主结点进行一次彻底同步。从结点将复制主结点中的每一个文档(操作量大且耗时)。当初始化的同步完成后,从结点将查询主结点的oplog并且执行这些操作来保持数据的更新。

    2. 如从结点上的操作落后主结点太多, 从结点处于out-of-sync状态。该状态表示从结点不能通过执行同步操作使本地数据赶上主结点数据,因为主结点中的每一个操作都太新了。造成这种情 况的原因包括结点宕机或者忙于处理读请求(尽管mongodb支持读操作的负载均衡)。如果同步的时间(戳)超出了oplog(滚动)的时间(戳),它将 重新开始一次彻底的同步(通过执行resync操作)。

    3. 当一个从结点处于out-of- sync状态时,复制将被挂起,从结点需要从主结点进行重新同步。resync流程可以手动执行,即在从结点的admin数据库上运行命令 {“resync”:1}, 或者自动执行:在启动从结点时使用 --autoresync选项。因为resync是非常操作量大且耗时,最好通过设置一个足够大的oplogSize来避免resync(默认的 oplog大小是空闲磁盘大小的5%)。

    为了验证上面的流程,下面我们就来看一下slave的执行流程。这里为了便于调试,对环境配置如下:

    1.master db ip-> 10.0.4.210
      启动命令行:d:/mongod>bin>mongod --dbpath=d:/mongodb/db --master --oplogSize 64

    2.在vs中做如下设置(mongod项目属性窗口):
      --slave --source 10.0.4.210:27017 --only test --slavedelay 100



    因为mongod的主入口函数在db.cpp中,我们可以通过下面方法的调用流程找到slave的蛛丝马迹:



    当执行到listen()方法后(如下):



   mongodb会紧跟着执行repl.cpp文件中的startReplication()方法,如下:


   


    上面方法在完成必要的参数分析检查之后,就会根据slave的配置信息来构造启动线程方法replSlaveThread,如下:

    



    上面方法中有mongodb进行认证的逻辑,之后就会用一个while(1)来循环执行(注:每5秒执行一次)replMain()方法,如下:



     上面代码又是一个while(1)循环,它会判断当前slave是否处于“out of sync”状态,如果是,但未开启autoresync时,则复制将被挂起。否则会执行_replMain方法来进行同步,如下:

        


    上面的_replMain()方法首先会从“local.sources”数据集中获取主(master)节点的信息。这里解释一下,mongod从结 点在启动时会将启动参数(--source)中的信息保存到"local.sources"数据集中,并通过此函数(loadAll())中加载到一个集 合对象中。这里我们看一下其加载代码,如下:



    完成了source的加载之后,就可以开始对source进行同步了,即如下代码:

    上面方法先进行一些异常判断,比如source为localhost地址,以及无法链接(oplogReader.connect)等情况。之后,调用sync_pullOpLog方法,从master上获取oplog来同步数据信息,如下:

 


    上面方法代码比较长,首先它会初始要链接的master的oplog名空间信息,之后尝试链接到master上以获取相应的cursor id信息。该cursor id用于标识当前slave访问master时所使用的cursor(因为master中的oplog cursor会在返回oplog信息时不关闭,它支持下次slave链接使用该cursor时从相应的pos位置继续获取。这块内容可以参见这篇文章 Mongodb源码分析--Replication之主从模式--Master).

    如果cursorid正常,则使用oplogReader对象来获取相应的oplog信息(注:oplogReader为mongodb为了查询oplog而声明的一个类,详情参见其源码文件oplogreader.h)

    除此以外,上面方法还会设置本地的syncedTo来记录下次同步时使用的时间戳。同时根据本地保存的时间戳与oplogReader所返回的 master oplog信息中的ts进行比较,以判断是否出现out of sync的情况,以进而执行resync操作。有关这类逻辑说明参见上面的代码注释即可。
    
    当获取的master oplog符合(本地时间戳)要求时,则将oplog对象进行分解,以进而将其中的数据对象保存到本地并执行持久化操作(上面代码 段:getDur().commitIfNeeded())。这里要说明的是,将oplog进行分解时执行的逻辑通过 sync_pullOpLog_applyOperation方法中执行,因为这里牵扯到oplog的数据结构,由于篇幅所限,这部分内容我会在后面章节 中进行说明,我们只要知道在分解结束后,最终调用如下方法将数据放到本机上:

  


    到这里,关于如何进行crud的操作,就与我之前的几篇文章的内容关联上了,大家回顾一下即可。最后用一次时序图来回顾一下slave的执行流程:



    好了,今天的内容到这里就告一段落了。

 
    原文链接:http://www.cnblogs.com/daizhj/archive/2011/06/20/mongodb_sourcecode_repl_slave_run.html
    作者: daizhj, 代震军   
    微博: http://t.sina.com.cn/daizhj
    Tags: mongodb,c++,Replica,master-slave
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页