一 数据同步

       一个健康的secondary在运行时,会选择一个离自己最近的,数据比自己新的节点进行数据同步。选定节点后,它会从这个节点拉取oplog同步日志,具体流程是这样的:
            a.执行这个op日志

b.将这个op日志写入到自己的oplog中(local.oplog.rs)

          c.再请求下一个op日志


         如果同步操作在第1步和第2步之间出现问题宕机,那么secondary再重新恢复后,会检查自己这边最新的oplog,由于第2步还没有执行,所以自己这边还没有这条写操作的日志。这时候他会再把刚才执行过的那个操作执行一次。那对同一个写操作执行两次会不会有问题呢?
MongoDB在设计oplog时就考虑到了这一点,所以所有的oplog都是可以重复执行的,比如你执行 {$inc:{counter:1}} 对counter字段加1,counter字段在加1 后值为2,那么在oplog里并不会记录 {$inc:{counter:1}} 这个操作,而是记录 {$set:{counter:2}}这个操作。所以无论多少次执行同一个写操作,都不会出现问题。

          注:从节点不一定要从主节点的操作日志来读取数据,它也可以选择距离自己最近的(根据ping的时间来计算)的且比自己操作日志记录更新的从节点获取操作日志。

二  同步过程

当我们在MongoDB时执行一个写操作时,默认会直接返回成功,同时也可以通过设置w参数,指定这个写操作同步到几个节点后才返回成功。如下:

db.foo.runCommand({getLastError:1, w:2})

上面例子就是执行getLastError命令,使其在上一个写操作同步到两个节点上后再返回。不同的客户端可能在写法上不太一样,不过这个功能应该都是有的。对于重要数据,可以考虑采用这样的方式,通过牺牲一部分写性能来提升数据的安全性。

       这个功能是如何实现的呢,primary节点是如何知道数据同步了几份呢?在调用上面命令时,实际上MongoDB内部执行了如下的一些流程:
a.在primary上完成写操作

b.在primary上记录一条oplog日志,日志中包含一个ts字段,值为写操作执行的时间,比如本例中记为t

c.客户端调用{getLastError:1, w:2}命令等待primary返回结果

d.secondary从primary拉取oplog,获取到刚才那一次写操作的日志

e.secondary按获取到的日志执行相应的写操作

f.执行完成后,secondary再获取新的日志,其向primary上拉取oplog的条件为{ts:{$gt:t}}

g.primary此时收到secondary的请求,了解到secondary在请求时间大于t的写操作日志,所以他知道操作在t之前的 日志都已经成功执行了

h.这时候getLastError命令检测到primary与secondary都完成了这次写操作,于是 w:2 的条件满足了,返回给客户端成功




注意:1.如果设置的w参数大于当前复制集中的从节点数目的话,写入操作会被阻塞,一直到写入节点数达到w参数所设置的数据才会返回。

          2.将W参数设置成当前负责集合中从节点的数目的话,这个复制集将会对外提供强一致性的服务,但是整个复制集的写性能也会下降。

启动初始化

当一个新节点启动并加入到现在的Replica Sets中时,这时候新启动的节点会查看自己的oplog,通过一个叫 lastOpTimeWritten 的命令查找到它最近的一条写操作。这个命令你也可以随便在命令行执行:

> rs.debug.getLastOpWritten()

这个命令会返回一条oplog记录,其中的ts字段就是最近一次写操作的时间了。

如果你这个节点是全新的,没有数据,那么oplog里也没有数据,这时候节点会选择执行一次全量的同步。本文暂时不对全量同步的方法进行描述。

选择同步源节点

Replica Sets中的节点之间总在同步数据,但是他们不是通过传统的一主多从的方式来同步的。MongoDB的策略是选择一个合适的节点作为数据源。

首先secondary节点会通过ping的时间来确定其它节点与它的距离。时间越长的识为距离越远。然后通过下面方法确定其源节点:

