Skip to content

repmgr 复制管理 ​

repmgr 是 PostgreSQL 生态中历史最长的复制管理工具集,由 repmgr CLI、repmgrd 守护进程与 repmgr 扩展三部分组成:CLI 负责「搭集群、克隆备库、计划内切换」这些确定性操作,repmgrd 负责「盯复制、判故障、自动提升」这些持续性工作,扩展则在数据库内维护集群元数据。相比上一页的 Patroni,repmgr 最显著的特点是不依赖外部 DCS——集群状态直接存放在数据库自身的元数据表中,部署形态更轻。

对已经熟悉流复制与手工故障切换的团队来说,repmgr 是从「纯手工」迈向「自动化」的最低阻力路径:它把 pg_basebackup、pg_promote、pg_rewind、pg_ctl 这些分散的操作封装成语义清晰的命令(standby clone、standby promote、standby switchover),再把「主库挂了谁来提升」这个问题交给 repmgrd 的守护循环。前几个阶段手工做过的切换演练,用 repmgr 重做一遍,往往只需要原来一半的操作步骤。

repmgr 不是 Patroni 的「低配替代」,而是同一问题的两种设计取舍:Patroni 把决策交给外部共识系统换取更强的 fencing 与更集中的配置管理,repmgr 把状态留在数据库内部换取更少的组件依赖,代价是脑裂防护更依赖网络与见证节点的设计。本页讲清它的组件结构、关键配置、常用命令、自动故障转移与计划内切换,最后给出与 Patroni 的选型对比,帮助按团队情况做决定。

前置知识

建议先阅读:Patroni 高可用方案

基础概念 ​

概念英文 / 记法说明
repmgr CLIrepmgr管理命令行工具,注册节点、克隆备库、执行切换
repmgrdrepmgrd守护进程,负责监控与自动故障转移
repmgr 扩展repmgr extension数据库内维护集群元数据的 PostgreSQL 扩展
元数据metadata存放节点清单、事件历史、监控历史的库表集合
主节点primary当前承担写入的节点
备节点standby流复制 follower,可提升为主
上游节点upstream node级联复制中备库的 WAL 来源(主库或另一台备库)
见证节点witness只保存元数据、不承担数据的仲裁用小实例
自动故障转移automatic failoverrepmgrd 检测主库失效并自动提升备库
计划内切换switchover主备角色互换的可控操作,无数据丢失

三大组件的分工 ​

repmgr 的三个组件各司其职,理解分工就能明白哪些文件装在哪台机器上:

组件形态装在哪职责
repmgr命令行程序每个节点注册、克隆、提升、切换、巡检等一次性操作
repmgrd常驻守护进程每个节点持续监控、自动故障转移、事件记录
repmgr 扩展PostgreSQL 扩展每个节点的数据库内提供元数据表与相关函数

三个组件读写同一份元数据:CLI 的每次注册写入元数据表,repmgrd 周期性读取元数据了解集群拓扑并写入监控历史,扩展提供这些表的 DDL 与基础函数。任一节点的元数据都以主库上的那份为权威,其余节点保持同步。

元数据的存放与节点清单 ​

每个 repmgr 节点都连到一个名为 repmgr 的元数据库(可在 conninfo 中自定义库名)。扩展在其中维护一组元数据表:以节点清单表(记录 node_id、node_name、类型、上游节点、连接串、active 状态等)为核心,配套事件历史表(注册、提升、切换、故障转移等事件的流水)与监控历史表(repmgrd 周期采样的复制延迟数据)。集群级的两个全局概念也存在这里:选举任期(避免跨任期误判)与当前主库的记录。

实际表结构与字段名随 repmgr 大版本变化,操作元数据请优先使用 repmgr 命令或官方文档查询语句,不要直接 UPDATE 元数据表。

语法与用法 ​

repmgr 的配置文件是每个节点一份的 repmgr.conf(路径任意,命令行用 -f 指定;部分子命令不指定时会尝试默认路径)。node1 的完整示例:

ini
# ---- 节点标识(必填,且全集群唯一、注册后不可改)----
node_id=1
node_name=node1
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/18/main'

# ---- 自动故障转移 ----
failover=automatic
promote_command='repmgr standby promote -f /etc/repmgr.conf'
follow_command='repmgr standby follow -f /etc/repmgr.conf --upstream-node-id=%n'

