概述
流复制默认是异步的:主库把 WAL 发给备库,备库稍后回放,间隔通常是毫秒级,但在写入高峰、网络抖动或备库变慢时会拉大。读到落后副本的用户可能看不到自己刚写入的数据,看起来像数据丢失,实际上并没有丢。
步骤
- 在副本上计算毫秒级延迟,并判断是否已追平:
SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())) * 1000 AS lag_ms,
pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() AS caught_up;
- 在主库上用
pg_stat_replication观察每个备库的字节延迟并配置告警,它在业务空闲时同样有效。 - 路由时加入滞回与缓存:延迟超过 2 秒切主库,低于 500 毫秒才回到副本,决策缓存约 1 秒,避免每次查询都探活。
- 探活失败一律视为不健康:无法证明副本已追平时,不要用它承载读流量。
验证
在副本执行 SELECT pg_wal_replay_pause();,然后在主库写入一条记录,等待超过缓存窗口后调用路由函数,应返回主库。执行 SELECT pg_wal_replay_resume(); 后数秒内读流量应回到副本。整个过程连接不会断开,正好模拟了回放停滞这一真实故障。
注意事项
- 延迟每个缓存窗口才采样一次,健康读数之后副本仍可能立刻落后。
- 切回主库会降低读扩展能力,故障期间可能把主库压垮,需要配合限流。
- 延迟门控只能降低陈旧读概率,不能保证读己之写;后者需要会话粘主或等待提交 LSN 回放。
- 新副本尚未回放任何事务时
lag_ms为空,必须结合caught_up判断,追平前不要加入轮转。 - 主库上按字节延迟告警比按时间更稳定,适合作为值班依据。