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

pg_stat_replication 的 lag 值到底代表什么延迟
pg_stat_replication 里的 pg_wal_lsn_diff() 计算出的 lag(比如 write_lag、flush_lag、replay_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,经连接池的连接不会出现在这里
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 很小也不参与同步提交 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 值会完全漏掉。










