暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

数据库可观测性的重要——记一次thread running高的原因排查失败

高情商说法: 数据库的可观测性
低情商说法: 数据库的监控告警

背景

今天帮同事排查客户一周前遇到的“web 前台登录卡死的问题”,客户在应用层没有找到原因,但在数据库监控仪表盘上看到一个异常的指标——Threads_running 高,当天晚上 20:00 - 21:20 之间监控曲线图有一个尖峰,从 0 涨到了 218,之后客户重启应用服务器,数据库恢复正常,问数据库 Threads_running 高的原因。

实际上,这是一个苦差事,分析当前发生的问题比较简单,但排查一个一周前发生的问题,这非常依靠监控系统有没有留有足够的线索。

目前,我们已知,一些辅助的线索是没有的,例如审计日志或者 general log 没有开启,无法知道案发现场的所有 SQL。

分析

在开始分析前,我先凭经验猜想 Threads_running 高可能有以下这几种情况:

  • 当时并发线程数确实高,有流量高峰
  • 当时有大量慢sql,引起雪崩效应
  • 系统资源层有瓶颈,或者 innodb 层有瓶颈。
  • 锁等待

1. 关于“当时并发线程数确实高,有流量高峰”

查看了当时监控的 TPS、QPS 曲线,没有明显的增长,TPS 压力甚至远低于白天,所以不是这个原因。

这里有个吐槽点,当时我看业务系统的 TPS、QPS 的采集频率是 2小时一次,这个对于性能分析没啥意义,我认为更合理的值是 10s,财力雄厚要求高的公司甚至可以设置 1s 一次

2. 关于“当时有大量慢sql,引起雪崩效应”

查看了慢查询日志,慢查询使用的阈值是记录执行两秒以上的慢查询,没有明显的慢查询现象,所以不是这个原因,系统也没有雪崩。

3. 关于“系统资源层有瓶颈,或者 innodb 层有瓶颈”

CPU 占用 20%,内存充裕没有使用到 swap,iops 非常低,客户的监控没有 iowait、io 饱和度监控指标(吐槽),但这么低的 iops 没理由有磁盘瓶颈,我这里就认为系统资源层没有遇到瓶颈。innodb 层简单了看了"open file"、"open table"等监控,没有遇到瓶颈。而且资源或数据库层有瓶颈,一般容易引发雪崩,我们当时并没有雪崩现象,所以不是这个原因。

4. 关于“锁等待”

排除了以上三个原因,锁等待这个原因导致的 Threads_running 高就非常大可能了。

官方文档对 Threads_running 的解释如下:

Threads_running
The number of threads that are not sleeping.

也就是非 sleep 状态的线程都属于 Threads_running 状态。

一旦一些查询遇到锁等待了,那他其实是不消耗 CPU 和 IO 资源的。所以完全符合我们 3 中的判断。

其中,锁等待一般又分为行锁等待和元数据锁等待(MDL锁等待)。

是锁等待?

不是。监控有通过show global status like 'Innodb_row_lock_time'
采集总的行锁时间,通过分析当时发生问题的 11 分钟内,只有 0.172 秒的行锁等待,这影响非常小,所以不是这个问题。

是元数据锁等待?

这个我无法确认。首先监控系统没有做长事务的监控告警,其次没做元数据锁等待的监控告警,再则我没有办法确认他们是否执行过 DDL 等需要争抢元数据锁的 SQL。MySQL 参数没有设置 log_slow_admin_statements =1
,设置了的话,慢的 DDL 或者 DBA 管理语句,例如 flush table with read lock
会记录进 slow.log。当然我们还是可以通过解析 binlog 确认是否有这些 DDL 行为,但无法确认flush table with read lock
(FTWRL)行为,所以意义也不大。问过业务方有没有执行过 DDL 或者备份程序(FTWRL),答案是没有,我信了,没有必要去调查了。

所以,我并没有找到根本原因。

结论

总之,巧妇难为无米之炊,这套业务系统的监控告警目前是有一些可优化的空间的,这些优化有助于我们日后通过监控系统回溯排查历史问题。

建议添加以下:
监控——iowait、io饱和度、长事务、元数据锁

告警:

  • io饱和度高
  • 长事务多于XX条
  • 元数据锁等待超过60s
  • 五分钟内慢查询数大于xx个
  • 并发线程数大于200 (建议值为逻辑核数 * 2)

最重要是最后这个"并发线程数大于200",有了他,我们当时会预警到问题,直接上数据库预防故障发生,并能通过 "show processlist" 等简单手段排查到原因。

我这么说后,同事决定添加了"并发线程数大于200" 这种告警,用于预发下次在发生。

最后补充一句,定时对数据库做"show processlist"、"show engine innodb status"快照保存下来,也是日后分析问题的利器,我自己运维是有这么干的。

Enjoy MySQL!


最后修改时间:2023-05-26 16:27:57
文章转载自芬达的数据库学习笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论