# ---- 复制槽 ----
use_replication_slots=yes

# ---- 提升优先级(数值大者优先;设为 -1 可禁止该节点被提升,细节以官方文档为准)----
node_priority=100

# ---- 日志与服务 ----
log_level=INFO
log_facility=STDERR
pg_bindir='/usr/lib/postgresql/18/bin'
service_start_command='sudo systemctl start postgresql@18-main'
service_stop_command='sudo systemctl stop postgresql@18-main'
service_restart_command='sudo systemctl restart postgresql@18-main'
service_reload_command='sudo systemctl reload postgresql@18-main'

# ---- 事件通知 ----
event_notification_command='/usr/local/bin/repmgr_alert.sh %e %n "%d"'
event_notifications='standby_register,standby_promote,primary_failover,standby_failover,switchover'

几乎所有操作都要显式带上配置文件:

bash
# 在主库上注册集群起点
repmgr -f /etc/repmgr.conf primary register

# 在备库上克隆并注册
repmgr -f /etc/repmgr.conf standby clone -h node1
repmgr -f /etc/repmgr.conf standby register

# 查看集群全貌
repmgr -f /etc/repmgr.conf cluster show
text
 ID | Name  | Role    | Status               | Upstream | Location | Timeline | Connection string
----+-------+---------+----------------------+----------+----------+----------+-------------------------------------------------------------
 1  | node1 | primary | * running            |          | default  | 1        | host=node1 user=repmgr dbname=repmgr connect_timeout=2
 2  | node2 | standby |   running            | node1    | default  | 1        | host=node2 user=repmgr dbname=repmgr connect_timeout=2
 3  | node3 | standby |   running            | node1    | default  | 1        | host=node3 user=repmgr dbname=repmgr connect_timeout=2

元数据库与专用用户在部署前创建(repmgr 官方文档建议该用户使用超级用户以简化操作,安全要求高的环境可按需收敛权限):

sql
CREATE USER repmgr WITH LOGIN SUPERUSER PASSWORD 'R3pmgr_Secret';
CREATE DATABASE repmgr OWNER repmgr;
ini
# pg_hba.conf:放行元数据库访问与复制连接(按网段收紧)
host  repmgr      repmgr  192.168.1.0/24  scram-sha-256
host  replication repmgr  192.168.1.0/24  scram-sha-256

详细说明 ​

repmgr.conf 关键配置 ​

repmgr.conf 的参数分四类:节点标识、故障转移行为、复制与服务、日志与通知。

参数必填说明
node_id是整数,全集群唯一,注册后不可更改
node_name是节点名,事件与监控中用于标识
conninfo是本节点的连接串。必须能被其他节点访问,因为它会被存入元数据表供集群互联
data_directory是本节点数据目录绝对路径
failover否manual(只监控不切换)或 automatic(repmgrd 自动提升)
promote_commandautomatic 时必填候选节点被选中后执行的提升命令,通常是 repmgr standby promote -f ...
follow_commandautomatic 时必填其余备库跟随新主库的命令,%n 会被替换为新主库的 node_id
use_replication_slots否由 repmgr 为备库创建并维护物理复制槽
node_priority否提升优先级;数值大者优先,负值可排除参与提升(细节以官方文档为准)
log_level否DEBUG / INFO / NOTICE / WARNING / ERROR 等
pg_bindir否PostgreSQL 可执行文件目录,standby clone 调 pg_basebackup 时需要
service_*_command否repmgr 代为启停 PostgreSQL 的命令,切换与重拉起时使用
event_notification_command否事件触发的通知命令,支持 %e(事件名)、%n(节点号)、%d(描述)等占位符
event_notifications否订阅的事件类型列表,如 standby_promote,primary_failover

两个最容易出错的点:其一,conninfo 写成 localhost 或 127.0.0.1 会让其他节点无法通过元数据连接到本节点,巡检与故障转移立刻失灵;其二,promote_command / follow_command 是以字符串形式保存、由 repmgrd 在故障现场执行的,路径写错只有等到故障那天才会暴露——部署完成后务必人工演练一次。

搭建集群:注册主库与克隆备库 ​

repmgr 搭集群的顺序是「先主后备」,每一步都是可回退的显式命令:

