SQL PostgreSQL 的 pg_stat_replication 的 lag 与同步状态监控

1次阅读

pg_stat_replication 中的 lag 值(如 replay_lag)表示 wal 字节偏移量差,非秒级时间延迟;replay_lag 最接近同步延迟感,但需结合 pg_last_xact_replay_timestamp() 获取真实秒级延迟。

SQL PostgreSQL 的 pg_stat_replication 的 lag 与同步状态监控

pg_stat_replication 的 lag 值到底代表什么延迟

pg_stat_replication 里的 pg_wal_lsn_diff() 计算出的 lag(比如 write_lagflush_lagreplay_lag)不是秒级时间差,而是 WAL 字节偏移量差。它反映的是主库已生成但备库还没写入/刷盘/重放的 WAL 数据量。

  • 这个值会受 WAL 生成速率影响:业务写入猛时 lag 字节数涨得快,但实际时间延迟未必高
  • replay_lag 最接近“同步延迟感”,但它仍不是 wall-clock 时间,postgresql 10+ 才有该字段,旧版本只能靠 pg_last_wal_receive_lsn()pg_last_wal_replay_lsn() 手动算差值
  • 如果 lag 突然从几 MB 暴涨到 GB 级,大概率是备库卡在 IO 或 replay 阶段,不是网络问题

SELECT client_addr, state, write_lag, flush_lag, replay_lag  FROM pg_stat_replication;

如何判断 standby 是否真的同步中(而不仅是连上了)

连接上不等于同步中。state = 'streaming' 只表示 WAL 流正在传输,但备库可能卡在 apply 阶段(比如被 long-running query 持有锁阻塞 replay)。

  • 优先看 replay_lag 是否稳定增长或归零;若为 NULL,说明备库还没开始 replay(可能刚启动、或配置了 hot_standby = off
  • 检查 pg_is_in_recovery() 返回 true 是基本前提,否则这台根本不是 standby
  • state = 'startup',说明备库还在 recovery 初始化阶段,此时所有 lag 字段都是 NULL,不算异常

常见误判:看到 state = 'streaming' 就认为 OK,结果 replay_lag 持续增大,且 pg_stat_activity 里没看到 client_addr 对应的 backend_type = 'client backend' 连接 —— 这说明 WAL 在传,但没进 replay 队列。

用 pg_stat_replication 监控同步状态时最常踩的坑

  • 监控脚本直接查 pg_stat_replication 却没加 WHERE client_addr IS NOT NULL,导致聚合时把本地 wal sender(如逻辑复制槽)也当 standby 算进去,拉低平均 lag
  • write_lag 当成最终延迟指标 —— 实际上只要 replay_lag 不为 0,数据就还没对应用可见,尤其对强一致性读场景致命
  • 忽略 sync_state 字段:'sync' 表示该 standby 被选为同步备库,'quorum''async' 下即使 lag 很小也不参与同步提交
  • 在 pgBouncer 后面查这个视图?不行。pg_stat_replication 只在主库上存在,且只反映直连主库的 standby,经连接池的连接不会出现在这里

一个典型错误监控语句:

SELECT 1 FROM pg_stat_replication WHERE replay_lag > '100MB';

—— 缺少 AND state = 'streaming'AND sync_state = 'sync' 条件,告警容易误触发。

lag 字节数怎么换算成可理解的延迟风险

没有固定换算公式,但可以建立经验锚点:

  • replay_lag :通常对应毫秒级延迟,可视为“基本实时”

  • 16MB ~ 128MB:取决于 WAL 写入节奏,一般在几百毫秒到 2 秒之间,多数 OLTP 场景仍可接受

  • > 128MB:需警惕 —— 若持续超过 30 秒,大概率出现 replay backlog,可能拖慢主库的 checkpoint,甚至触发 max_standby_streaming_delay 超时取消查询

  • 不要依赖 pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) 的绝对值做 SLO,它和磁盘 IO、备库负载、WAL segment 大小都强相关

  • 更稳妥的方式是结合 now() - pg_last_xact_replay_timestamp()(PostgreSQL 9.6+),这个才是真正的秒级延迟,但要注意它只记录最后一次事务重放时间,静默期不更新

真正麻烦的是那种 lag 波动剧烈、反复冲高又回落的情况 —— 往往意味着备库磁盘吞吐不足,或者主库突发大批量 copy / VACUUM FULL,这种问题光看平均 lag 值会完全漏掉。

text=ZqhQzanResources