序言
那是大半年前的一次线上DB故障。凌晨刚躺下就被call起来,经过紧张刺激,大脑高速运转的40分钟后,得出几个结论:
- 靠谱的基建团队很重要!
- 压力之下排查问题,大脑容易卡顿!
- 人在事上练!
问题表象
2023-12-xx 01:10时用户反馈APP系统崩了,列表查不出来。同事发日志截图看很清晰的获取数据库连接报错。当时想的是最近有没有发版,导致的?咨询了同事查看了线上工作负载的更新时间是7天前,代表不是最近发版导致的问题。

运行了7天都好好的,突然发现连接池打满了,获取链接超时,自然所有系统的查询都出不来了。但什么原因?一时没有头绪,只能赶快尝试恢复服务(线上还是以立即止损为第一要求),边让同事重启服务试试。发现重启后一瞬间也出现连接池打满的错误。
怀疑方向和排查
我们的数据库分为了几个逻辑库,工单、用户、商务等,在页面上只有工单库相关业务出现了阻塞。这几个逻辑库都在同个数据库实例上。究竟是什么原因导致连接池打满?当时想到的是:1.工单服务和DB的网络不通 2.DB负载很高,无法响应新连接。
查看了DB当时的负载,CPU和IO都是正常范围不算高。那很可能就是网络不通?查看工单服务所在241主机,发现网络IO是有异常,进出流量都突然下跌了。佐证了网络连通性很有问题!仿佛看到了点希望,然后让运维同事将工单服务放到236机器,241的下掉。发现236机器也出现拿不到链接问题。

很快拉了云服务供应商的运维群,运维登录241用telnet命令测试235主库,两台机网络是连通的。此时心有点凉了,重启服务不行,网络没问题,DB负载不高,近期没发版。没头绪了...
柳暗花明
DBA甩了张慢SQL截图在群里,发现有3条SQL执行了9个多小时... 然后还有个备份任务显示waitting for table flush
32515秒,这3条SQL就是某个同事下午执行的查询报表的语句。sending data代表SQL正在执行,边读数据边放到MySQL的send buf中,此时不一定是在发送数据给客户端,也有可能是在等锁。


把这3条慢SQL都干掉,然后把备份进程干掉。DB就自动恢复正常。网上查了些资料也的确是这个慢SQL和备份进程因获取MDL读写锁问题导致故障。第二天DBA也在UAT库模拟复现了这个问题。
原理学习和验证
回顾整个过程,刚开始猜测的两个方向的确是有可能的。但是看了DB负载比较低之后就放弃了排查DB本身问题,几条慢SQL有时可能并不会引发DB的负载大规模升高。但问题在于如果慢SQL在短时间内积压,就会造成雪崩效应。
这里先普及一个知识,MySQL的MDL锁,也称元数据锁。元数据锁是server层的锁,表级锁,每执行一条DML、DDL语句时都会申请MDL锁,DML操作需要MDL读锁,DDL操作需要MDL写锁(MDL加锁过程是系统自动控制,无法直接干预,读读共享,读写互斥,写写互斥),申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。事务一旦申请到MDL锁后,直到事务执行完才会将锁释放。
这次慢SQL碰上备份,慢SQL先获取了表的MDL读锁,备份程序innodbbackupex也需要获取表的MDL写锁,因为慢SQL迟迟没有结束所以备份程序只能进入队列排队获取MDL写锁,因为队列中存在了MDL写锁请求,后续的DML语句也因此被阻塞,因为获取MDL写锁请求高于MDL读锁请求。
总结:服务DB连接池打满的可能:
- 网络不通
- 突发流量导致负载高
- 慢SQL
- MDL表锁
参考文章:
https://blog.51cto.com/u_16099316/7137136
https://blog.51cto.com/u_16099316/7137136
https://blog.itpub.net/29654823/viewspace-2944599/
https://blog.itpub.net/29654823/viewspace-2944599/


被折叠的 条评论
为什么被折叠?