bash
# 0. 前提:主库已按流复制要求配置(见主库配置页),元数据库与用户已创建
# 1. 主库注册,初始化元数据
repmgr -f /etc/repmgr.conf primary register

# 2. 备库(node2)上:克隆主库数据目录(内部执行 pg_basebackup,目录需为空或不存在)
repmgr -f /etc/repmgr.conf standby clone -h node1

# 3. 启动备库实例后注册
sudo systemctl start postgresql@18-main
repmgr -f /etc/repmgr.conf standby register

# 4. 可先做干跑校验:不落盘,只检查可行性与磁盘空间
repmgr -f /etc/repmgr.conf standby clone -h node1 --dry-run

standby clone 自动写入 primary_conninfo 与 primary_slot_name(开启复制槽时),创建 standby.signal,把备库配置一次到位。级联场景用 --upstream-node-id 指定上游备库;上游库配置参见级联复制。

clone 的前置条件清单:

  • 目标数据目录为空或不存在(repmgr 默认拒绝覆盖已有数据);
  • 备库机器能以 conninfo 中的账号访问上游的元数据库与复制连接(对应 pg_hba.conf 的两条放行);
  • pg_bindir 指向正确的 PostgreSQL 可执行目录,且主备大版本一致;
  • 上游的 max_wal_senders / max_replication_slots 余量足够容纳新节点。

先 dry-run 再落盘

standby clone --dry-run 会做除实际拷贝外的全部检查(连通性、权限、磁盘空间、目录占用),把「克隆到 80% 失败」变成「30 秒内得到明确报错」。任何一次生产克隆前都先干跑一遍,是零成本的保险。

常用命令总览 ​

命令作用
repmgr primary register / primary status / primary unregister主库的注册、状态查看、注销
repmgr standby clone从上游克隆备库数据目录(内部用 pg_basebackup)
repmgr standby register / standby unregister备库注册 / 注销
repmgr standby promote把本备库提升为主库
repmgr standby follow让备库跟随指定新上游
repmgr standby switchover计划内主备切换
repmgr cluster show集群成员与角色总览
repmgr cluster events事件历史流水
repmgr cluster matrix / cluster crosscheck节点两两连通性矩阵(matrix 看出向,crosscheck 双向核对)
repmgr cluster cleanup清理元数据中的监控历史(防止历史表无限膨胀)
repmgr node status本节点复制状态:上游、延迟、复制槽等
repmgr node check逐项健康检查(连接、复制、槽、归档等),适合接监控
repmgr node rejoin让脱离集群的旧节点(如被降级的旧主库)重新加入,可配 --force-rewind
repmgr node service通过配置的 service 命令启停本节点 PostgreSQL
repmgr witness register / witness unregister注册 / 注销见证节点
repmgr daemon start / stop / status启动、停止、查看本节点 repmgrd

巡检两条命令的典型输出:

bash
repmgr -f /etc/repmgr.conf node status
text
Node "node2" (ID: 2) is an active standby with upstream "node1" (ID: 1).
Node classification: "- - -"
Replication lag     : 0 seconds / 0 bytes
WAL receiving       : streaming
Replication slot    : node2_slot (physical)
    slot status     : healthy
bash
repmgr -f /etc/repmgr.conf node check
text
Node "node2":
	Server version: 18.0
	Node name: "node2"
	Node ID: 2
	Current upstream: "node1"
	WAL archiving: off
	Replication connections: OK (number of standby databases: 0)
	Replication slots: 0 physical, 0 logical slot(s)

见证节点(witness)与双节点脑裂 ​

自动故障转移有一个绕不开的约束:repmgrd 需要区分「主库真的挂了」和「我看不见主库了」。三节点及以上时,其余健康节点可以互相印证;两节点集群(一主一备)时没有第三方视角——两台机器之间的网络中断会让备库误判「主库挂了」并自我提升,形成双主脑裂。

见证节点(witness)就是为这个场景准备的第三方:它是一台只存元数据、不存业务数据的小 PostgreSQL 实例,注册进集群后通过元数据同步与主库保持一致。它的仲裁逻辑是:备库看不见主库时,先询问见证节点——如果见证节点还能看见主库,说明只是「备库与主库之间」的网络断了,备库不应提升;如果见证节点也看不见主库,才判定主库真死,允许提升。

bash
# 在独立小服务器上初始化一个空实例作为 witness 数据目录
repmgr -f /etc/repmgr-witness.conf witness register -h node1 -D /var/lib/postgresql/18/witness

