Lock 等待
通常可以直接从 SQL 找到持有者与阻塞链的重量级锁。
Lock 是最容易直接处置的一类:后端向锁管理器申请重量级锁,但不兼容的持有者尚未释放。与 LWLock 不同,这些等待通常在 pg_locks 中有对应行,pg_blocking_pids() 也能给出有效答案。
看阻塞图,不要只数受害者
二十个等待者可能都只是一个空闲事务的症状。先走到阻塞图最前端,再判断持有者是在做有效工作、已被遗弃,还是处于计划内 DDL/发布窗口。
- 正常: 普通写入或计划内 DDL 期间,亚秒级的锁交接。
- 关注: 任一面向用户的等待超过其延迟目标,或至少 10% 的活动会话等待同一个根阻塞者。
- 紧急: 根持有者是
idle in transaction、阻塞链持续增长、关键 DDL 阻塞流量,或死锁开始增加。
值得先认出的事件
| 事件 | 通常表示 |
|---|---|
| relation | 表/索引级锁冲突,常见于 DDL 对 DML |
| transactionid | 等待另一事务结束,常见于并发更新同一行 |
| tuple | 元组锁竞争或很长的行锁队列 |
| extend | 多个会话在扩展同一关系时串行化 |
| virtualxid | DDL 等待可能仍在使用对象的事务 |
| advisory | 应用自定义的 advisory lock 协调 |
阻塞者查询
常见误读
- 被列为阻塞者的会话并不一定可以安全终止;它可能是维护业务不变量的唯一写入者。
transactionid不代表事务 ID 即将耗尽。relation本身不说明具体关系;需要把pg_locks.relation关联到pg_class。- 增大
lock_timeout只改变受害者等多久,并不会移除阻塞者。
等待获取用户 advisory lock。
等待获取逻辑复制订阅端正在应用的远程事务上的锁。
等待扩展 relation。
等待更新 pg_database.datfrozenxid 和 pg_database.datminmxid。
等待获取非 relation 数据库对象上的锁。
等待获取 relation 页面上的锁。
等待获取 relation 上的锁。
等待获取推测式插入锁。
等待事务结束。
等待获取 tuple 上的锁。
等待获取用户锁。
等待获取虚拟事务 ID 锁。