PostgreSQL 写入风暴问题:来源、检测与解决

John Doe 四月 15, 2026

生产环境里最让人头疼的,莫过于那种毫无征兆的性能雪崩:前一秒 TPS 还稳稳跑在 2000+,下一秒直接腰斩;应用延迟突然飙升,请求排队堵成山;排查半天 CPU、内存都正常,最后发现磁盘 IO 被打满了。

image

PostgreSQL 写入风暴是指数据库突然产生大量磁盘写入操作,导致IO系统饱和,进而引发应用性能急剧下降、延迟飙升甚至服务中断的现象。它是生产环境中最常见且最容易被忽视的性能杀手之一。

写入风暴的两大主要来源

强制检查点(Checkpoint)

PostgreSQL 通过预写日志(WAL)保证数据持久性。当 WAL 累积量达到 max_wal_size 软限制时,数据库会触发强制检查点,立即将所有脏页刷入磁盘。

问题本质:强制检查点不遵守 checkpoint_completion_target 参数,会以磁盘能承受的最大速度写入,与用户查询激烈争夺 IO 资源。

典型影响:测试显示,默认1GB max_wal_size 在中等负载下会导致TPS骤降约 40%。

高发场景:批量数据导入(COPY)、大表索引创建、批量更新等操作。

无节流的自动清理(Autovacuum)

autovacuum_cost_delay 设置为 0 时,自动清理进程会全速运行,引发另一种形式的写入风暴。

问题本质:autovacuum 扫描表时会设置元组提示位(hint bits),这会脏化页面。页面在检查点后首次被修改时,PostgreSQL 会将整个 8KB 页面写入 WAL(全页写入,FPI)。

典型影响:产生巨量 WAL 流量,导致主从复制延迟,进而引发 IPC:SyncRep 等待事件,阻塞所有提交操作。

高发场景:仅插入(append-only)的大表,尤其是 TOAST 表。

如何检测写入风暴

检查点相关

启用 log_checkpoints = on(PostgreSQL 15+ 默认开启)

日志中出现 checkpoint starting: wal 表示强制检查点:

LOG:  checkpoint starting: wal
LOG:  checkpoint complete: wrote 2069 buffers (1.6%), wrote 2 SLRU buffers;
      0 WAL file(s) added, 1 removed, 32 recycled; write=2.132 s, sync=0.092 s,
      total=2.282 s; sync files=35, longest=0.090 s, average=0.003 s;
      distance=553713 kB, estimate=553713 kB; lsn=6/FEBDB228, 
      redo lsn=6/DFFFFC60
LOG:  checkpoints are occurring too frequently (2 seconds apart)
HINT:  Consider increasing the configuration parameter "max_wal_size".

监控 pg_stat_checkpointer(PG17+)或 pg_stat_bgwriter

SELECT num_timed, num_requested FROM pg_stat_checkpointer;

健康系统中,相对于 num_timed 的值,num_requested 应接近 0

Autovacuum 相关

启用 autovacuum 日志。

监控 IPC:SyncRep 等待事件。

使用 pg_walinspect 分析 WAL 内容,查看是否有大量 FPI_FOR_HINT 记录。

解决与预防措施

针对强制检查点

合理设置 max_wal_size

  • 写密集 OLTP:10-20 GB
  • 有大量批量操作:50 GB 以上

目标是让几乎所有检查点都是定时检查点(checkpoint starting: time)。

为 WAL 日志分区预留足够的磁盘空间(至少是max_wal_size的 2 倍)。

针对 autovacuum

永远不要将 autovacuum_cost_delay 设置为 0

保持默认值 2ms,根据系统负载微调。

对于超大表,可以单独调整表级 autovacuum 参数。

总结

PostgreSQL 写入风暴主要由配置不当引起,而非数据库本身的缺陷。两个最常见的错误是:

  1. 参数 max_wal_size 使用默认的 1GB,处理高写入负载
  2. autovacuum_cost_delay 设置为 0 以"加速"清理

通过正确配置这两个参数,并建立相应的监控体系,绝大多数写入风暴问题都可以提前预防。这两个参数的调整几乎没有负面影响,却能带来显著的性能提升。