for each member that is healthy:
if member[state] == PRIMARY
add to set of possible sync targets if member[lastOpTimeWritten] > our[lastOpTimeWritten]
add to set of possible sync targets sync target = member with the min ping time from the possible sync targets

对于节点是否healthy的判断,各个版本不同,但是其目的都是找出正常运转的节点。在2.0版本中,它的判断还包括了salve delay这个因素。

你可以通过运行db.adminCommand({replSetGetStatus:1})命令来查看当前的节点状况,在secondary上运行这个命令,你能看到syncingTo这个字段,这个字段的值就是这个secondary的同步源。(其实名字应该是叫syncingFrom,但是由于版本兼容的原因,沿用了这个错误的名字)

链式同步结构

上面对w参数的实现,讲解上比较简单,只讲了w为2的情况,但是当w更大时,由于我们并不是采用一主多从的方式进行同步。所以情况会复杂一些。

比如我们有节点A,为primary节点,然后B节点为secondary节点,它从A节点同步数据,同时又有secondary节点C,它从同是secondary的B节点同步数据。这样A->B->C之间就形成了一个链式的同步结构。如果我们设定w为3,那么A节点如何能知道C节点已经从B节点同步成功了呢?

         这是通过oplog同步协议来实现的,我们用通俗的语言来解释一下oplog的同步协议。
   a.当C从B同步数据时,C会在协议中对B说:我要从你这同步数据了,如果写操作有w参数的话,我的同步也算上吧。

b.然后B会回答说:我不是一个primary节点,我会把你的这个计数转到我的同步源上去


   c.然后B再对A打开一个新的连接,并且对A说:这个连接你就当成是C的吧,也算一个计数在w里。


   d.这时候在A看来,就有两个连接连到他上面,一个是B,一个是虚拟的C,这两个连接都能报告他说完成了同步操作。

当一个写操作在A上执行后,B首先同步到这个操作的oplog,执行完后会告诉A,我执行完了。然后C同样从B上获取到B的oplog,也执行了这一条写操作,然后他告诉B,我执行完了,B在收到这个响应后,会通过刚才开通的虚拟通道跟A说,我是虚拟的C节点,我也完成写操作了。这时候A就知道,A、B、C三个节点都完成写操作了。w:3的条件满足,然后返回给调用getLastError的客户端,完成这次操作。

具体三个节点间的连接如下图:

C        B        A
<====>
<====> <---->
B和A之间有两条通道,双线那条是真正的同步连接,单线那条是一个虚拟连接。

注意:MongoDB这种链式同步结构类似于Hadoop中HDFS中数据块的流式复制,这样的好处是可以大大减轻主节点的压力,提高数据同步的速度。

三 新功能展望

上面就是当前的Replica Sets同步的内部实现,在后续这一块MongoDB还会进行一些新特性的开发。在2.2版本中,会提供replSetSyncFrom命令,让用户可以手动设置一个secondary的同步源。使用方法大概是这样:

> db.adminCommand({replSetSyncFrom:"otherHost:27017"})

