数据技术嘉年华等你来

预告:11.16-17日,北京市东三环中路61号富力万丽酒店,相聚数据技术嘉年华,(99元票务)免费购票倒计时,点击查看大会详情。

张甦老师带来主题“双剑合璧带你走进MySQL和MongoDB的世界”,敬请期待~

点击“阅读原文”免费购票。

前段时间笔者的客户遇到了一个主从延迟导致的业务故障,故障的原因本来是较为简单易查的,但是由于客户环境的安全、保密性要求,监控和指标只能间接获知,信息比较片段化与迟缓。

不过这反而致使整个排查过程变得更加有分享和借鉴价值。在这里分享给大家希望可以让大家避免踩坑。

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

  • 背景(简单介绍背景情况)

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

  • 深究与排查

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

    • 通过慢查询定位异常业务

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

  • 验证与总结

背景

9月初我们的某客户反馈,部署在其私有云中的Teambition系统存在异常。该客户通过调用系统的开放API包装了一层业务向内部提供,此时两个连续接口调用之间出现了数据一致性异常,导致包装的上层业务无法正常使用,而此时Teambition系统本身业务使用均正常。

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

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

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

现象为在第二步的过程中,无法查找到第一步中”新建的任务_id”。考虑到该客户使用的是MongoDB复制集架构,并且第二个接口的query使用了SecondaryPreferred,由于此时我们无法连接到数据库查看指标也无法查看到客户处该mongodb集群的监控信息,根据已有信息初步判断故障原因可能为“主从延迟”导致的数据一致性问题。

临时应对与考量

我们知道MongoDB的主从同步为异步同步,主从节点之间延迟在所难免,但是正常情况下延迟时间大多为毫秒级别,大多不会影响到正常业务。此时的现象透露着一个信息,该MongoDB集群存在异常,但是由于第一时间无法获取集群状态,具体的异常暂时无从得知。

由于该上层业务重要性较高,摆在面前的首要情况是恢复该业务的可用性,综合考虑后,得出了如下的几种处理方式:

  1. 取消SecondaryPreferred,以保证调用接口正常

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

  3. 解决主从延迟。

在上述三种方案中,我们选择了方案1“取消SecondaryPreferred”来作为应急处理方案。原因如下:

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

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

  • 方案2需要客户包装上层业务进行修改,而客户的接口调用场景极多,故而放弃。(虽然放弃该方案,但是需要提醒的是,在任何涉及到数据一致性要求的业务场景都需要充分考虑到异常和可能性,在业务层尽可能的规避。这也是为什么有主从延迟的时候Teambition系统本身并未)

  • 由于短时间内我们无法查看客户处mongodb集群的状态与监控指标,方案3实现周期长于前两者,故而放弃。

深究与排查

在我们将SecondaryPreferred的配置取消后,上层业务恢复了正常。我们也辗转获得了客户处mongodb集群的部分监控信息、状态等。

梳理后总结为:

  • 流量稳定无暴增

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

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

  • Resident Memory稳定,且整体eviction状态良好

  • Cache Activitiy稳定无暴增

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

  • 存在local.oplog.rs的slow query

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

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

主从复制延迟是一个非常严重且影响业务的指标,此处显示的5s的时间在有读写分离的场景中已经可以认为是非常影响业务的。

不过我们也需要额外注意,该值不为0并不能100%代表系统存在主从延迟问题。我们先来看看db.printSlaveReplicationInfo()的结果是如何获取的。

在mongodb源码中定义了这样的计算方式

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

看起来该值的计算并没有什么问题,但是在某类场景下,db.printSlaveReplicationInfo()的返回值(即主从延迟)并没有那么贴切。如:

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

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

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

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

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

看起来从节点落后了主节点25秒的时间,十分严重。但是由于场景的特殊性,此时落后的是1个写操作,并且因为执行时间的原因,该写操作后续很快也完成了同步。此时的25secs对于集群来说影响甚微。

回归到此次故障的场景,虽然db.printSlaveReplicationInfo()存在不准确的可能,但是以当时的pqs情况来判断,应该是真实出现了主从延迟。

接下来尝试分析为何会出现主从延迟,从之前梳理的集群状态来看,除去主从延迟和local.oplog.rs的slow query,其他指标均十分健康(并不是)。

