1. 问题场景分析
近期负责的系统上线一段时间后,现场反馈所有模块响应特别慢并有超时提醒,收到问题立即开展排查,依次对网络、服务器CPU和内存、数据库状态进行了一轮排查,最终找到问题并及时修复,稳定了现场状况,引发原因如下:
-
1.1 查询死锁SQL进程:
-
1.2 通过SQL定位到问题出在质检化验的模块
-
1.3 分析代码逻辑,判断出问题原因
由于一个事务逻辑中,调用了第三方的质检化验的接口比较慢,长时间等待请求返回,导致调用前启用的事务一直没有提交,数据库表被长期加锁,当有限连接数消耗殆尽时,引起越来越多其它模块访问数据的线程因无法获取数据库连接而被挂起,从而导致整个系统奔溃
- 1.4 解决方案
核心目的是要缩减锁表时间,有以下几种方式:
方案一,等第三方接口返回后再启动更新事物
方案二,调用第三方接口支持超时机制,避免长时间等待
方案三,异步队列处理三方调用
本次故障结合方案一和方案二进行解决的,也是推荐处理方案。
2. 锁表分析SQL汇总
-
2.1 查找锁表的pid
SELECT pid FROM pg_locks l JOIN pg_class t ON l.relation = t.oid WHERE t.relkind = 'r' AND t.relname = 'lockedtable';
-
2.2 查找锁表的语句
SELECT pid, state, usename, QUERY, query_start FROM pg_stat_activity WHERE pid IN ( SELECT pid FROM pg_locks l JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r' WHERE t.relname = 'lockedtable' );
-
2.3 查找所有活动的被锁的表
select pid, state, usename, query, query_start from pg_stat_activity where pid in ( select pid from pg_locks l join pg_class t on l.relation = t.oid and t.relkind = 'r' );
-
2.4 解锁
SELECT pg_cancel_backend(pid);