跳转到主要内容

LWLock: WALInsert

等待将 WAL 数据插入内存 buffer。
PostgreSQL 等待事件档案
类别LWLock 事件WALInsert 版本PG 13-18 证据3 个源码位置

官方描述译文

等待将 WAL 数据插入内存 buffer。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

后端在共享 WAL 缓冲区中预留空间并复制 WAL 记录时,必须持有一个 WAL insertion lock。并发 WAL 生产者很多、插入临界区变长时,会在此排队。

正常还是麻烦?

  • 正常: 并发写入与提交突发期间的瞬时等待很正常。
  • 需要调查: 前台会话反复堆积说明 WAL 插入已成为串行点,常伴随极高写并发、全页镜像或缓冲区换页过慢。

诊断 SQL

正在等待 LWLock/WALInsert 的会话
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'LWLock'
  AND wait_event = 'WALInsert'
ORDER BY query_age DESC NULLS LAST;
当前 LWLock 等待分布
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'LWLock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
这些会话的锁与关系上下文
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'LWLock'
  AND a.wait_event = 'WALInsert'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

处置建议

  1. 按 WAL 生成量与调用频率排序语句。
  2. 检查检查点/全页镜像时机与并发写会话数量。
  3. 批量合并微小写入、减少无效索引抖动,并处理 WAL 写延迟。

源码证据

典型事故模式

扇出任务在检查点后立即发起大量单行提交,全页镜像与写并发共同让 WAL 插入成为瓶颈。