一次MongoDB故障的复盘

  • 时间:
  • 浏览:1

而上层业务将A、B三个多 接口的调用包装后的场景将会SecondaryPreferred的导致 ,导致 B接口异常,最终影响了业务的正常对外服务。

调用接口B(可简单认为insert了一条数据b,但在insert完后 检查了接口A返回的数据a的_id)

体现了若干游标定义

9月初你们都 的某客户反馈,部署在其私有云中的Teambition系统居于异常。该客户通过调用系统的开放API包装了一层业务向内控 提供,此时三个多 连续接口调用之间经常总出 了数据一致性异常,导致 包装的上层业务无法正常使用,而此时Teambition系统并都是业务使用均正常。

验证与总结

看起来该值的计算并这样这种问题报告 ,否则在某类场景下,db.printSlaveReplicationInfo()的返回值(即主从延迟)并这样这样贴切。如:

主从好友克隆延迟是三个多 非常严重且影响业务的指标,此处显示的5s的时间在有读写分离的场景中将会可里都都都可不可以 认为是非常影响业务的。

流量稳定无暴增

此时primary的optimeDate为ISODate(“2018-10-24T07:00:1000Z”),而将会你们都 执行该命令的完后 各个从节点完成同步,所以 各个从节点的optimeDate为ISODate(“2018-10-24T07:00:05Z”)。于是乎你们都 得到了这样 的返回

类型为getmore

SecondaryPreferred,将接口B的请求发向Primary。

不过这反而致使整个排查过程变得更加有分享和借鉴价值。在这里分享我想要们 希望可里都都都可不可以 我想要们 处里踩坑。

根据迟来的监控指标确认cursor的异常并分析

你们都 知道oplog是这样严格意义上的索引,所以 这类游标在第一次建立的过都是比较耗时,持续trace到最后的末尾的过都是居于tailabled和awaitData请况,此时实时trace数据的getmore就应该居于相对稳定的快速请况。

在此,你们都 对故障的排查进行一次复盘。

在ISODate(“2018-10-24T07:00:05Z”)进行了三个多 写操作a(insert/update/delete)

至此,这种问题报告 算是全版落下帷幕,总结一下踩的坑以及何如处里

我想要们 来梳理下这次故障的前因后果。

看起来从节点落后了主节点25秒的时间,十分严重。否则将会场景的特殊性,此时落后的是三个多 写操作,否则将会执行时间的导致 ,该写操作后续减慢也完成了同步。此时的25secs对于集群来说影响甚微。

当时就是感觉到该服务使用游标的最好的法子居于不妥,还未能全版与问题报告 关联起来,记得上文中提到当时的整体常用监控指标都十分“健康”(这里埋下了三个多 伏笔),此时从客户处有获知了这样 监控指标–cursor数,客户告知当时主节点cursor总数为71000k+个。

接到反馈后你们都 与对方同步了其包装的业务逻辑,大体为:

此前该业务经常总出 过异常,从而导致 服务不断异常与重启,部分了71000k+个notimeout的cursor,而每个cursor是有额外内存的消耗,从而导致 主节点内存被无效的cursor占用(此处占用的内存全版都是wt cache,就是剩余的ram,所以 此时监控的wt cache的相关指标全版都是正常的),否则每个请求除了利用wt cache外还是会产生内控 ram的消耗,如connection,结果集临时存储等。此时从节点producer thread来拉取oplog的速率单位降低,进一步造成了主从延迟的产生。

Connections连接数稳定,并无暴增暴减

从节点的磁盘性能不够(客户在当时并未提供io和吞吐请况,不过按照当时的低位qps,不应当会有磁盘性能问题报告 ,暂时排除)

主要的慢查询主要的条件为如下,大多为getmore。

首先从最直观的问题报告 进行入手,观察到 db.printSlaveReplicationInfo()返回的结果和客户处集群的可视化监控显示主从延迟不稳定,会不时飙升至5s,如:

