由 John Doe 九月 24, 2025
PostgreSQL 18 即将提供异步 I/O 的能力。但是,你知道如何运维异步 I/O 吗?
特性提交日志
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_result
和target_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