1.预备知识
1.1 同步分2种:
1)intial sync,可以理解为全量同步。
2)replication,追同步源的oplog,可以理解为增量同步。
Secondary 在什么情况下会intial sync?
a)新加入节点,无任何oplog
b)local.replset.minvalid集合里_initialSyncFlag字段设置为true
c)内存标记initialSyncRequested设置为true
对应下面3种情况:
1.新节点加入,无任何oplog,此时需要intial sync。
2.initial sync开始时,会主动将_initialSyncFlag字段设置为true,正常结束后再设置为false;如果节点重启时,发现_initialSyncFlag为true,说明上次全量同步中途失败了,此时应该重新进行initial sync。
3.当用户发送resync命令时,initialSyncRequested会设置为true,此时会重新开始一次initial sync。
* intial sync流程(对应3.2 版本)
1 ) 全量同步开始,设置minvalid集合的_initialSyncFlag
2) 获取同步源上最新oplog时间戳为t1
3) 创建集合(包含_id索引),全量同步集合数据 (此步耗时)
4) 获取同步源上最新oplog时间戳为t2
5) 重放[t1, t2]范围内的所有oplog
6) 获取同步源上最新oplog时间戳为t3
7) 重放[t2, t3]范围内所有的oplog
8) 建立集合其他所有索引 (此步耗时)
9) 获取同步源上最新oplog时间戳为t4
10) 重放[t3, t4]范围内所有的oplog
11) 全量同步结束,清除minvalid集合的_initialSyncFlag
intial sync结束后,Secondary会不断的拉取主库上新生成的oplog并重放,转成Replication。
* Replication 流程:
上图很清晰的看到Repliction的流程。
producer thread:这个线程不断的从同步源上拉取oplog,并加入到一个BlockQueue的队列里保存着。
replBatcher thread:这个线程负责逐个从producer thread的队列里取出oplog,并放到自己维护的队列里。
sync线程将replBatcher thread的队列分发到默认16个replWriter线程,由replWriter thread来最终决定哪些可以并发重放oplog。
从上面看出,这是个PC(生产者-消费者模型),因为拉取主库上的线程是单线程,如果把重放也放到拉取线程里,性能跟不上去,所以设计加入producer thread、replBatcher thread,提升复制性能。
replBatcher thread 主要是控制哪些可以并发。
replWriterThreadCount:MongoDB 3.2开始多线程复制,取值1-256,默认16。
1.2 全量同步的改进:
Mongodb 3.2 复制可以表述为如下:
记录最新oplog(t1),创建集(含_id索引),记录最新oplog(t2),重放[t1,t2]之间的oplog,记录最新oplog(t3)
重放[t2,t3]之间的oplog,拷贝集合数据,记录最新oplog(t4),重放[t3,t4]之间的oplog
创建其他所有索引
拉取增量oplog并应用
Mongodb 3.4 复制可以表述为如下:
创建集合(包含所有索引)
拷贝集合数据
应用本地缓存的oplog
拉取主库的oplog至本地临时集合
其实在上图3.2版本会在每个阶段都会拷贝增量的oplog。
从上面可以看出:3.4 相对于3.2 有2个大改进,
1) 3.4在拷贝数据的同时创建所有的索引,3.2是先创建_id索引,再拷贝集合数据,拷贝集合数据后再创建其他所有索引。
2) 3.4在拷贝数据的同时会把主库增量的oplog 拷贝到本地local库下。等待集合数据全部拷贝完,直接读取本地local库下临时集合中的oplog。目的:提升追增量oplog的效率,同时也可以避免主库上oplog_size 不够大的情况。
1.3 优化主从复制
1.3.1 repl Buffer size的大小:默认是256MB。
hhlshd2:SECONDARY> db.serverStatus().metrics.repl.buffer.maxSizeBytes
NumberLong(268435456)
* 这个暂时没找到可以调整的参数。
1.3.2 调整从库replWriter 的数量:
参数:replWriterThreadCount 默认是16,从3.2 开始引入,取值范围: 1-256
hhlshd2:SECONDARY> db.adminCommand({getParameter:1, replWriterThreadCount:true})
{ "replWriterThreadCount" : 16, "ok" : 1 }
1.3.3 replApplyBatchSize:批量oplog的条数。
hhlshd2:SECONDARY> db.adminCommand({getParameter:1, replApplyBatchSize:true})
{ "replApplyBatchSize" : 1, "ok" : 1 }