合理利用读写分离,MongoDB的读写分离并全版都是真正意义上的将读写压力全版分离,还要明确业务对于数据一致性的需求,一致性要求强的场景处里SecondaryPreferred将会通过业务型态的调整处里该问题报告 。

将会该上层业务重要性较高,摆在肩头的首要请况是恢复该业务的可用性,综合考虑后,得出了如下的几种处里最好的法子:

接下来尝试分析为啥会经常总出 主从延迟,从完后 梳理的集群请况来看,除去主从延迟和local.oplog.rs的slow query,这种指标均十分健康(并全版都是)。

此时你们都 正好在1ms后于primary节点中执行了db.printSlaveReplicationInfo()

db.printSlaveReplicationInfo()所体现的主从延迟并非 一定真的代表延迟,否则该监控指标任何完后 都还要提起120%的关注度。

方案2还要客户包装上层业务进行修改,而客户的接口调用场景极多,故而放弃。(虽然放弃该方案,否则还要提醒的是,在任何涉及到数据一致性要求的业务场景都还要充分考虑到异常和将会性,在业务层尽将会的规避。这也是为这种有主从延迟的完后 Teambition系统并都是并未)

通过慢查询定位异常业务

深究与排查

接下来你们都 将目光聚焦到了local.oplog.rs的慢查询上。

回归到此次故障的场景,虽然db.printSlaveReplicationInfo()居于不准确的将会,否则以当时的pqs请况来判断,应该是真实经常总出 了主从延迟。

不调整接口B的逻辑,在上层调用接口A和B之间加一层保护,通过业务的手段处里在短时间内进行连续的调用,通过业务型态的微调拉长A与B接口调用之间的时间轴,如:先交由用户配置所需字段,在提交时再进行任务_id的判断与绑定

使用cursor完后 并非 使用noCursorTimeout能力,为cursor设置合理的timeout,由应用来控制timeout后的重试机制。以此来保证cursor的合理利用。

前段时间笔者的客户遇到了三个多 主从延迟导致 的业务故障,故障的导致 这样 是较为简单易查的,否则将会客户环境的安全、保密性要求,监控和指标不到间接获知,信息比较片段化与迟缓。

不过你们都 也还要额外注意,该值不为0并非 能1000%代表系统居于主从延迟问题报告 。你们都 先来看看db.printSlaveReplicationInfo()的结果是何如获取的。

梳理后总结为:

背景(简单介绍背景请况)

集群节点间网络延迟(客户网络工程师反馈节点间网络正常,该将会排除)

退还SecondaryPreferred,以保证调用接口正常

验证2:在tailable,awaitData和noCursorTimeout定义下,服务异常重启会导致 cursor不被释放,进而造成cursor堆积。

主节点上居于这种异常的慢查询,影响了从节点上producer thread拉取oplog的速率单位,从而导致 延迟(最有将会)

cursor的堆积造成了异常的内存消耗(wt cache外的内存),进而影响到了从节点producer thread的速率单位,从而导致 了主从延迟的产生。

调用接口A(可简单认为insert了一条数据a)

Resident Memory稳定,且整体eviction请况良好

居于local.oplog.rs的slow query

验证1:小量cursor导致 wt cache外的ram资源紧张,进而造成主从延迟。

你们都 知道MongoDB的主从同步为异步同步,主从节点之间延迟在所难免,否则正常请况下延迟时间大多为毫秒级别,大多无需影响到正常业务。此时的问题报告 透露着三个多 信息,该MongoDB集群居于异常,否则将会第一时间无法获取集群请况,具体的异常暂时无从得知。

主从延迟不稳定,有时飙升至5s

而代码中游标加入了这种属性

MongoDB的读写分离并全版都是真正意义上的将读写压力全版分离,Primary上的写最终还是以oplog的形式在从上进行了回放,读写分离的效果有限,所以 在判断集群整体压力居于合理范围内,你们都 考虑退还

集群正居于写操作极为空闲的阶段

背景

临时应对与考量(该请况下快速恢复业务的选用)