一般主从延迟有以下几种可能原因:

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

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

  • 主节点有大量并发写导致从节点无法及时追上(当时qps处于低位,replWriter为默认线程数,不应存在瓶颈,暂时排除)

  • 主节点上存在某些异常的慢查询,影响了从节点上producer thread拉取oplog的效率,从而导致延迟(最有可能)

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

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

可以看到上述慢查询有几个特点:

  • 是针对oplog.rs的慢查询

  • 类型为getmore

  • 体现了若干游标定义

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

我们知道oplog是没有严格意义上的索引,所以这类游标在第一次建立的时候会比较耗时,持续trace到最后的末尾的时候会处于tailabled和awaitData状态,此时实时trace数据的getmore就应该处于相对稳定的快速状态。

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

slow query内getmore存在这个属性。

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

当时只是感觉到该服务使用游标的方式存在不妥,还未能完整与现象关联起来,记得上文中提到当时的整体常用监控指标都十分“健康”(这里埋下了一个伏笔),此时从客户处有获知了另一个监控指标–cursor数,客户告知当时主节点cursor总数为7200k+个。

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

  • 同步业务代码在建立cursor时,使用了tailable,awaitData,且noCursorTimeout的定义,致使cursor在业务没有主动close的情况下,将永久存在。(并且此时cursor监听在primary节点中,后续我们新增了hidden member用于该业务的请求)。

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

验证与总结

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

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

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

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

由于该服务采用pm2进行服务运行态管理,我们不断向其发送异常关闭的signal,pm2在其error后不断重启。期间观察db.serverStatus().metrics.cursor状态,发现db.serverStatus().metrics.cursor.open.noTimeout值持续上升堆积。确认了cursor堆积的原因。

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

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

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

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

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

至此,这个问题算是完整落下帷幕,总结一下踩的坑以及如何避免

  • 使用cursor时候不要使用noCursorTimeout能力,为cursor设置合理的timeout,由应用来控制timeout后的重试机制。以此来保证cursor的合理利用。

  • 由于该集群环境的监控以及状态无法直接查看只能通过客户转述,这个过程遗漏了很多信息也造成了很多时间的浪费,在有可能的情况下,mongodb的使用者还是需要对mongodb的全面指标进行监控,魔鬼往往隐藏在细节中。

  • 避免对local库内表的操作,如果有骚操作的需求,必须明白自己在做什么,同时将骚操作安排在隐藏节点中进行(如果此次最初我们的业务使用的是隐藏节点,该问题就不会直接影响到业务)且新版本可以使用changestream来满足类似trace oplog的需求。

  • db.printSlaveReplicationInfo()所体现的主从延迟并不一定真的代表延迟,但是该监控指标任何时候都需要提起120%的关注度。

  • 合理利用读写分离,MongoDB的读写分离并不是真正意义上的将读写压力完全分离,需要明确业务对于数据一致性的需求,一致性要求强的场景避免SecondaryPreferred或者通过业务形态的调整避免该问题。

end

/

作者简介

/

周李洋(eshujiushiwo):

Teambition运维负责人

MongoDB Master

MongoDB中文社区联席主席

MongoDB上海用户组发起人

MongoDB Certified Professional

DTCC 演讲嘉宾

关注数据库技术,自动化运维,容器,servicemesh等领域

转载自:Mongoing中文社区。


近期文章

删了库之后,不要着急跑路

一道面试题看数据库性能和安全的方方面面

Percona发布XtraBackup for MySQL 8.0

独立发布的Oracle严重CVE-2018-3110公告

Oracle宣布在云上正式上线 自治事务处理数据库

为什么看了那么多灾难,还是过不好备份这一关?

