使用等待事件优化 PostgreSQL

John Doe 四月 20, 2026

现代 PostgreSQL 中最有用的一个调优工具就是等待事件系统。

image

目录

介绍

当查询速度变慢或数据库陷入 CPU 瓶颈时,一个很自然的问题是:“会话实际在等待什么?” Postgres 通过视图中的pg_stat_activity两列公开了此信息:

SELECT pid, wait_event_type, wait_event, query
FROM pg_stat_activity
WHERE wait_event IS NOT NULL;

视图 pg_wait_events 提供了有关等待事件的描述,可以与 pg_stat_activity 结合使用,如下所示:

SELECT a.pid, a.wait_event, w.description 
  FROM pg_stat_activity a JOIN 
       pg_wait_events w ON (a.wait_event_type = w.type AND 
                            a.wait_event = w.name) 
 WHERE a.wait_event IS NOT NULL and a.state = 'active';

下面我们来重点探讨一类等待事件:LWLock 等待。

为什么会出现 LWLock 等待?

LWLock 代表轻量级锁(Lightweight Lock)。这些是 PostgreSQL 内部的同步实现,用于协调对共享内存结构的访问。

在健康的系统中,LWLocks 的获取和释放都非常迅速。然而,在以下情况下,它们可能会变得可见:

  • 资源竞争加剧
  • 多个会话访问相同的内部结构,如:共享缓冲区、WAL 缓冲区
  • CPU 饱和现象发生
  • 共享内存结构成为热点

OLTP 工作负载会产生高并发性和对共享资源的频繁访问,因此您经常会看到锁等待和缓冲区或 IO 相关的等待。

pg_stat_activity中看到 LWLock 等待并不一定意味着出了问题。但持续的 LWLock 争用通常表明工作负载的某个地方存在扩展性问题。

常见的 LWLock 等待事件

在现实世界的事件中,一些 LWLock 事件会频繁出现。

了解这些因素有助于缩小问题根源的范围。

LWLock - buffer_content

当 Postgres 进程争用共享缓冲区页面时,就会发生这种情况。

常见病因包括:

  • 对同一行的多次并发更新
  • 索引大幅修改
  • 热表接收到大量写入

如果看到这些锁定图标,请尝试以下故障排除步骤:

  • 检查是否存在写入密集型工作负载
  • 检查频繁更新的表
  • 查看是否缺失索引导致页面访问过多

LWLock - WALWriteLock

这表明在写入 WAL 预写日志时存在争用。

常见原因:

  • 高写入吞吐量
  • 大批量插入或更新
  • 低速存储影响 WAL 刷写

可能的诊断步骤:

  • 检查 WAL 生成速率
  • 检查磁盘延迟
  • 审查批量写入类工作负载

在某些系统中,这表现为提交延迟峰值。

LWLock 问题诊断

在调查 LWLock 等待问题时,通常有几个步骤会有所帮助。

寻找占主导地位的等待事件

首先确定出现频率最高的 LWLock 类型:

SELECT wait_event, count(*)
FROM pg_stat_activity
WHERE wait_event_type = 'LWLock'
GROUP BY wait_event
ORDER BY count(*) DESC;

检查工作负荷特征

需要提出的问题:

  • 同时有多个写入者?
  • 是否有单个表正在接收大量更新?
  • 事务处理量是否极高?

检查连接数

大量的连接会加剧资源争用。连接池通常能显著降低 LWLock 的压力。

查看查询模式

频繁查询访问相同的行或页面会造成热点。

结语

PostgreSQL 等待事件系统提供了关于数据库内部运行情况的宝贵信息。特别是 LWLock,它能够揭示共享内存结构内部的争用情况,而这些争用在其他情况下是不可见的。在调查性能问题时,一个有效的经验法则是:如果多个会话都在等待同一个 LWLock,那么通常存在某个工作负载的热点。一旦确定了争用的位置,解决问题的路径就会变得清晰得多。

另外,在 Redrock Postgres 最新的版本中,我们添加了等待事件统计信息收集扩展rp_wait_states,方便进行性能问题的诊断分析。