什么是死锁
死锁是指两个或两个以上的线程(或进程)在执行过程中,因为争夺资源而陷入的相互等待的状态,若无外力干涉,它们都无法推进下去。
表现
1、用户反馈:哪个功能卡住了,具体的操作路径是什么?涉及哪些页面或接口
2、QPS/TPS:是否暴跌或降为0。
3、相应时间:是否飙至无限长。
4、错误率:是否出现大量超时错误。
5、资源状态:CPU使用率是否很低(说明线程正在处理阻塞中),数据库连接池是否被耗尽。
初步定位问题层
1、应用层死锁:表现为某个服务实例完全无相应,但其他的服务可能正常
2、数据库死锁:表现为涉及某个特定数据库表的操作全部挂起,但是应用服务本身还是健康的,只是无法完成数据库操作)
3、分布式死锁:表现为多个微服务之间的一个调用链卡住,每个服务都在等待上游或者下游的响应,形成一个跨服务的循环等待。
深入调查和取证
应用层死锁
1、 观察全局的流量和基础设施监控
1.1、看是哪条业务线的QPS/TPS暴跌或着响应时间飙升,这个可以立刻帮你缩小范围到某一个业务域(比如是用户中心的问题,还是订单服务的问题)
1.2、看应用层,看有没有某一个服务的CPU使用率异常, 突然100%或者0%,或者GC异常
1.3、看中间件:数据库的连接池是否耗尽,消息队列是否有大量堆积,这些都可以指向依赖他们的应用
2、使用工具来分析
工具:jstack,jconsle,Arthas
操作:找到有应用Pod或服务器,获取其PID,在短时间内(如隔5-10秒)连续执行2-3次jstack。如果多次的dump都显示同一批线程阻塞在同一个锁对象上,那可以基本断定为死锁,同时分析deadlock关键字,jstack有时会直接报告。
数据库死锁(常见)
工具:数据库的系统表或命令
Mysql:执行 shwo engine innodb status;
命令;在输出结果中,有一个Latest detected deadlocak章节,会清晰的记录一次死锁的详细信息,包括涉及的事务SQL、争夺的资源(索引、记录)以及回滚哪个事务,这就是最直接的证据。或者查询information_schema.INNODB-TRX,查看当前有哪些长时间运行的事务。
分布式死锁(最复杂)
这里指的是服务A等待服务B的响应,服务B等待服务C的响应,而服务C又在等待服务A的响应,形成了一个跨网络的循环等待。
工具:分布式链路追踪系统(如SkyWalking,Jaeger,Zipkin)
操作:找到卡住链路:根据卡住的功能特征,搜索调用链,分析链路图谱,可以找到一个调用链一直处于等待中,并且停留在一个或者多个服务节点上。