天天看点

MongoDB Secondary 延时高(同步锁)问题分析

secondary 拉取到一批 oplog 后,在重放这批 oplog 时,会加一个特殊的 <code>lock::parallelbatchwritermode</code> 的锁,这个锁会阻塞所有的读请求,直到这批 oplog 重放完成。这么做的原因有2个

尽量避免脏读,等一批 oplog 重放完后,这批数据才允许用户读到。

基于上述问题,某些用户在读取备节点时,可能遇到因为 secondary 重放 oplog 占用特殊锁时间较长,导致读取的延时变长。

上述场景除了会影响 secondary 上的读请求,如果 priamry 上写请求指定了 writeconcern 来写多个节点({w: 2+}),而 secondary 又一直阻塞在创建索引上,导致其后的oplog 重放都要等待创建索引结束,从而主上的写入也阻塞。

当主上写入并发很大时,secondary 每次能拉到很多条 oplog,然后并发重放,重放一条的耗时可能很小,但累计起来一次重放上百、上千条 oplog,耗时就会高很多,而重放过程中,secondary 上读请求都是要阻塞等待的,所以总体看上去,「secondary 上平均延时,可能比 primary 上更长点」(这就是为什么很多用户在写入比较多时,会发现读secondary 比 读praimry 更慢),但只要延时在可接受范围内,这个问题并无影响,而且根据云上用户使用的经验,绝大部分用户都是感受不到这个差异的。

但有一种情况值要注意

MongoDB Secondary 延时高(同步锁)问题分析

从上面的例子可以看到,一条 update 操作,指定了 {multi: true} 选项,更新了2个匹配的文档,针对每个文档都产生了一条 oplog(主要为了保证 oplog 幂等性),如果匹配的文档有成千上万条,就会产生对应数量的 oplog,然后 secondary 拉取这些 oplog 并重放;这个场景下,update 的开销在secondary 上被放大多倍,此时secondary 的读延时可能会受比较大的影响。

从上述的例子可以看出,secondary 在某些场景下会出现读延时很高的情况,那么当实际遇到问题时,如何判断问题就是 secondary 重放 oplog 占用锁时间太长导致呢?

<a href="https://yq.aliyun.com/articles/57755?spm=5176.8091938.0.0.p8qw7y">mongodb复制集同步原理解析</a>

<a href="https://yq.aliyun.com/articles/55821">secondary节点为何阻塞请求近一个小时?</a>

<a href="https://www.aliyun.com/product/mongodb?spm=5176.8142029.388261.35.ayuymx">阿里云数据库 mongodb 版</a>