部署要点:见证节点应与主库位于同一网络分区/机房,这样它才能代表「主库侧视角」;见证实例只需要极小规格(元数据量与业务无关),但必须有独立的 repmgrd 进程与 repmgr.conf。

witness 不是共享存储,也不是备份

见证节点不复制业务数据、无法参与提升、不能代替备份。它的唯一价值是为双节点集群提供仲裁视角;三节点以上集群不需要 witness,标准的多副本设计见级联复制。

复制槽与 use_replication_slots ​

use_replication_slots=yes 后,repmgr 会在主库为每个备库自动创建物理复制槽,并把 primary_slot_name 写进备库配置。这解决了流复制最经典的运维痛点——备库落后超过 wal_keep_size 后 WAL 被回收、复制中断、被迫重做基础备份。复制槽原理参见复制槽。

repmgr 对槽的管理不止于创建:故障转移后,新主库会为各备库重建复制槽(旧主库上的槽已随角色失效);standby clone --dry-run 会预先检查槽名冲突;node status 输出里会显示本节点槽的健康状态。代价依然是那个经典警告:槽会无限制保留 WAL,长期宕机的备库会撑爆主库磁盘,务必配合 max_slot_wal_keep_size 上限与监控(见复制槽策略)。

repmgrd 自动故障转移 ​

failover=automatic 时,repmgrd 进入守护循环,每个周期执行:监控上游 → 与兄弟节点交换视角 → 判定故障 → 选举候选 → 执行提升 → 全员跟随。

text
┌─────────────── repmgrd 故障转移决策 ───────────────────────┐
│ 1. 主库连接超时 / 复制流中断                                 │
│ 2. 与兄弟备库、见证节点交换视角:主库是「真死」还是「失联」?  │
│ 3. 确认真死后:在健康备库中选候选                             │
│    - 数据最新(WAL 位置最靠前)优先                          │
│    - 其次比较 node_priority                                  │
│ 4. 候选执行 promote_command → repmgr standby promote         │
│ 5. 其余备库执行 follow_command(%n = 新主库 node_id)        │
│ 6. 新主库重建各备库复制槽,事件写入元数据并触发通知           │
└──────────────────────────────────────────────────────────────┘

两条命令就是自动故障转移的全部「可编程面」:promote_command 决定「怎么提升」,follow_command 决定「怎么跟随」。它们必须是幂等、可重试的——repmgrd 在边界条件下可能重复执行。旧主库恢复上线后,由人工(或监控脚本)用 repmgr node rejoin 让它以备库身份重新加入;数据目录与新主库有分叉时加 --force-rewind 走 pg_rewind 回卷(wal_log_hints 等前提与 Patroni 一节所述相同)。

候选节点的资格判定依据,按优先级排列:

  1. 本节点健康且已注册:repmgrd 在运行、节点在元数据中处于 active 状态;
  2. 数据最新:与其他备库比较 WAL 位置,位置最靠前者优先——数据旧不配当新主;
  3. node_priority:数据相当(差距在容忍范围内)时,优先级数值大者当选;
  4. 视角仲裁:与兄弟节点及见证节点交换视角,确认主库「真死」而非局部失联。

理解这个顺序就能反推运维动作:想让某台机器优先当选,给它更高的 node_priority;想让某台机器永远不当选(如异地延迟备库),把它设为排除参与提升(细节以官方文档为准),而不是指望它「恰好不是最新的」。

failover=manual 不等于没有脑裂风险

failover=manual 只是 repmgrd 不自动提升,监控与事件记录照常工作。它适合「宁可人工决策也不想误切」的环境,配合 手工故障切换 流程使用。

计划内切换(switchover) ​

版本升级、硬件维护、机房迁移都要求「主备角色互换且服务不中断」,repmgr 用一条命令完成整套动作:

bash
# 在将成为新主库的备库(node2)上执行
repmgr -f /etc/repmgr.conf standby switchover --siblings-follow

内部流程与手工切换一一对应:

  1. 校验前置条件(主库可达、复制正常、无长事务阻塞);
  2. 将旧主库(node1)优雅降级:等待事务排空、拒绝新连接;
  3. 等待 node2 追平 WAL 差距;
  4. 提升 node2 为主库(新时间线);
  5. 旧主库 node1 自动 follow 新主库转为备库(数据有分叉时借助 pg_rewind);
  6. --siblings-follow 让 node3 等其他备库一并跟随新主库。
