Devops必须留意的Mongo副本集Resync的坑

Devops通常不多时间会花在数据库的部署上,只有到了不起不去考虑的状况下,才会去考虑如何调整数据库,以适应业务的发展。mongodb自己就很适合Devops,大部分状况下,部署基本按照说明操做一下便可。但实际操做起来,其实还有会有一些坑,好比Resync。mongodb

正常同步和oplog

mongo副本集,在正常工做的状况下,是以一种不断的、异步的方式进行同步。每一个副本都会不断的记录本身进行的操做进入到oplog表里;Secondary副本就会不断的从Primary副本那里同步最新的操做,从而完成整个副本集的同步。固然Secondary的副本也能够选择从其余的Secondary副本同步,由于每一个副本都会记录oplog。详细的描述能够参考官方文档Replica Set Data Synchronization数据库

clipboard.png

Oplog是一个特殊的固定大小的collection,固定大小意味着,新的操做记录的写入会致使最老的操做记录的删除,以保证oplog的大小。这个值若是不去设置,mongo会自动根据硬盘大小的5%来设定。大部分状况下没有什么问题,但有一个很是重要的设(da)定(keng):网络

oplog一旦大小固定,那么只能经过重启+配置来进行修改架构

为何这会是一个坑,后面会继续讨论。异步

同步延迟lag和optime

副本集之间通常经过网络链接,副本集之间的性能也有可能有差别(固然最好不要有),因此同步操做有可能出现毫秒级别的延迟,甚至到1s以上,这个能够经过在任意一个副本集上执行性能

rs.status()

来查看全部副本集的同步状态。这个打印出的各个副本的optime,就是这个副本最后一条操做执行的时间,Secondary和Primary之间optime的时间差,其实就是同步延迟。阿里云

同步延迟通常状况下,顶多也就一两秒,可是一些异常状况,例如宕机、长时间过载overload,可能会致使这个时间愈来愈长。这里,咱们的oplog的巨大做用就显现出来了!spa

Secondary和Primary之间的同步差,最大不能超过Primary的oplog能存储的条数操作系统

注意!由于Secondary是从Primary同步oplog,因此,这里只与Primary的oplog大小有关,与Secondary自身记录的oplog无关!固然,若是Secondary是从其余的Secondary同步数据,那么至于同步目标的oplog有关。日志

为了帮助用户直观的理解oplog里面存储了多少条操做,mongo还额外提供了两个数据:

  1. tFirst 第一条oplog的时间

  2. tLast 最后一条oplog的时间

这两个数据,能够经过在primary上执行:

db.getReplicationInfo()

得到。tLast - tFirst就是mongo同步机制所容许你进行停机同步数据的最大时间,固然这个时间不是固定的,若是当前的负载很低,至关于相同的oplog表能够存更长时间内的操做数据,就会给你留更多的停机操做时间。

clipboard.png

上图中,Secondary落后于Primary,也就是说,同步延迟有10分钟(两个optime相减),但此时,Primary上存有最近20分钟的oplog,那么Secondary经过获取这些oplog,仍然可以在短期内遇上Primary的进度。

可是,一旦optime的差距超出了Primary的tFirst,状况就不妙了,以下图:

clipboard.png

此时,自动的同步已经没法完成同步了(stale),必须执行手动操做Resync。并且Secondary已经降级为Recovering,将没法接受请求,以及不能变成master。

Resync机制

Resync机制官网有详细的介绍,基本思路就是把数据拷贝过来,再进行上面的oplog的同步。例如:

  1. 使用磁盘快照,把快照的数据库文件直接覆盖到Secondary上,重启Secondary

  2. 使用Initial Sync,把Secondary的数据清空,让mongo自动从0开始,从新同步全部数据

磁盘快照看起来很美好,可是是mongo的数据存储是分配后就不返回的,也就是说实际占用的磁盘空间要比真实数据的大小要大,使用操做系统的scp也好rsync也好,这些无用的空间也会被复制,耽误复制的时间。除此以外,创建快照自己也须要耗时,反正在阿里云上建快照并不快,200G的数据大约要1小时多。

而Initial Sync是mongo之间拷贝表数据,拷贝完了就地重建索引,因此至关于只传输了真实的表数据,连索引数据都不用传输,从总体的复制时间来看更加节省,可是会对拷贝对象Primary有一些性能影响,但毕竟只是读,并且不须要Primary停机。

Resync的大坑

不管使用上面的哪一种Resync机制,思路都是一致的,经过某种快速的方式同步更多的数据,而后剩下的使用oplog弥补在执行操做时的新操做。看起来很美好,而实际的执行过程当中,若是操做的时间,要大于oplog所记录的时间,怎么办?将永远没法不停机Resync成功!

clipboard.png

这里Initial Sync为何也不能成功呢?其实在Initial Sync的日志中,就能够看出来,在STATUP2的状态,就是一张表一张表的拷数据,也就是说,就算拷贝过程当中的数据已经同步过去了,当拷贝下一张表时,上一张表的数据其实已通过期了。而当数据量很大的状况下(其实不须要太大,几百G),整个拷贝过程也要持续数小时,此时若是oplog的记录时间低于STARTUP2所须要花费的时间,恭喜你,你中奖了。

固然,若是你能有一台正常同步数据的Secondary,新的机器指向这台也是能够的,可是你的架构是一台Arbiter一台Primary一台Secondary的话……就没办法了,只能期望Primary了。别问我为何知道,我就是知道。(╯‵□′)╯︵┴─┴

遇到这种状况怎么办?

  1. 半夜Primary停机,同步数据。这对于DBA也都不奇怪,只是在用了mongo集群后没享受到mongo的便利。固然,到了半夜负载降低,至关于oplog容许的操做时间变长了,也许不用停机。

  2. 若是有不少冗余数据、日志数据什么的,能够删除,从而下降Initial Sync花费的时间,那也是很值得尝试的!

坑的真正缘由

上面的坑,其实主要是在于oplog的值相对于数据量太小的时候会出现。通常默认状况下,oplog取磁盘大小的5%彷佛没太大问题。坑在哪呢?

  1. 磁盘扩容

  2. 高负载

一开始我就提到,oplog的存储大小一旦肯定是不会改的,也就是说,一旦随着业务的发展,进行了磁盘扩容,或者移动到了一块更大的硬盘上,oplog的大小不会随之改变!

一旦两件巧合的事情遇到了一块儿:磁盘曾经扩容且没有额外考虑oplog;须要新增副本或者副本stale了;此时正常的机器只有一台Primary;就会变成一件解决起来不那么轻松的事情了。

而高负载也是潜在的另一个可能,因为负载太高,虽然oplog存储很大,可是实际上oplog所支持的停机操做时间变少了,此时也会遇到相同的状况。

防坑指南

总结一下,在用mongo副本集群的时候,随着数据的增加、磁盘的扩容,一方面在考虑sharding的同时,必定要注意当前的oplog存储是否够用,提早为下一次部署策略更换准备好,给下一次的操做留够时间。特别是Devops,平时没时间管的,必定要未雨绸缪呀。

相关文章
相关标签/搜索