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 CLI | repmgr | 管理命令行工具,注册节点、克隆备库、执行切换 |
| repmgrd | repmgrd | 守护进程,负责监控与自动故障转移 |
| repmgr 扩展 | repmgr extension | 数据库内维护集群元数据的 PostgreSQL 扩展 |
| 元数据 | metadata | 存放节点清单、事件历史、监控历史的库表集合 |
| 主节点 | primary | 当前承担写入的节点 |
| 备节点 | standby | 流复制 follower,可提升为主 |
| 上游节点 | upstream node | 级联复制中备库的 WAL 来源(主库或另一台备库) |
| 见证节点 | witness | 只保存元数据、不承担数据的仲裁用小实例 |
| 自动故障转移 | automatic failover | repmgrd 检测主库失效并自动提升备库 |
| 计划内切换 | 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 的完整示例:
# ---- 节点标识(必填,且全集群唯一、注册后不可改)----
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'几乎所有操作都要显式带上配置文件:
# 在主库上注册集群起点
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 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 官方文档建议该用户使用超级用户以简化操作,安全要求高的环境可按需收敛权限):
CREATE USER repmgr WITH LOGIN SUPERUSER PASSWORD 'R3pmgr_Secret';
CREATE DATABASE repmgr OWNER repmgr;# 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_command | automatic 时必填 | 候选节点被选中后执行的提升命令,通常是 repmgr standby promote -f ... |
follow_command | automatic 时必填 | 其余备库跟随新主库的命令,%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 搭集群的顺序是「先主后备」,每一步都是可回退的显式命令:
# 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-runstandby 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 |
巡检两条命令的典型输出:
repmgr -f /etc/repmgr.conf node statusNode "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 : healthyrepmgr -f /etc/repmgr.conf node checkNode "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 实例,注册进集群后通过元数据同步与主库保持一致。它的仲裁逻辑是:备库看不见主库时,先询问见证节点——如果见证节点还能看见主库,说明只是「备库与主库之间」的网络断了,备库不应提升;如果见证节点也看不见主库,才判定主库真死,允许提升。
# 在独立小服务器上初始化一个空实例作为 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 进入守护循环,每个周期执行:监控上游 → 与兄弟节点交换视角 → 判定故障 → 选举候选 → 执行提升 → 全员跟随。
┌─────────────── 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 一节所述相同)。
候选节点的资格判定依据,按优先级排列:
- 本节点健康且已注册:repmgrd 在运行、节点在元数据中处于 active 状态;
- 数据最新:与其他备库比较 WAL 位置,位置最靠前者优先——数据旧不配当新主;
- node_priority:数据相当(差距在容忍范围内)时,优先级数值大者当选;
- 视角仲裁:与兄弟节点及见证节点交换视角,确认主库「真死」而非局部失联。
理解这个顺序就能反推运维动作:想让某台机器优先当选,给它更高的 node_priority;想让某台机器永远不当选(如异地延迟备库),把它设为排除参与提升(细节以官方文档为准),而不是指望它「恰好不是最新的」。
failover=manual 不等于没有脑裂风险
failover=manual 只是 repmgrd 不自动提升,监控与事件记录照常工作。它适合「宁可人工决策也不想误切」的环境,配合 手工故障切换 流程使用。
计划内切换(switchover)
版本升级、硬件维护、机房迁移都要求「主备角色互换且服务不中断」,repmgr 用一条命令完成整套动作:
# 在将成为新主库的备库(node2)上执行
repmgr -f /etc/repmgr.conf standby switchover --siblings-follow内部流程与手工切换一一对应:
- 校验前置条件(主库可达、复制正常、无长事务阻塞);
- 将旧主库(node1)优雅降级:等待事务排空、拒绝新连接;
- 等待 node2 追平 WAL 差距;
- 提升 node2 为主库(新时间线);
- 旧主库 node1 自动 follow 新主库转为备库(数据有分叉时借助 pg_rewind);
--siblings-follow让 node3 等其他备库一并跟随新主库。
# 干跑:只做检查不做变更
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 把「集群里发生了什么」记录在事件历史中,并提供两种消费方式:
# 命令行查看事件流水
repmgr -f /etc/repmgr.conf cluster events --limit 10 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 2event_notifications + event_notification_command 把同一份事件实时推给外部系统(告警平台、运维机器人、工单系统),占位符 %e %n %d 分别替换为事件名、节点号与描述。监控侧的接入点:
| 监控点 | 来源 | 说明 |
|---|---|---|
| 节点角色与状态 | repmgr cluster show | 主库缺失、备库 down 都是最高级告警 |
| 复制延迟 | repmgr node status / pg_stat_replication | 延迟影响故障转移候选资格 |
| repmgrd 进程存活 | systemd / repmgr daemon status | repmgrd 挂了自动转移就没有了 |
| 节点两两连通 | 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 据此分流:
#!/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# 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 的选型对比
| 维度 | repmgr | Patroni |
|---|---|---|
| 架构依赖 | 无外部 DCS,状态存于数据库元数据 | 依赖 etcd / Consul / ZooKeeper / Kubernetes |
| 部署复杂度 | 低:装包、写 conf、注册即成 | 中高:需先搭建并维护 DCS 集群 |
| 自动故障转移 | 有(repmgrd),依赖兄弟节点/witness 互证 | 有,DCS 租约仲裁,机制更健壮 |
| 脑裂防护 | 依赖网络设计与见证节点;双节点场景需要 witness | DCS 租约 + watchdog fencing,覆盖更全面 |
| 计划内切换 | standby switchover(支持 --scheduled) | patronictl switchover(支持定时) |
| 配置管理 | 逐节点本地 repmgr.conf | DCS 集中动态配置(edit-config 全集群生效) |
| 角色表达能力 | 无内置 API,需自建探针/VIP 脚本 | REST API 原生表达角色(/primary、/replica) |
| 生态与社区 | 老牌工具,EDB 维护,迭代节奏平缓 | Zalando 主导,社区活跃,云原生生态好 |
| 典型适用 | 既有 Postgres 运维团队、组件求简、双节点+witness | 新建集群、K8s 环境、要求强 fencing 与集中配置 |
一句话总结:没有历史包袱、能接受 DCS 依赖时选 Patroni;已有简单拓扑、想少一个组件时选 repmgr。两者都要求「复制槽 + 备份 + 监控」的基本盘,这些底座与选型无关,参见主库配置与备库配置。
实战示例
示例一:两节点 + witness 的完整搭建
# ---- 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示例二:健康巡检三连
# 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 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 与多节点互证机制赖以工作的输入,也是网络排障的起点。
示例三:计划内切换演练
# 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 ID | Name | Role | Status | Upstream | Timeline
----+-------+---------+-----------+----------+----------
1 | node1 | standby | running | node2 | 2
2 | node2 | primary | * running | | 2
3 | witness | witness | * running | node2 | 2示例四:自动故障转移演练
# 1. 模拟主库崩溃(主库此时是 node2)
sudo pkill -9 -f 'postgres -D'
# 2. 在备库上观察 repmgrd 的动作(日志或事件流)
tail -f /var/log/postgresql/repmgrd.log[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# 3. 旧主库恢复后,人工让它重新加入(有分叉时走 pg_rewind)
repmgr -f /etc/repmgr.conf node rejoin -h node2 --force-rewind示例五:事件通知接入告警平台
# 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'#!/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 / 监控代理:
#!/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# 每 5 分钟巡检一次(crontab)
*/5 * * * * /usr/local/bin/repmgr_health.sh# 正常节点上手动执行,确认退出码为 0
repmgr -f /etc/repmgr.conf node check; echo "exit=$?"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 不要混装。 两套工具对同一个数据目录有各自的状态假设,同时管理必然冲突;迁移时要彻底卸载一方再部署另一方。
最佳实践
三节点起步,双节点必须加 witness。 网络分区视角是自动故障转移的安全底线;witness 放在与主库同分区的独立小实例上。
use_replication_slots=yes+max_slot_wal_keep_size成对出现。 槽保证备库 WAL 不被回收,上限保证备库宕机不撑爆主库磁盘。promote_command/follow_command写完后立刻演练。 这两条命令是故障日的唯一执行路径,路径上的每一个绝对路径、每一个账号权限都要实测。事件通知至少接入四类事件。
standby_promote、primary_failover、switchover、repmgrd_shutdown——特别是最后一个,它失效意味着自动转移整体失效。把
repmgr node check接入监控采集。 它的逐项检查(连接、复制、槽、归档)是现成的健康定义,比自拼 SQL 更贴近 repmgrd 的判断标准。每个季度做一次 switchover 演练。 计划内切换验证的是全链路:复制健康度、切换耗时、PgBouncer/HAProxy 恢复、应用重连;记录 RTO 并与上期对比。演练方法参见灾难恢复演练。
旧主库回归写进 runbook。
node rejoin --force-rewind的执行条件、回卷后的校验步骤、验证查询,全部文档化,故障当天照单执行。元数据库账号按最小权限原则收敛。 官方文档为简化起见建议 SUPERUSER,安全敏感环境可按官方文档拆分所需权限,并用
scram-sha-256认证。HAProxy 角色探针独立于 repmgr。 用
pg_is_in_recovery()之类数据库自身事实构建 HTTP 探针,让负载均衡不依赖 repmgr 元数据可用性,解耦故障域。升级顺序:先备库、后主库。 PostgreSQL 与 repmgr 的升级都在备库上先行验证,switchover 后再处理原主库,任一步失败都有完整的主库在位。
cluster crosscheck纳入日常巡检。 连通性矩阵是最早的网络分区信号,等它反映到复制中断时往往已经错过了最佳处理窗口。选型犹豫时先试 Patroni。 新建集群、容器化环境、需要集中配置管理的场景,Patroni 的 REST API 与 fencing 生态更完整;repmgr 的优势场景是「已有轻量拓扑、只差自动切换的最后一公里」。
下一节
继续学习:读写分离