bash
# 干跑:只做检查不做变更
repmgr -f /etc/repmgr.conf standby switchover --dry-run

# 旧主库与新主库数据不一致时,借助 pg_rewind 修正旧主库
repmgr -f /etc/repmgr.conf standby switchover --siblings-follow --force-rewind

# 定时切换:预约在业务低峰自动执行
repmgr -f /etc/repmgr.conf standby switchover --siblings-follow --scheduled='2026-10-08 02:00'

计划内切换全程无数据丢失,是比故障转移安全得多的操作;定期做 switchover 演练本身就是对集群健康度的体检。它与手工切换的对应关系,可以对照手工故障切换逐条验证:

switchover 内部步骤手工操作的等价命令
校验前置条件cluster show + node status 人工目检
旧主库优雅降级应用侧停写 + pg_ctl stop -m fast
等待 WAL 追平pg_stat_replication 观察 replay_lsn
提升新主库pg_ctl promote / SELECT pg_promote();
旧主库跟随新主库pg_rewind(如有分叉)+ standby.signal + 重启
其他备库改指新主库逐台改 primary_conninfo 并重启

事件通知与监控 ​

repmgr 把「集群里发生了什么」记录在事件历史中,并提供两种消费方式:

bash
# 命令行查看事件流水
repmgr -f /etc/repmgr.conf cluster events --limit 10
text
 Node | Event             | OK | Timestamp           | Details
------+-------------------+----+---------------------+------------------------------------
 1    | primary_register  | y  | 2026-10-07 10:00:00 | primary registered
 2    | standby_register  | y  | 2026-10-07 10:02:11 | standby registered
 2    | standby_promote   | y  | 2026-10-08 02:00:04 | node 2 promoted to primary, new timeline 2
 1    | node_rejoin       | y  | 2026-10-08 02:03:41 | node rejoined, timeline 2

event_notifications + event_notification_command 把同一份事件实时推给外部系统(告警平台、运维机器人、工单系统),占位符 %e %n %d 分别替换为事件名、节点号与描述。监控侧的接入点:

监控点来源说明
节点角色与状态repmgr cluster show主库缺失、备库 down 都是最高级告警
复制延迟repmgr node status / pg_stat_replication延迟影响故障转移候选资格
repmgrd 进程存活systemd / repmgr daemon statusrepmgrd 挂了自动转移就没有了
节点两两连通repmgr cluster crosscheck网络分区的前兆
事件流cluster events / 事件通知提升与切换的审计记录

repmgr 自身不带 Prometheus exporter,监控脚本可直接调用 repmgr node check 的机器可读输出或查询元数据表(表结构以官方文档为准),数据库层指标复用常规的 pg_stat_replication 采集即可,参见复制监控。

与 PgBouncer / HAProxy 的配合 ​

repmgr 与连接层组件的组合方式和 Patroni 一节完全同构,差别只在「角色变化的通知速度」:

  • PgBouncer + repmgr:[databases] 指向 HAProxy 写端口或 VIP。切换后 PgBouncer 池内的旧连接断开重连即恢复;必要时 RECONNECT 加速。
  • HAProxy + repmgr:repmgr 没有 Patroni 那样的 REST API,角色健康检查退回到 TCP 层。常见做法是 HAProxy 用 option pgsql-check 探测节点存活,同时各节点跑一个小脚本依据 repmgr 元数据(或 pg_is_in_recovery())维护一个 HTTP 状态文件/端口,用 option httpchk 消费——即「repmgr 决策,自建探针表达角色」。
  • Keepalived VIP:VIP 迁移由 event_notification_command 触发(standby_promote 事件时在新主库上接管 VIP、旧主库上释放),脚本要幂等并处理「释放旧 VIP 失败」的残余状态。

「自建探针表达角色」的最小实现——每个节点上用 systemd socket 或任意轻量 HTTP 服务输出角色状态,HAProxy 据此分流:

bash
#!/bin/bash
# /usr/local/bin/role_probe.sh —— 各节点定时刷新角色状态文件(供 HTTP 服务暴露)
if psql -qAtX -h /var/run/postgresql -d postgres -c "SELECT pg_is_in_recovery();" | grep -q 'f'; then
    echo "primary" > /var/www/role