记一次MongoDB故障排查的过程相关推荐

  1. 如何利用秒级监控进行mongodb故障排查

    摘要: 在我们平时的数据库使用当中,监控系统,作为排查故障,告警故障的重要辅助系统,对dba.运维.业务开发同学进行问题诊断.排查.分析有着重要的作用.并且一个监控系统的好坏,也很大程度上影响了能否精 ...

  2. 记一次AD域域管理员密码更改导致某系统群集管理器故障排查解决过程

    环境描述 某公司有一套系统,2台Windows2003系统,采用自带的群集管理器功能实现双机热备功能,正常情况下,服务器10.1.1.1承载中间件应用服务,服务器10.1.1.2承载数据库服务,仅当其 ...

  3. 记一次网站故障排查过程(nginx 504状态码、 upstream timed out (110: Connection timed out)以及jbd2引起IO高

    一.问题描述 客户侧反馈无法正常访问系统,页面转圈,时好时坏,访问不稳定. 二.系统环境: 机器环境:UOS . nginx .php(对接其他服务器kingbase .钉钉.redis .KF) E ...

  4. 坑爹坑娘坑祖宗的87端口(记一次tomcat故障排查)

    参考:http://www.cnblogs.com/liuxianan/p/err_unsafe_port.html?ref=myread 问题来源 因为经常有各种各样的大小项目要跑,全部放一个tom ...

  5. 信息系统故障分析案例---------记一次性能检测系统故障排查

    2018年10月10日凌晨2点接到信调值班员电话,单位信息运维统一监管(I6XXX)系统报警显示公司门户和网站系统性能检测报警,页面访问响应时长和模拟登录功能异常,实际情况是网站和门户系统运行正常,稍 ...

  6. vmware 搭建k8s无法ping通子节点_一波四折 —— 记一次K8S集群应用故障排查

    一波四折--记一次K8S集群应用故障排查Part1 初露端倪 一个周四的下午,客户的报障打破了微信群的平静. "我们部署在自建K8S集群上的应用突然无法正常访问了,现在业务受到了影响!&qu ...

  7. Atitit.播放系统的选片服务器,包厢记时系统 的说明,教程,维护,故障排查手册p825...

    Atitit.播放系统的选片服务器,包厢记时系统 的说明,教程,维护,故障排查手册p825 1. 播放系统服务器方面的维护 2 1.1. 默认情况下,已经在系统的启动目录下增加了俩个启动项目 2 1. ...

  8. linux 内存溢出排查_记一次JAVA 线上故障排查完整套路

    JAVA线上故障排查全套路 线上故障主要会包括cpu.磁盘.内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍.同时例如jstack.jmap等工具也 ...

  9. MongoDB 常用故障排查工具

    MongoDB 常用故障排查工具 1.profile profiling levels: 0,关闭profile:1,只抓取slow查询:2,抓取所有数据. 启动profile并且设置Profile级 ...

最新文章

  1. telegraf监控mysql数据库_部署Telegraf+Influxdb+Grafana 架构来监控 MySQL
  2. R语言可视化堆叠(stack)的条形图并通过另外一个分类变量分离(dodge)条形图(stacking by one variable and dodging by another)实战
  3. Opencv cv2 Overload resolution failed
  4. python urllib2下载文件 是否成功,Python urllib2未完成下载fi
  5. MATLAB之简谐信号声音的生成及其调制性
  6. MySQL复制数据库
  7. linux云管理,教程|云帮手部署Linux公有云管理系统
  8. 读者诉苦:Redis 宕机,数据丢了,老板要辞退我
  9. redis的zset的底层实现_redis zset底层实现原理
  10. Python爬取各大汽车销量信息
  11. 万紫千红总是春的上一句是什么,万紫千红总是春全诗赏析
  12. django 接收ajax请求
  13. 如何查看json文件数据编码_【阿里】如何把 json 数据转化为 demo.json 并下载文件...
  14. 网络安全实验室 脚本关 10
  15. 《崩坏3》评测:游戏设计中整体性和利用率分析(中)
  16. 华为云-基于Ambari构建大数据平台
  17. 电脑连接手机Termux后保持在后台运行
  18. 光电器件(发光器件)特征与发光特性介绍
  19. 董卿:闲暇时光才是人生精华,这几个优质号一生必读
  20. 不租服务器,自建个人商业网站(1)

热门文章

  1. 为什么引入devops_DevOps可以为您的文档做什么?
  2. devops实践指南_开发DevOps的实用指南:减少八卦的步骤
  3. osi7层协议源代码_捍卫开放源代码的17年:立即加入OSI
  4. 属性 元素的内容 创建,插入和删除节点 虚拟节点
  5. Bootstrap3 弹出提示插件的选项
  6. normalize()方法
  7. 视觉SLAM十四讲学习笔记-第二讲-开发环境搭建
  8. TensorFlow笔记(8) LeNet-5卷积神经网络
  9. java 集成 v8_J2V8首页、文档和下载 - V8 的 Java 封装版本
  10. python数据挖掘与分析实战pdf_《Python数据分析与挖掘实战》PDF+完整源码