Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

Vinllen Chen


但行好事,莫问前程

MongoDB主从复制之增量同步

  本文首先介绍3.4版本,MongoDB主从复制中增量同步的拉取和写入流程,然后介绍几个位点的区别:lastApplied,lastCommit,stableCkpt,appliedThrough。

1. 增量同步基本流程

  secondary的OplogFetcher负责从源端拉取oplog,并写入到内存blocking队列OplogBuffer中;OplogBatcher负责从oplog中拉取数据,并写入到目的端(也就是当前结点)。下图是增量同步的基本流图:
incr_sync
  同步之前,secondary会选择一个sync source作为同步的源进行全量和增量的拉取,那么同步源是如何选择的?

1.1 同步源sync source的选择

  每次开启全量intial sync,创建BackgroundSync的时候,必须先获取一个sync source,这个过程就是通过SyncSourceResolver来完成的。SyncsourceResolver代理ReplicationCoordinator去进行选择sync source,其内部是通过调用TopologyCoordinator进行完成。
  TopologyCoordinator如何进行选择:

  1. 判断是否用户强行指定primary(replSetSyncFrom命令),是的话直接选择用户指定的sync source
  2. 判断链式复制选项是否被disable,是的话直接选择当前primary作为sync source
  3. 重复以下几个步骤直到完成选择
  4. 检查TopologyCoordinator中cache的副本集的OpTime的信息。(当前结点缓存的primary节点上关于各个节点最新的同步时间)
  5. 通过检查TopologyCoordinator上缓存的拓扑里面的primary的OpTime。secondary并不会选择那些secondary节点落后primary超过maxSyncSourceLagSecs时间间隔的节点。
  6. secondary迭代各个节点,选择满足various criteria的ping延迟最低的结点作为sync souce.
  7. 如果没有节点满足要求,则sleep 1s并重试4-7三步骤。

选择完sync source以后,SyncSourceResolver会对sync source进行探测以观察是否有异常。

  1. 如果sync source没有oplog或者有异常,那么这个sync source会被拉入到黑名单持续一定的时间,并重新发起sync source的选举。
  2. 如果sync source的最老的oplog大于当前结点最新的oplog,那么这个sync source同样会被拉入黑名单,并重新选举。
  3. 在initial sync,rollback或者recovery期间,结点都将会设置OpTime(local.repliaset.minValid表),其中begin字段存在则表示不一致状态,如果存在不一致状态,那么secondary需要检查这个ts在primary上是否存在。关于minValid的知识,主要是用于检测需要的oplog还是否存在,具体请参考MongoDB Primary为何持续出现oplog全表扫描
  4. 拉取sync source的RollbackID用于检测source是否发生回滚

如果结点落后所有结点太多,则无法选择sync source,需要人为介入,比如执行resync命令(由于各种问题,在3.6版本之后resync被废弃了)。BackgroundSync会一直重复选举,直到找到一个sync source,并启动OplogFetcher进行增量的拉取。

2. OplogFetcher

  secondary通过OplogFetcher从主上进行拉取oplog,其原理就是采用find+getMore命令来进行。最初的find请求必须有返回(>=1个文档),如果没有则表示现在的源不适合作为sync source(源落后于secondary);如果有,但是拉取的第一条oplog不等于secondry上的最后一条,那么说明当前结点的数据需要进行回滚(回滚到上一个stable checkpoint)。secondary需要对拉取的结果进行检查,以判断目前的源是否ok,以及是否需要回滚。
  OplogFetcher采用{awaitData: true, tailable: true}配置项进行长期拉取,如果出错将会重启Fetcher(最多3次)。OplogFetcher是跑在BackgroundSync线程内部,只要是secondary节点位于SECONDARY状态(其实还包括STARTUP2)该线程会一直循环跑。除非碰到:

  1. 拉取的oplog位点在源端丢了 (重新全量);
  2. 拉取的oplog不等于secondary上的最后一条(需要回滚)
  3. 网络等原因出错(重试)
  4. secondary结点退出(bgsync线程也会退出)

  OplogFetcher拉取完数据后,并不是直接应用,而是将数据塞入到OplogBuffer中,OplogBuffer是一个内存的block queue(大小256MB),这个队列写满了相当于拉取就暂停了。有独立的线程从这个队列里拉取并进行apply。

3. OplogBatcher

  OplogBatcher死循环执行,负责从oplog buffer里面读取数据,并进行应用。SyncTail会启动多个线程进行应用,一个batcher对oplog没必要保证顺序,但需要对同一个oplog._id的保证顺序,保证对同一个文档的操作放在一个线程里面执行。DDL的batch size等于1;同类型的操作比如insert操作会batch一定条数以后再进行批量写入以提高吞吐。
  以下是写入的具体过程:

  1. 从oplogBuffer中获取下一批batched oplog
  2. 获取并发写锁
  3. 设置oplogTruncateAfterPoint为上一次写成功的最后一条oplog。用于同步中间出错,重启后将会把oplog阶段到这个位点,这个位点之后的Oplog都会丢失。
  4. 写batched oplog到oplog表中(这一步叫write)
  5. 清除oplogTruncateAfterPoint并更新minValid为最后一条oplog。begin字段存在表示中间发生中断会存在不一致状态,从begin重新进行拉取。{ ts: lastOplogTimestamp, begin: firstOplogTimestamp}
  6. 多线程并发apply Oplog,对于同一个文档的oplog保证顺序,不是同一个文档的将会并发apply以提高写入性能。写入之前同类型的操作还会进行聚合,比如insert操作会聚合一定的条数再进行写入。这个过程将会抢占PBWM(Parallel Batch Write Mode)锁,然后再对一个batch内部进行并发写。(这一步叫apply)
  7. 引擎flush掉journal。
  8. 保存appliedThrough位点,用于标识当前这一批batch已经成功写入。同时minValid的begin字段将会被删除,以表示当前是一个一致的状态。
  9. 推进全局时间戳到lastApplied

4. 几个位点的区别

several_point

  • stableCkpt:表示这个是wiredTiger做了的checkpoint。
  • lastCommit:表示这个位点的数据已经复制到大多数节点。一旦回滚将会保证能回滚到lastCommit
  • lastApplied:用于表示这个位点之前的都是可见的。推进在4.0以前是通过粗暴加锁实现的,4.0以后通过wiredTiger提供的多版本读能力实现的。
  • appliedThrough:表示一批batch的并发回放结束,但不一定可见
  • oplogTruncateAfterPoint:发生中断这个位点开始的后面oplog会被截断。

Q: 如何保证发生回滚,一定能回滚到lastCommit?

A: stableCkpt是一个全量的镜像,回滚将会加载这个镜像,stableCkpt到lastCommit是通过增量oplog进行恢复。也就是说通过全量+增量恢复到这个lastCommit位点。

Q: 并发写入的时候,是先write oplog还是先apply数据?

A: 先write oplog,然后再apply。如果重启将会把appliedThrough以后的oplog阶段掉重新应用。

说明:

转载请注明出错:http://vinllen.com/mongodbzhu-cong-fu-zhi-zhi-zeng-liang-tong-bu/

参考:

https://github.com/mongodb/mongo/blob/master/src/mongo/db/repl/README.md
https://www.percona.com/blog/2018/10/10/mongodb-replica-set-scenarios-and-internals/
https://yq.aliyun.com/articles/226367


About the author

vinllen chen

Beijing, China

格物致知


Discussions

comments powered by Disqus