else
    echo "replica" > /var/www/role
fi
conf
# haproxy.cfg:主库端口按探针结果路由
backend pg_primary
    option httpchk GET /role
    http-check expect string primary
    default-server inter 3s fall 3 rise 1 on-marked-down shutdown-sessions
    server node1 192.168.1.11:5432 check port 5100
    server node2 192.168.1.12:5432 check port 5100
    server node3 192.168.1.13:5432 check port 5100

相比 Patroni 方案,这里多出来的每一段胶水脚本都是要自己维护的代码。组件少的优势与角色表达的短板,在选型时应该放在一起权衡。

与 Patroni 的选型对比 ​

维度repmgrPatroni
架构依赖无外部 DCS,状态存于数据库元数据依赖 etcd / Consul / ZooKeeper / Kubernetes
部署复杂度低:装包、写 conf、注册即成中高:需先搭建并维护 DCS 集群
自动故障转移有(repmgrd),依赖兄弟节点/witness 互证有,DCS 租约仲裁,机制更健壮
脑裂防护依赖网络设计与见证节点;双节点场景需要 witnessDCS 租约 + watchdog fencing,覆盖更全面
计划内切换standby switchover(支持 --scheduled)patronictl switchover(支持定时)
配置管理逐节点本地 repmgr.confDCS 集中动态配置(edit-config 全集群生效)
角色表达能力无内置 API,需自建探针/VIP 脚本REST API 原生表达角色(/primary、/replica)
生态与社区老牌工具,EDB 维护,迭代节奏平缓Zalando 主导,社区活跃,云原生生态好
典型适用既有 Postgres 运维团队、组件求简、双节点+witness新建集群、K8s 环境、要求强 fencing 与集中配置

一句话总结:没有历史包袱、能接受 DCS 依赖时选 Patroni;已有简单拓扑、想少一个组件时选 repmgr。两者都要求「复制槽 + 备份 + 监控」的基本盘,这些底座与选型无关,参见主库配置与备库配置。

实战示例 ​

示例一:两节点 + witness 的完整搭建 ​

bash
# ---- node1(主库)----
# 1. 建用户与元数据库
sudo -u postgres psql -c "CREATE USER repmgr WITH LOGIN SUPERUSER PASSWORD 'R3pmgr_Secret';"
sudo -u postgres psql -c "CREATE DATABASE repmgr OWNER repmgr;"

# 2. 写 /etc/repmgr.conf(见「语法与用法」),放行 pg_hba 后注册
repmgr -f /etc/repmgr.conf primary register

# ---- node2(备库)----
# 3. 写 repmgr.conf(node_id=2, node_name=node2, conninfo 指向 node2 ...)
# 4. 克隆并注册
repmgr -f /etc/repmgr.conf standby clone -h node1
sudo systemctl start postgresql@18-main
repmgr -f /etc/repmgr.conf standby register

# ---- witness(独立小实例,数据目录单独初始化)----
# 5. 注册见证节点,仲裁双节点集群
initdb -D /var/lib/postgresql/18/witness
repmgr -f /etc/repmgr-witness.conf witness register -h node1 -D /var/lib/postgresql/18/witness

# ---- 全部节点 ----
# 6. 启动 repmgrd(systemd 包管理器装包后通常自带 repmgrd.service)
sudo systemctl enable --now repmgrd

示例二:健康巡检三连 ​

bash
# 1. 集群总览
repmgr -f /etc/repmgr.conf cluster show

# 2. 本节点复制细节(延迟、槽、WAL 接收状态)
repmgr -f /etc/repmgr.conf node status

# 3. 节点两两连通性(排查网络分区的第一步)
repmgr -f /etc/repmgr.conf cluster crosscheck
text
 Name  | Node ID | Connection to node1 | Connection to node2 | Connection to witness
-------+---------+---------------------+---------------------+-----------------------
 node1 | 1       | *                   | success             | success
 node2 | 2       | success             | *                   | success
 witness | 3     | success             | success             | *

crosscheck 输出的矩阵里任何一格出现 failed,都意味着存在分区视角差——这正是 witness 与多节点互证机制赖以工作的输入,也是网络排障的起点。

示例三:计划内切换演练 ​

