适用范围与版本边界
本文面向 PostgreSQL 物理流复制,并补充使用 Patroni、etcd 与 HAProxy 时的高可用视图核对。SQL 按 PostgreSQL 17 文档编写;其他版本先核对视图字段与函数权限,逻辑复制订阅不适用这套主备进度判据。Patroni 输出随版本变化,应记录实际版本和集群配置。本文没有执行提升、切换、重建或数据写入,验证状态为待验证。
前提:连接到可识别的实例
准备主库、每个备库及业务代理入口的映射,使用已授予必要监控读取权限的账号。部分统计字段对普通账号不可见,缺失或 NULL 可能是权限原因;不要临时授予超级用户来完成诊断。凭据使用现有连接服务或受控凭据存储,禁止在工单中暴露连接密码、复制连接串或完整配置文件。
SQL 片段应分别在已确认的目标实例运行,使用短时只读事务和查询超时,及时结束事务;例如在当前诊断连接先执行 BEGIN READ ONLY;、SET LOCAL statement_timeout = '5s';,完成一轮读取后 COMMIT;。重新采样开启新事务,避免长事务和统计快照造成误读。事务设置仅影响该诊断会话,不替代账号权限控制。
第一步:核对数据库角色与入口
SELECT clock_timestamp() AS sampled_at,
current_setting('server_version') AS server_version,
inet_server_addr() AS server_addr,
inet_server_port() AS server_port,
pg_is_in_recovery() AS in_recovery;分别记录直连每个实例与通过业务入口的结果。in_recovery=true 说明仍在恢复,false 不单独证明该实例被批准承接业务写入;还需要控制面、网络隔离和路由证据。代理、连接池和 Unix socket 可能使地址字段不能直接对应资产,必要时由平台的现有实例标识补齐。
同一 HA 集群中若出现两个都自认为可承接主库职责的节点,立即按疑似双主升级,不通过写入测试决定“谁才是真的主库”。只读核对角色时也要记录采样先后,因为正在进行的合法切换可能使相邻时刻不同。
第二步:在主库看 WAL 发送链路
确认该连接是预期主库后读取:
SELECT application_name, client_addr, state, sync_state,
sent_lsn, write_lsn, flush_lsn, replay_lsn,
write_lag, flush_lag, replay_lag, reply_time
FROM pg_stat_replication
ORDER BY application_name;
SELECT pg_current_wal_lsn() AS primary_lsn;将每行连接与预期备库映射,区分连接不存在、仍在追赶和稳定流式传输。sync_state 应与设计的同步策略比对;仅看到一个同步状态不能直接推出完整的零数据丢失保证。延迟字段描述近期 WAL 的发送反馈过程,不是预测追平所需时间;空闲或追平后可能变成 NULL,不能因此认定复制断开。PostgreSQL 统计文档 给出这些字段的含义。
若备库连接缺失,先核对备库进程状态、认证与连接日志、网络和 WAL 可用性;日志只截取相关时间段并脱敏。不通过创建新的复制连接或重启来替代证据收集。
第三步:在备库分离接收与回放
SELECT status, sender_host, sender_port, slot_name,
flushed_lsn, received_tli,
last_msg_send_time, last_msg_receipt_time
FROM pg_stat_wal_receiver;
SELECT pg_last_wal_receive_lsn() AS receive_lsn,
pg_last_wal_replay_lsn() AS replay_lsn,
pg_last_xact_replay_timestamp() AS last_replayed_xact,
pg_is_wal_replay_paused() AS replay_paused;先确认实例仍处于恢复;若角色已变,停止套用备库判据并重新建立拓扑。接收位置持续前进但回放位置停滞,关注恢复暂停、备库 IO、CPU 与查询冲突;接收和回放都不动时,需要先证明主库仍产生 WAL,再调查上游传输。接收器没有行也可能正在使用归档恢复,不能仅凭空视图判定没有任何恢复路径。
pg_last_xact_replay_timestamp() 是最后回放事务在主库产生提交或中止记录的时间,主库没有新事务时,其距当前时间可以不断增大;这不是可靠的独立复制延迟告警。恢复信息函数 说明各位置与时间戳的边界。
第四步:计算有上下文的进度差
在同一备库可用下面的只读表达式观察已接收但尚未回放的 WAL 字节差:
SELECT pg_wal_lsn_diff(pg_last_wal_receive_lsn(),
pg_last_wal_replay_lsn()) AS receive_replay_gap_bytes;NULL 应保留为未知,不强制替换成零。比较主库当前位置与备库位置前,必须确认属于同一集群和兼容的时间线,且采样时间接近;跨时间线或切换前后的位置不能草率相减。差值是 WAL 字节差,不是事务数,不一定包含所有业务延迟来源。至少对比两个时间点与业务负载,避免单点误判。
出现负值或与拓扑不一致时,先检查采样来源、归档与流复制路径、角色变化和时间线,不据此做提升决定。异步复制存在故障时未复制事务丢失的边界,必须按照业务允许的 RPO 和实际证据评估,而不是看到“streaming”就认定安全。主备复制指南 说明同步与异步复制语义。
第五步:核对复制槽与 WAL 容量风险
在预期主库上只读取物理槽:
SELECT slot_name, slot_type, active, restart_lsn,
wal_status, safe_wal_size
FROM pg_replication_slots
WHERE slot_type = 'physical'
ORDER BY slot_name;将槽名与配置中的备库用途对应,结合既有磁盘监控观察 WAL 目录增长。非活跃槽不能直接判为可删:备库离线、临时维护或控制面管理都可能解释它。wal_status 与 safe_wal_size 需要按保留上限和状态解读,NULL 不统一表示容量充足;相关定义见 pg_replication_slots。
如果所需 WAL 已不可用,需要由负责人评估归档恢复或重建,而不是删除槽后假设复制能继续。诊断中不删除或推进复制槽、不删除 WAL 文件,也不修改 WAL 保留策略。
第六步:对照 Patroni、DCS 与代理
仅在使用 Patroni 的环境,利用已授权的配置和具体集群名读取:
OPS_PATRONI_CONFIG='/REPLACE_WITH_APPROVED_PATRONI_CONFIG'
OPS_PATRONI_CLUSTER='REPLACE_WITH_CLUSTER_NAME'
patronictl -c "$OPS_PATRONI_CONFIG" list "$OPS_PATRONI_CLUSTER" --extended核对成员、角色、时间线、状态和待重启提示与 SQL 观测是否一致;Patroni 的列表不是独立的写入隔离证明。patronictl 文档 列出输出字段与命令用途。再通过已有只读监控核对 etcd 仲裁与连接错误、Patroni 日志及 HAProxy 后端状态,不临时修改 DCS key、代理路由或健康检查。
数据库正常但 DCS 失联、代理仍指向旧主、SQL 角色与控制面矛盾,应分别记录并升级。特别是疑似双主时,写入隔离必须由事故负责人按既定机制执行,本手册不自动选择或提升任何候选节点。
验收、停止与恢复边界
验收应说明主备映射一致、接收与回放趋势可解释、槽和 WAL 容量风险受控、控制面与业务入口一致,并在业务认可的只读查询中确认可见性。恢复后持续观察一个约定业务窗口,不能只以连接成功或单次 Lag 为零结案。
出现疑似双主、持续 WAL 丢失错误、磁盘接近耗尽或查询影响业务,停止扩大采样并升级处置。严禁在此流程执行 pg_promote、Patroni failover/switchover、reinit、修改同步策略或清理数据目录。只读诊断无数据回滚;新主接受写入后,返回旧主不是简单切回地址,必须先处理分叉、隔离和数据一致性。
案例证据记录模板
- 事件编号、PostgreSQL/Patroni 版本、集群与实例映射、连接入口:待填。
- 每次采样时间、角色、时间线、发送/接收/回放位置及解释:待填。
- 复制连接、槽、WAL 容量、DCS 与代理证据:待填。
- 业务可见性、RPO/RTO 要求、疑似分叉或丢失范围:待填。
- 假设与反证、授权负责人、停止条件、复查结果:待填。
示例不表示已经达到 RPO/RTO,不把未测量的数据保护能力写成验收事实。