MongoDB 复制集 (三) 内部数据同步的更多相关文章

  1. MongoDB复制集与Raft协议异同点分析

    此文已由作者温正湖授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 一.日志复制流程: a.raft leader节点在接收client请求后,先将请求写到日志中,再将日志通过 ...

  2. MongoDB DBA 实践5-----复制集集群的数据同步和故障转移

    (1)复制集集群的数据同步 1>主节点数据库test,在其中goods集合中加入一个文档. 2>在副节点中查看 注意:SECONDARY是不允许读写的,要使用rs.slaveOk()获得读 ...

  3. MongoDB复制集高可用选举机制(三)

    复制集高可用选举机制 在上一章介绍了MongoDB的架构,复制集的架构直接影响着故障切换时的结果.为了能够有效的故障切换,请确保至少有一个节点能够顺利升职为主节点.保证在拥有核心业务系统的数据中心中拥 ...

  4. Raft与MongoDB复制集协议比较

    在一文搞懂raft算法一文中,从raft论文出发,详细介绍了raft的工作流程以及对特殊情况的处理.但算法.协议这种偏抽象的东西,仅仅看论文还是比较难以掌握的,需要看看在工业界的具体实现.本文关注Mo ...

  5. MongoDB 复制集 (一) 成员介绍

       一 MongoDB 复制集简介          MongoDB的复制机制主要分为两种:          Master-Slave    (主从复制)      这个已经不建议使用       ...

  6. MongoDB复制集

    1.1 MongoDB复制集简介 一组Mongodb复制集,就是一组mongod进程,这些进程维护同一个数据集合.复制集提供了数据冗余和高等级的可靠性,这是生产部署的基础. 1.1.1 复制集的目的 ...

  7. MongoDB复制集原理、环境配置及基本测试详解

    一.MongoDB复制集概述 MongoDB复制集实现了冗余备份和故障转移两大功能,这样能保证数据库的高可用性.在生产环境,复制集至少包括三个节点,其中一个必须为主节点,一个从节点,一个仲裁节点.其中 ...

  8. MongoDB复制集技术

    复制集搭建 没毛病: https://www.cnblogs.com/nicolegxt/p/6841442.html?utm_source=itdadao&utm_medium=referr ...

  9. MongoDB复制集成员及状态转换

    此文已由作者温正湖授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 复制集(Replica Set)是MongoDB核心组件,相比早期版本采用的主从(Master-Slave) ...

随机推荐

  1. Python 爬取网站资源文件

    爬虫原理: 以下来自知乎解释 首先你要明白爬虫怎样工作.想象你是一只蜘蛛,现在你被放到了互联“网”上.那么,你需要把所有的网页都看一遍.怎么办呢?没问题呀,你就随便从某个地方开始,比如说人民日报的首页 ...

  2. C#中可直接调用WIN32的API函数--USER32.DLL

    Win32的API函数可以直接在C#中直接调用,在做WinForm时还是很有帮助的.有时候直接调用Win32的API,可以很高效的实现想要的效果. using System; using System ...

  3. iptables转发

    需求 将流入服务器的公网IP的80端口的流量全部转发到另一个公网IP(1.2.3.4)的80端口上. 操作 iptables -P FORWARD ACCEPT iptables -t nat -A ...

  4. 调整V7连保监平台时问题

    11北京 XXX: 界面无法录入导致无法出单. 31上海 XXX: 送平台代码有问题 保费计算失败! 车险平台返回信息 0101010024_公司险种代码/平台险种代码('030006 '/'C02 ...

  5. Kruscal 、 Prime Template

    Kruscal  Template : 很裸的Kruscal Template(求最小生成树中最长路,即最短路中最长路) //#pragma comment(linker, "/STACK: ...

  6. [转载] epoll详解

    转载自http://blog.csdn.net/xiajun07061225/article/details/9250579 什么是epoll epoll是什么?按照man手册的说法:是为处理大批量句 ...

  7. 详解卷积神经网络(CNN)

    详解卷积神经网络(CNN) 详解卷积神经网络CNN 概揽 Layers used to build ConvNets 卷积层Convolutional layer 池化层Pooling Layer 全 ...

  8. Android中px, ppi, dpi, dp, dip, sp概念解析

    Android中px, ppi, dpi, dp, dip, sp概念解析

  9. JQueryMobile开发必须的知道的知识

    移动Web页面的基本组成元素: 页面头部,页面内容,页面底部 <!DOCTYPE html> <html> <head> <title>My Page& ...

  10. 如何写一个简单的HTTP服务器(重做版)

    最近几天用C++重新写了之前的HTTP服务器,对以前的代码进行改进.新的HTTP服务器采用Reactor模式,有多个线程并且每个线程有一个EventLoop,主程序将任务分发到每个线程,其中采用的是轮 ...