bash
# 1. 干跑检查
repmgr -f /etc/repmgr.conf standby switchover --dry-run --siblings-follow

# 2. 正式切换(在 node2 上执行,node2 即将成为主库)
repmgr -f /etc/repmgr.conf standby switchover --siblings-follow

# 3. 确认角色互换与新时间线
repmgr -f /etc/repmgr.conf cluster show
repmgr -f /etc/repmgr.conf cluster events --limit 5
text
 ID | Name  | Role    | Status    | Upstream | Timeline
----+-------+---------+-----------+----------+----------
 1  | node1 | standby |   running | node2    | 2
 2  | node2 | primary | * running |          | 2
 3  | witness | witness | * running | node2  | 2

示例四:自动故障转移演练 ​

bash
# 1. 模拟主库崩溃(主库此时是 node2)
sudo pkill -9 -f 'postgres -D'

# 2. 在备库上观察 repmgrd 的动作(日志或事件流)
tail -f /var/log/postgresql/repmgrd.log
text
[2026-10-08 02:30:11] INFO: connection to upstream node 2 lost
[2026-10-08 02:30:14] NOTICE: attempting to ping node "node2" (ID: 2)
[2026-10-08 02:30:16] WARNING: unable to ping "node2"
[2026-10-08 02:30:18] NOTICE: this node is the winner, will now promote itself
[2026-10-08 02:30:19] NOTICE: promoting standby to primary
[2026-10-08 02:30:21] NOTICE: STANDBY PROMOTE successful
bash
# 3. 旧主库恢复后,人工让它重新加入(有分叉时走 pg_rewind)
repmgr -f /etc/repmgr.conf node rejoin -h node2 --force-rewind

示例五:事件通知接入告警平台 ​

ini
# repmgr.conf
event_notification_command='/usr/local/bin/repmgr_alert.sh %e %n "%d"'
event_notifications='standby_promote,primary_failover,standby_failover,switchover,repmgrd_shutdown'
bash
#!/bin/bash
# /usr/local/bin/repmgr_event.sh —— 推送到内部告警机器人(示例)
EVENT=$1; NODE=$2; DETAIL=$3
curl -s -X POST https://alert.internal.example.com/api/v1/events \
     -H 'Content-Type: application/json' \
     -d "{\"source\":\"repmgr\",\"event\":\"$EVENT\",\"node\":\"$NODE\",\"detail\":\"$DETAIL\"}"

至少订阅四类事件:standby_promote(发生提升,无论计划内外都要知道)、primary_failover(自动故障转移已发生)、switchover(计划内切换完成)、repmgrd_shutdown(守护进程退出——它挂了就没有下一次自动转移了)。

示例六:把 node check 接入监控脚本 ​

repmgr node check 的输出本身就是一份健康定义,包一层即可接入 cron / systemd timer / 监控代理:

bash
#!/bin/bash
# /usr/local/bin/repmgr_health.sh —— 出问题时非零退出,供监控代理调用
OUT=$(repmgr -f /etc/repmgr.conf node check 2>/dev/null)
RC=$?

if [ $RC -ne 0 ]; then
    logger -t repmgr_health "node check failed with exit code $RC"
    echo "$OUT" | logger -t repmgr_health
    exit 1
fi

if echo "$OUT" | grep -qE 'FAILED|CRITICAL'; then
    logger -t repmgr_health "node check reported failures:"
    echo "$OUT" | grep -E 'FAILED|CRITICAL' | logger -t repmgr_health
    exit 1
fi

exit 0
bash
# 每 5 分钟巡检一次(crontab)
*/5 * * * * /usr/local/bin/repmgr_health.sh
text
# 正常节点上手动执行,确认退出码为 0
repmgr -f /etc/repmgr.conf node check; echo "exit=$?"
text
Node "node2":
	Server version: 18.0
	Node name: "node2"
	Node ID: 2
	Current upstream: "node1"
	WAL archiving: off
	Replication connections: OK (number of standby databases: 0)
	Replication slots: 0 physical, 0 logical slot(s)
exit=0

这套脚本与事件通知互补:事件通知管「集群级的大事」,巡检脚本管「单节点的小病」,两者都非零时优先怀疑网络分区(结合 cluster crosscheck 判断)。

注意事项 ​

conninfo 必须是其他节点可达的地址。 写成 localhost 的后果是元数据同步、兄弟互证、跟随切换全部静默失败;它一经注册就存入元数据表,改动要走注销重注册流程。

