PostgreSQL 18: 新增 pg_aios 视图

John Doe 九月 24, 2025

PostgreSQL 18 即将提供异步 I/O 的能力。但是,你知道如何运维异步 I/O 吗?

image

特性提交日志

aio:新增 pg_aios 视图。

该新视图会列出当前所有正在使用的 IO 句柄,主要对 PostgreSQL 开发者有用,但在对 PostgreSQL 进行性能调优时也可能发挥作用。

讨论:https://postgr.es/m/uvrtrknj4kdytuboidbhwclo4gxhswwcpgadptsjvjqcluzmah%40brqs62irg4dt

pg_aios 视图

在 PostgreSQL 中,异步 IO 是提升存储性能的核心机制之一,主要用于处理关系数据(如表、索引)的读写操作。传统场景下,开发者与运维人员难以直观获取异步 IO 操作的实时状态:

  • 无法快速定位 “IO 卡住” 问题:当某个进程响应缓慢时,无法判断异步 IO 是未提交、已提交但未执行,还是执行后未处理结果;
  • 难以分析 IO 负载分布:不清楚当前系统中活跃的 IO 类型、目标对象(哪个表 / 索引)及失败原因;

pg_aios 视图的出现就能很好地处理这些问题,它通过列出当前所有在用的异步 IO 句柄(每行对应一个句柄),将异步 IO 的全生命周期状态(从分配到完成)透明化。以下是对pg_aios视图中关键列的解读,完整列定义可参考 PostgreSQL 系统视图文档。

列名 描述
pid 发起该 IO 操作的服务器进程 ID。
io_id IO 句柄的标识符。IO 操作完成后(或 IO 开始前句柄被释放时),句柄会被复用;复用句柄时,pg_aios.io_generation(IO 句柄生成版本号)会递增。
io_generation IO 句柄的生成版本号。
state IO 句柄的状态,包含以下取值:
- HANDED_OUT:已被代码引用,但尚未使用
- DEFINED:已明确执行所需的信息
- STAGED:已就绪,等待执行
- SUBMITTED:已提交,等待执行
- COMPLETED_IO:已完成,但结果尚未处理
- COMPLETED_SHARED:已完成共享层的完成处理
- COMPLETED_LOCAL:已完成后端本地的完成处理
operation 通过 IO 句柄执行的操作,包含以下取值:
- invalid:操作类型尚未确定
- readv:向量读操作(一种可一次性读取多个不连续缓冲区数据的操作)
- writev:向量写操作(一种可一次性写入多个不连续缓冲区数据的操作)
off IO 操作的偏移量(即 IO 操作在目标文件中的起始位置)。
length IO 操作的数据长度。
target IO 操作的目标对象类型,当前仅支持 smgr(表示针对关系数据(如表、索引)的 IO 操作)。
handle_data_len 与 IO 操作关联的数据长度。对于往返于 shared_buffers(共享缓冲区)和 temp_buffers(临时缓冲区)的 IO 操作,该字段表示 IO 操作所涉及的缓冲区数量。
raw_result IO 操作的底层结果(如操作系统返回的错误码);若操作尚未完成,该字段值为 NULL。
result IO 操作的高层结果,包含以下取值:
- UNKNOWN:操作结果尚未确定
- OK:IO 操作已成功完成
- PARTIAL:IO 操作无错误完成,但未处理全部数据(通常调用方需重试,通过另一个 IO 操作处理剩余数据)
- WARNING:IO 操作无错误完成,但执行过程触发警告(例如,启用 zero_damaged_pages(零损坏页面)参数时遇到损坏的缓冲区)
- ERROR:IO 操作执行失败
target_desc IO 操作目标对象的描述信息(如“relation 16384”,可通过该信息关联数据库对象详情)。
f_sync 标识 IO 操作是否为同步执行的标志;true 表示同步执行(需等待操作完成),false 表示异步执行。
f_localmem 标识 IO 操作是否引用进程本地内存的标志;true 表示引用本地内存,false 表示不引用。
f_buffered 标识 IO 操作是否为缓冲 IO 的标志;true 表示通过操作系统缓存执行 IO,false 表示直接执行 IO(不经过操作系统缓存)。

示例

当某个数据库进程(如 PID=1890)执行查询时响应延迟,怀疑是异步 IO 卡住,可通过以下查询定位:

-- 查看目标进程的所有 AIO 句柄状态
SELECT 
  io_id, state, operation, result, 
  target_desc, now() - query_start AS delay  -- 关联会话延迟(需结合 pg_stat_activity)
FROM pg_aios 
JOIN pg_stat_activity ON pg_aios.pid = pg_stat_activity.pid
WHERE pg_aios.pid = 1890;
  • 若结果中state = 'SUBMITTED'result = 'UNKNOWN',说明 IO 已提交但未执行,需检查存储层(如磁盘 IO 队列、驱动是否正常);
  • state = 'COMPLETED_IO'result = 'OK',说明 IO 已完成但未处理,需排查结果处理进程是否出现瓶颈。

通过统计不同状态、操作类型的 IO 数量,可以了解系统异步 IO 的活跃程度:

-- 1. 统计各状态的 IO 数量,判断是否存在拥堵
SELECT state, COUNT(*) AS io_count, 
       ROUND(COUNT(*)::NUMERIC / SUM(COUNT(*)) OVER () * 100, 2) AS ratio
FROM pg_aios
GROUP BY state
ORDER BY io_count DESC;

-- 2. 统计读写操作占比,判断 IO 类型倾斜
SELECT operation, COUNT(*) AS io_count
FROM pg_aios
WHERE operation != 'invalid'
GROUP BY operation;
  • SUBMITTED状态的 IO 占比过高(如超过 50%),说明异步 IO 执行队列拥堵,需调整io_workers(异步 IO 工作进程数)或优化存储 IO 性能;
  • writev操作占比过高,需检查是否存在 “写放大”(如频繁更新导致 WAL 大量写入),可考虑调整表填充因子。

另外,也可以用于分析 IO 失败原因,定位存储问题。当result = 'ERROR'时,结合raw_resulttarget_desc排查失败根源:

-- 查看近期 IO 失败的详细信息
SELECT 
  pid, io_id, target_desc, 
  result, raw_result, 
  now() - query_start AS delay
FROM pg_aios
JOIN pg_stat_activity ON pg_aios.pid = pg_stat_activity.pid
WHERE result = 'ERROR'
ORDER BY query_start DESC;
  • raw_result = -5(操作系统错误码,对应 EIO),说明磁盘存在硬件错误,需检查磁盘健康状态;
  • target_desc指向某张表且频繁报错,可能是表文件损坏,需执行pg_checksums验证或恢复数据。

非常不错的特性。感谢社区的所有相关人员。

参考

提交日志:https://git.postgresql.org/pg/commitdiff/60f566b4f24362f54003569d5f6e24137bcd83fc