从里面的特点你们都 可里都都都可不可以 判断这类说说无需是正常业务场景,也全版都是A或B接口触发的,回顾下整个服务体系中会对oplog.rs有这样查询的为trace oplog的场景,来源于三个多 从mongodb同步数据到elasticsearch的应用。该应用会实时trace oplog 并进行同步。检查了下服务代码,部分如下:

一般主从延迟有以下几种将会导致 :

Cache Activitiy稳定无暴增

而后在ISODate(“2018-10-24T07:00:1000Z”)才进行了下三个多 写操作b

临时应对与考量

在上述并都是方案中,你们都 选用了方案1“退还SecondaryPreferred”来作为应急处里方案。导致 如下:

在mongodb源码中定义了这样 的计算最好的法子

主节点有小量并发写导致 从节点无法及时追上(当时qps居于低位,replWriter为默认守护进程池数,不应居于瓶颈,暂时排除)

该服务异常重启多次造成了primary中cursor的堆积。

在初步获取到了结论后,你们都 刚开始进行相应的验证。

处里对local库内表的操作,将会有骚操作的需求,还要明白本人在做这种,一块儿将骚操作安排在隐藏节点中进行(将会此次最初你们都 的业务使用的是隐藏节点,该问题报告 就无需直接影响到业务)且新版本可里都都都可不可以 使用changestream来满足这类trace oplog的需求。

slow query内getmore居于这种属性。

你们都 可里都都都可不可以 看过,基准时间是primary节点的optimeDate(将其定义为startOptimeDate),各个从节点的延迟是按照startOptimeDate – st(也就是各个从节点的optimeDate)进行计算(不包括arbiter)。

问题报告 为在第二步的过程中,无法查找到第一步中”新建的任务_id”。考虑到该客户使用的是MongoDB好友克隆集架构,否则第十个 接口的query使用了SecondaryPreferred,将会此时你们都 无法连接到数据库查看指标也无法查看过客户处该mongodb集群的监控信息,根据已有信息初步判断故障导致 将会为“主从延迟”导致 的数据一致性问题报告 。

当时涉及到了主从延迟,慢查询,cursor的不当使用等mongodb问题报告 ,本文将从这几次方面全面复盘整个故障的排查过程,其含高高了如下内容:

同步业务代码在建立cursor时,使用了tailable,awaitData,且noCursorTimeout的定义,致使cursor在业务这样主动close的请况下,将永久居于。(否则此时cursor监听在primary节点中,后续你们都 新增了hidden member用于该业务的请求)。

将会该服务采用pm2进行服务运型态管理,你们都 不断向其发送异常关闭的signal,pm2在其error后不断重启。期间观察db.serverStatus().metrics.cursor请况,发现db.serverStatus().metrics.cursor.open.noTimeout值持续上升堆积。确认了cursor堆积的导致 。

可里都都都可不可以 看过上述慢查询有几次特点:

而当时系统内小量的getmore成为了slow query,考虑到当时整体qps请况,你们都 对slow query和代码进行仔细的查看。发现了端倪:

是针对oplog.rs的慢查询

将会该集群环境的监控以及请况无法直接查看不到通过客户转述,这种过程遗漏了所以 信息也造成了所以 时间的浪费,在有将会的请况下,mongodb的使用者还是还要对mongodb的全面指标进行监控,魔鬼往往隐藏在细节中。

将会短时间内你们都 无法查看客户处mongodb集群的请况与监控指标,方案3实现周期长于前两者,故而放弃。

主从延迟分析与排查,并通过部分mongo源码佐证推断

在你们都 将SecondaryPreferred的配置退还后,上层业务恢复了正常。你们都 也辗转获得了客户处mongodb集群的部分监控信息、请况等。

同步服务中不当的使用了noCursorTimeout的cursor。

为了释放cursor你们都 将节点实例重启并关闭同步服务,持续观察后,确认主从延迟请况不再经常总出 恢复正常。将SecondaryPreferred重新启用,业务也一切正常。

至此,你们都 大体推断出了根因。

QPS居于低位运行,且业务场景读远大与写