用 pg_stat_io 深入观察 PostgreSQL 的 I/O 行为

2026-06-03 16 预计阅读时间:1 分钟
来源:postgr.es AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:7 分钟

PostgreSQL 的 I/O 一直是运维和调优中最难看清的盲区——你知道磁盘忙,但不知道到底是哪种操作在忙、忙在哪里、花了多少时间。pg_stat_io 正是为了填补这个缺口而引入的视图。Robert Haas 近期宣布,2026 年 6/7 月的 PostgreSQL Hacking Workshop 将邀请 Melanie Plageman 一起深入讨论她在 pgconf.dev 上的演讲《Additional IO Observability in Postgres with pg_stat_io》。如果你在生产环境调优中曾被 I/O 问题困扰,这次 workshop 和这个视图都值得重点关注。

pg_stat_io 能看到什么

传统上我们用 pg_stat_database 里的 blks_read / blks_hit,或者操作系统层面的 iostat,来推断 I/O 状况。但这些指标要么粒度太粗(只到数据库级别),要么脱离了 PostgreSQL 内部语义(不知道是 checkpoint 写、后台写还是扩展表写)。

pg_stat_io 按三个维度拆分 I/O 统计:

  • 对象类型(object_type):relation、temp relation、shared buffer 等
  • 上下文(context):normal、vacuum、checkpoint、bgwriter、extend 等
  • 操作(op):read、write、extend、evict、reuse、fsync

每一行记录给出 readswritesextendsevictionsreusesfsyncs 的次数,以及 read_byteswrite_bytesextend_bytes 等字节量,还有 evict_timeread_timewrite_timeextend_time 等耗时(微秒)。

这意味着你可以回答诸如:

  • vacuum 期间读了多少字节、花了多少时间?
  • checkpoint 写和 bgwriter 写的比例如何?
  • 表扩展(extend)操作是否频繁到值得关注?
  • 共享缓冲区中被 evict 的块有多少、耗时多长?

实战:用 pg_stat_io 定位 I/O 瓶颈

下面是一个可以直接在 PostgreSQL 15+ 上运行的查询,帮你快速找出最耗时的 I/O 上下文和操作组合:

-- 查看各上下文+操作的 I/O 耗时与吞吐,按耗时降序
SELECT
    object_type,
    context,
    op,
    reads,
    writes,
    extends,
    evictions,
    reuses,
    fsyncs,
    read_bytes,
    write_bytes,
    extend_bytes,
    -- 耗时单位为微秒,转为毫秒更直观
    round(read_time  / 1000.0, 2)  AS read_time_ms,
    round(write_time / 1000.0, 2)  AS write_time_ms,
    round(extend_time / 1000.0, 2) AS extend_time_ms,
    round(evict_time / 1000.0, 2)  AS evict_time_ms
FROM pg_stat_io
WHERE reads > 0 OR writes > 0 OR extends > 0 OR evictions > 0
ORDER BY (read_time + write_time + extend_time + evict_time) DESC;

运行后你会看到类似这样的输出(截取关键几行):

 object_type | context     | op    | reads | writes | ... | read_time_ms | write_time_ms | ...
-------------+-------------+-------+-------+--------+-----+--------------+---------------+-----
 relation    | normal      | read  | 12480 |      0 | ... |        38.50 |          0.00 | ...
 relation    | checkpoint  | write |     0 |   3200 | ... |         0.00 |         42.10 | ...
 relation    | vacuum      | read  |  1800 |      0 | ... |         5.20 |          0.00 | ...

从这个结果可以快速判断:如果 checkpoint 的 write_time_ms 占大头,说明 checkpoint 写磁盘是瓶颈,可以考虑调大 checkpoint_completion_target 或减少 shared_buffers 里的脏页积压速度;如果 vacuum 的 read 耗时突出,说明 autovacuum 在大量扫描表,可能需要调整 autovacuum_vacuum_cost_limit 或给热点表设置自定义参数。

监控脏页回写节奏

另一个常见问题是:脏页到底是被 checkpoint 写出去的,还是被 bgwriter 提前刷掉的?比例失衡往往意味着 checkpoint 集中写导致 I/O 尖峰。下面的查询直接对比两者:

SELECT
    context,
    writes,
    write_bytes,
    round(write_time / 1000.0, 2) AS write_time_ms
FROM pg_stat_io
WHERE context IN ('checkpoint', 'bgwriter')
  AND op = 'write';

理想状态下 bgwriter 应该承担更多写入,让 checkpoint 在目标时间内均匀完成。如果 checkpoint 的 write_bytes 远大于 bgwriter,可以尝试调高 bgwriter_lru_maxpages 或降低 bgwriter_delay,让后台写更积极。

持续采集:把 pg_stat_io 接入你的监控栈

单次查询只能看累计值。要观察趋势,需要定期快照并计算增量。以下是一个用 psql + cron 的最小方案:

# 每分钟采集一次,追加到 CSV 文件
# 部署到监控机器上,用 cron 调度:* * * * * /path/to/collect_pg_stat_io.sh
COLLECT_SQL="
COPY (
  SELECT
    now()                          AS ts,
    object_type, context, op,
    reads, writes, extends, evictions, reuses, fsyncs,
    read_bytes, write_bytes, extend_bytes,
    read_time, write_time, extend_time, evict_time
  FROM pg_stat_io
) TO STDOUT WITH CSV HEADER
"

psql -h $PGHOST -U $PGUSER -d $PGDB -c "$COLLECT_SQL" \
  >> /var/log/pg_stat_io_metrics.csv

有了 CSV 之后,用 Grafana / Prometheus 或者简单的 Python 脚本计算每分钟增量,就能画出 I/O 吞吐和耗时的时序曲线。如果你已经在用 pg_stat_statements 做查询级别监控,把 pg_stat_io 加进来可以补上"查询慢是因为磁盘慢还是因为计算慢"这块拼图。

上手建议

  • 版本要求pg_stat_io 从 PostgreSQL 16 开始可用(早期版本为实验性视图,字段可能有差异)。升级前先在测试环境确认视图结构。
  • 权限:查询 pg_stat_io 需要 pg_read_all_stats 预定义角色或超级用户。给监控账号授权时用 GRANT pg_read_all_stats TO monitoring_user;,不要直接给 superuser。
  • 冷启动注意:视图统计是累计值,重启后清零。首次采集时先记录基线,后续用差值分析。
  • 与现有指标互补:不要用 pg_stat_io 替代 pg_stat_database,两者粒度不同。前者看 I/O 语义,后者看逻辑读写比例,结合使用效果最好。

如果你想和 Melanie Plageman 及社区开发者一起深入讨论 pg_stat_io 的细节和未来方向,Robert Haas 的 Hacking Workshop 正在招募参与者——通过报名表单申请即可收到会议邀请。对于正在做 PostgreSQL I/O 调优或监控建设的人来说,这是一个直接和视图设计者对话的好机会。


相关推荐