node_id 与 node_name 注册后不可变。 变更标识等于重建节点;规划节点名时预留扩展性(如 pg-1/pg-2/pg-3),不要用临时主机名。

双节点集群必须有 witness 或人工 failover。 没有 third-party 视角的自动故障转移在网络分区下必然产生双主,这不是配置问题而是机制约束。

repmgrd 必须在每个节点上运行。 包括 witness(它的 repmgrd 负责元数据同步与视角仲裁);监控 repmgrd 进程存活与监控数据库本身同等重要。

旧主库回归要人工参与。 repmgr 不会自动把恢复的旧主库拉回集群,node rejoin(必要时 --force-rewind)是标准流程;把这个步骤写进切换 runbook。

--force-rewind 的前提与 Patroni 相同。 wal_log_hints=on 或数据页校验和是 pg_rewind 生效的前提,建集群时就要配置好;细节以官方文档为准。

复制槽是双刃剑。 use_replication_slots=yes 解决 WAL 回收问题的同时引入了磁盘风险,务必配置 max_slot_wal_keep_size 并监控 pg_wal 水位。

元数据表只读不写。 修复集群状态一律通过 repmgr 命令;直接 UPDATE 元数据会破坏 repmgrd 的决策输入,产生难以追溯的故障。

升级 repmgr 大版本前先读兼容性说明。 元数据表结构随版本演进,升级步骤(扩展更新、repmgrd 重启顺序)以官方文档为准,切勿跳版本。

failover=automatic 的演练要在低峰做。 故障转移涉及提升、跟随、槽重建三个动作,任何一步失败都会留下「半切换」状态;演练时全程盯 cluster events 与日志。

repmgr 与 Patroni 不要混装。 两套工具对同一个数据目录有各自的状态假设,同时管理必然冲突;迁移时要彻底卸载一方再部署另一方。

最佳实践 ​

  1. 三节点起步,双节点必须加 witness。 网络分区视角是自动故障转移的安全底线;witness 放在与主库同分区的独立小实例上。

  2. use_replication_slots=yes + max_slot_wal_keep_size 成对出现。 槽保证备库 WAL 不被回收,上限保证备库宕机不撑爆主库磁盘。

  3. promote_command / follow_command 写完后立刻演练。 这两条命令是故障日的唯一执行路径,路径上的每一个绝对路径、每一个账号权限都要实测。

  4. 事件通知至少接入四类事件。 standby_promote、primary_failover、switchover、repmgrd_shutdown——特别是最后一个,它失效意味着自动转移整体失效。

  5. 把 repmgr node check 接入监控采集。 它的逐项检查(连接、复制、槽、归档)是现成的健康定义,比自拼 SQL 更贴近 repmgrd 的判断标准。

  6. 每个季度做一次 switchover 演练。 计划内切换验证的是全链路:复制健康度、切换耗时、PgBouncer/HAProxy 恢复、应用重连;记录 RTO 并与上期对比。演练方法参见灾难恢复演练。

  7. 旧主库回归写进 runbook。 node rejoin --force-rewind 的执行条件、回卷后的校验步骤、验证查询,全部文档化,故障当天照单执行。

  8. 元数据库账号按最小权限原则收敛。 官方文档为简化起见建议 SUPERUSER,安全敏感环境可按官方文档拆分所需权限,并用 scram-sha-256 认证。

  9. HAProxy 角色探针独立于 repmgr。 用 pg_is_in_recovery() 之类数据库自身事实构建 HTTP 探针,让负载均衡不依赖 repmgr 元数据可用性,解耦故障域。

  10. 升级顺序:先备库、后主库。 PostgreSQL 与 repmgr 的升级都在备库上先行验证,switchover 后再处理原主库,任一步失败都有完整的主库在位。

  11. cluster crosscheck 纳入日常巡检。 连通性矩阵是最早的网络分区信号,等它反映到复制中断时往往已经错过了最佳处理窗口。

  12. 选型犹豫时先试 Patroni。 新建集群、容器化环境、需要集中配置管理的场景,Patroni 的 REST API 与 fencing 生态更完整;repmgr 的优势场景是「已有轻量拓扑、只差自动切换的最后一公里」。

下一节

继续学习:读写分离

参考链接 ​