PostgreSQL高可用实战:repmgr主备部署与自动切换指南
干数据库运维这个行当每次提到高可用我大概率会先问一句你现在是“能跑”还是“能切”很多环境里 PostgreSQL 主备复制都搭好了但真到主库宕机那一刻备库能不能自动顶上、数据会不会丢、脑裂怎么防全是问号。PostgreSQL 安装部署、主备复制、再加上 repmgr 这套集群管理工具正好能把“能跑”升级成“能切”。repmgr 不像某些方案那样引入一堆外部中间件它寄生在原生流复制之上提供节点注册、状态监控、手动/自动切换和故障节点收回功能非常适合中小规模集群。这篇文章我从裸机开始把三节点 PostgreSQL repmgr 主备部署完整走一遍参数怎么调、踩过哪些坑、切换演练怎么做都写清楚给需要从零搭一套可运维高可用 PG 环境的朋友一条能直接照着走的路。1. 项目概述与整体架构1.1 为什么不是 Patroni而是 repmgr先把这个最容易被问的问题说清楚。市面上 PostgreSQL 高可用方案不少Patroni、repmgr、PAF、甚至自己写 keepalived 脚本各有各的使用场景。我这次选择 repmgr不是因为它比 Patroni 先进而是因为它契合“PostgreSQL 原生化、结构简单、依赖少”这几个关键词。repmgr 的核心思路很直接数据复制仍然用 PostgreSQL 自带的流复制repmgr 只是在每个节点上维护一套元数据表放在 repmgr 数据库里记录节点的角色、上游节点、连接信息、状态等再基于这些信息提供主备注册、集群状态查询、switchover 计划切换、failover 强制提升、故障节点 rejoin 等功能。它不接管 PostgreSQL 进程不改变数据复制链路更像是一个“PG 高可用管家”。对比 PatroniPatroni 会把 PostgreSQL 实例完全纳入自己的编排体系依赖 etcd 或 ZooKeeper 做分布式共识实现基于 leader 选举的自动切换。这种架构在大规模、需要强一致性和自动化运维的场景下确实强但代价是引入额外的存储组件、学习成本和排障复杂度。对于一个两个节点或三五个节点的中小集群repmgr 的轻量优势非常明显安装一个 rpm 包就能跑配置一个 repmgr.conf 就能注册不需要额外的分布式基础设施。还有一点很现实很多存量环境已经手动搭好了 PostgreSQL 流复制主备都在正常跑。此时如果引入 Patroni基本上要把现有复制体系推倒重来而 repmgr 可以在已有流复制基础上直接注册把现有架构平稳纳入管理。这一点对生产环境升级非常友好。1.2 集群角色与节点拓扑repmgr 集群里节点分三种角色理解这三个角色是看懂后面所有配置的前提primary主库集群中唯一可读写的节点。所有写操作先落在它身上它负责把 WAL 持续发送给下游备库。standby备库通过流复制实时接收并回放主库 WAL。正常情况下只读故障时可以被提升为新的 primary。witness见证节点。它不承载业务数据也不参与复制但会独立保存一份 repmgr 元数据。当集群出现网络分区时witness 提供一个第三方视角帮助判断主库到底是真宕机还是只是当前节点失联减少脑裂风险。很多人搭双节点主备时觉得 witness 可有可无我的建议很明确只要条件允许一定要加。双节点场景下备库检测到主库失联它只能基于“我连不上主库”这一个信息做判断无法区分是主库挂了还是网络分区导致双方互相看不到。加入 witness 后备库在准备提升时会先看 witness 是否也连不上主库如果只有自己连不上而 witness 能连上说明大概率是网络隔离而非主库真宕盲目提升会造成双主脑裂。本次部署使用三台虚拟机主机名IP 地址角色数据目录pg-main192.168.66.101primary/var/lib/pgsql/15/datapg-standby192.168.66.102standby/var/lib/pgsql/15/datapg-witness192.168.66.103witness/var/lib/pgsql/15/data操作系统统一使用 Rocky Linux 9数据库使用 PostgreSQL 15repmgr 使用与 PostgreSQL 15 匹配的 repmgr15 版本。需要特别提醒repmgr 版本必须和 PG 主版本对应比如 PG15 就用 repmgr15PG16 就用 repmgr16混装会直接导致命令不识别或元数据不兼容。1.3 数据复制与切换的基本原理既然要搭主备就得先知道数据是怎么从主库到备库的。PostgreSQL 流复制的完整路径是主库每提交一个事务就会生成对应的 WAL 日志WAL 写入日志文件后WAL sender 进程通过网络把数据发送给备库上的 WAL receiver 进程备库收到后先写入本地 WAL 文件再由 startup 进程回放到数据页。这里有两个关键点。第一流复制是异步还是同步取决于主库的synchronous_standby_names参数默认不设置就是异步复制主库提交事务不必等备库确认适合大多数场景性能好但是故障切换时可能有少量数据丢失。第二备库回放 WAL 时处于“恢复模式”对外表现为只读这就是hot_standby on提供的功能。repmgr 的切换本质上就是改变节点角色原主库从读写状态退化为恢复模式原备库从恢复模式进入读写状态。repmgr 通过元数据表记录这些状态变迁并提供命令来触发和确认切换结果。这个机制并不复杂但正是这种简单让它的行为可预期、方便排查也方便我们一步一步手动演练。2. 环境准备与 PostgreSQL 基础安装2.1 节点系统初始化三个节点先做同样的基础配置我习惯把这几项放在最前面处理避免后面排查时被低级问题浪费时间。第一件事是主机名。分别执行hostnamectl set-hostname pg-main hostnamectl set-hostname pg-standby hostnamectl set-hostname pg-witness然后修改每台机器的 /etc/hosts把三个节点都写进去192.168.66.101 pg-main 192.168.66.102 pg-standby 192.168.66.103 pg-witness这一步很多人会跳过去但后端操作中 repmgr 要基于主机名识别节点DNS 或 hosts 解析不一致会出现“节点名称对不上”类的诡异报错而且切换脚本里也常常直接用主机名连接。第二件事是时间同步。数据库集群对时间一致性非常敏感尤其是在 repmgr 这种靠时间戳记录状态变化的场景。我的做法是每个节点配置 chrony 指向同一台内网时间服务器dnf install -y chrony systemctl enable --now chronyd chronyc sources -v第三件事是 SSH 免密。repmgr 的 node rejoin 等操作需要在多个节点间执行命令建议 root 和 postgres 用户都把 SSH 互信配置好。最简单的方式是从主库用 ssh-copy-id 分发公钥ssh-keygen -t rsa -N -f ~/.ssh/id_rsa ssh-copy-id rootpg-main ssh-copy-id rootpg-standby ssh-copy-id rootpg-witness不要贪快跳过这个步骤后面 witness 注册和 rejoin 演示时直接靠它跑通。第四件事是防火墙。内网实验环境我通常直接把集群所在的网段加入受信区域firewall-cmd --permanent --add-rich-rulerule familyipv4 source address192.168.66.0/24 accept firewall-cmd --reload如果公司安全策略要求精细控制至少放行 5432 端口和 SSH 的 22 端口。之前我踩过一个大坑数据库部署完发现复制连不上查了半天是防火墙默认 zone 把 5432 丢了这种问题最费时间。2.2 通过 PGDG 仓库安装 PostgreSQL 15安装 PostgreSQL 我推荐直接用 PGDG 官方仓库不要自己编译源码。编译安装虽然能定制更多参数但不利于后续用系统工具统一维护、打补丁而且部署耗时更长。仓库安装步骤在所有节点上执行。首先安装 PGDG 仓库 RPMdnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm然后禁用 Rocky Linux 自带的 PostgreSQL 模块否则dnf install postgresql15-server时可能解析到系统内置的不同版本dnf -qy module disable postgresql安装服务端和 contrib 扩展包dnf install -y postgresql15-server postgresql15-contrib这里有个容易忽略的点PGDG 仓库安装的软件都带版本号前缀命令统一放在 /usr/pgsql-15/bin 下数据目录默认是 /var/lib/pgsql/15/data服务名是 postgresql-15。我第一次从 Debian 系切过来时总习惯用service postgresql restart结果发现根本没有这个服务名全是版本号后缀适应了一下才习惯。把二进制目录加入 PATH方便后续直接敲命令echo export PATH/usr/pgsql-15/bin:$PATH /etc/profile.d/pgsql.sh source /etc/profile.d/pgsql.sh2.3 初始化集群并配置访问控制主库、备库、witness 节点都需要初始化数据库集群。在备库和 witness 上建议初始化但不启动等 repmgr 流程接管主库则直接初始化并启动。执行初始化/usr/pgsql-15/bin/postgresql-15-setup initdb systemctl start postgresql-15 systemctl enable postgresql-15设置 postgres 超级用户密码sudo -u postgres psql -c ALTER USER postgres PASSWORD postgres;这个密码在生产环境一定要换成足够复杂的并且记到密码库里别以为本地只有自己能连就偷懒。然后修改 /var/lib/pgsql/15/data/pg_hba.conf。这是我每次都会重点叮嘱的地方因为 pg_hba.conf 是 PostgreSQL 访问控制的第一道关卡也是主备复制连不上的头号原因。在文件末尾追加host replication replica 192.168.66.0/24 md5 host all all 192.168.66.0/24 md5第一行允许复制账号 replica 从内网发起流复制连接第二行允许其他客户端统一从内网访问。注意 pg_hba.conf 是从上往下逐条匹配的如果在前面写了拒绝规则后面的允许规则不会生效。改完配置文件别急着重启数据库先pg_ctl reload重载即可sudo -u postgres /usr/pgsql-15/bin/pg_ctl reload -D /var/lib/pgsql/15/data主库初始化到此就绪。我这里用的是最大兼容度的配置后续通过 repmgr 正式部署时还会再调 postgresql.conf。3. 主备复制搭建3.1 主库复制参数逐个拆解repmgr 本身不做数据复制它依赖 PostgreSQL 原生流复制所以主备复制的正确性直接决定 repmgr 能不能正常注册和切换。在主库的 postgresql.conf 中有几个参数是绕不开的我逐个说明理由listen_addresses * wal_level replica max_wal_senders 10 max_replication_slots 10 wal_keep_size 512MB hot_standby onwal_level replica是流复制的最低要求。它决定了 WAL 里会记录足够多的信息供备库恢复logical级别也可以用于流复制但开销更大除非要做逻辑复制否则不用设。max_wal_senders控制同时允许多少个 WAL 发送进程。每增加一个备库就至少消耗一个后续可能还会加节点或做备份我习惯设为 10 而不是默认的 4。max_replication_slots控制复制槽数量。后面 repmgr 配置会开启use_replication_slots用来防止备库 WAL 被过早回收这里先预留。wal_keep_size是 WAL 文件保留的额外空间。备库断线时间过长、复制槽又没开时主库可能已经把备库需要的 WAL 循环掉了导致备库只能重建。把它设成 512MB 是给短时故障留的缓冲垫。hot_standby on允许备库在恢复模式下接受只读查询。这个参数必须在主库上提前配置好因为备库的配置是从主库复制过去的。改完配置重启主库systemctl restart postgresql-15然后创建专门的复制账号。这里我强调一下复制账号最好和超级用户分离权限最小化免得日常连接池或者误操作把它带偏CREATE ROLE replica WITH REPLICATION LOGIN PASSWORD replica;验证账号可用psql -U replica -h 192.168.66.101 -d postgres -c select 1;到这里主库端的复制必要条件已经全部具备。3.2 用 pg_basebackup 构建备库备库初始化不推荐手动执行 initdb而是用 pg_basebackup 从主库拉一份完整的物理备份这样数据文件、WAL 起始点、集群配置都会和主库保持完全一致。备库在安装完 PostgreSQL 后先确保没有启动过或者如果初始化过就清掉数据目录systemctl stop postgresql-15 rm -rf /var/lib/pgsql/15/data然后执行备份sudo -u postgres pg_basebackup -h 192.168.66.101 -p 5432 -U replica \ -D /var/lib/pgsql/15/data -R -P -X stream这里几个参数的意义要理解-R会在备份完成时自动生成 standby.signal 文件并写入主库连接信息到 postgresql.auto.conf备库启动后自动进入恢复模式并接入复制。-X stream表示 WAL 通过流复制方式持续传输而不是打包归档文件。这样备份结束后备库能立刻无缝追平主库的增量数据。-P显示进度一个多 GB 的库能直观看到传输速度。备份完成后修复文件属主然后启动备库chown -R postgres:postgres /var/lib/pgsql/15/data systemctl start postgresql-15备库启动后在主库上执行这条 SQL就能看到复制链路已经建立SELECT client_addr, state, sync_state, write_lag, flush_lag, replay_lag FROM pg_stat_replication;正常输出中 client_addr 应为 192.168.66.102state 为streaming三个 lag 字段都接近 0。如果这里看不到记录说明备库没有真正连接上主库优先检查 pg_hba.conf 的复制规则和防火墙。3.3 备库状态自查进入备库确认恢复状态sudo -u postgres psql -c select pg_is_in_recovery();返回t代表当前确实处于恢复模式说明它是标准备库而不是误启动成独立实例。再看 WAL 回放延迟sudo -u postgres psql -c select pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn());返回值接近 0 表示接收和回放之间没有积压。如果这个值持续增大说明备库磁盘写速跟不上主库需要检查备库磁盘性能。到这里纯手工的 PostgreSQL 主备复制已经建立。但这样只是“能跑”还不能自动切换因为没有哪一层在做节点状态管理和切换决策。接下来就是 repmgr 登场的地方。4. repmgr 的部署与注册4.1 repmgr15 安装与目录规划在三个节点上安装 repmgr15dnf install -y repmgr15安装完成后二进制在 /usr/pgsql-15/bin/repmgr配置文件需要手动创建。我习惯的目录规划是配置文件/etc/repmgr/15/repmgr.conf日志目录/var/log/repmgr创建目录并授权mkdir -p /etc/repmgr/15 /var/log/repmgr chown -R postgres:postgres /etc/repmgr /var/log/repmgr特别提醒一个容易被忽略的地方repmgr 命令通常用 postgres 用户执行所以配置文件和数据目录的权限必须对 postgres 可读。如果直接用 root 运行 repmgr 也可以但会留下 root 归属的文件后面切换剧本执行时容易踩权限坑。4.2 repmgr.conf 配置详解repmgr 的配置集中在 repmgr.conf 一个文件里主库、备库、witness 的配置内容基本一致只有 node_id、node_name、conninfo 中的 host 需要按节点区分。先看主库 pg-main 的 /etc/repmgr/15/repmgr.confnode_id101 node_namepg-main conninfohost192.168.66.101 dbnamerepmgr userrepmgr passwordrepmgr port5432 data_directory/var/lib/pgsql/15/data pg_bindir/usr/pgsql-15/bin replication_userreplica replication_user_passwordreplica use_replication_slotstrue monitoring_interval2s逐项解读关键配置node_id和node_name在集群内必须唯一。node_id 我用的是 101、102、103命名上尽量和 IP 对应的习惯保持一致方便人肉记忆。conninfo是 repmgr 连接数据库用的连接串里面指定了 repmgr 元数据库、用户和密码。注意这里的 host 要写本节点自身 IP因为 repmgr 会用它来连接本节点的 PostgreSQL 实例。data_directory必须精确指向数据目录一旦写错repmgr 无法判断节点当前是主还是备。pg_bindir指向 PostgreSQL 二进制目录repmgr 在执行 pg_basebackup、pg_rewind 等操作时需要调用这些命令。replication_user是流复制账号repmgr clone 备库时会用它来拉起 pg_basebackup。use_replication_slotstrue会为备库创建持久复制槽防止 WAL 被提前回收。monitoring_interval2s是 repmgrd 守护进程状态检查的间隔默认是 2 秒生产环境可以保持这个频率。备库 pg-standby 的配置差异只在于node_id102 node_namepg-standby conninfohost192.168.66.102 dbnamerepmgr userrepmgr passwordrepmgr port5432witness 节点类似node_id103node_namepg-witness。4.3 在主库注册 primaryrepmgr 元数据需要一个专门的数据库来存放数据库名就叫 repmgr用户也叫 repmgr。先创建这个用户和库CREATE ROLE repmgr WITH SUPERUSER LOGIN PASSWORD repmgr; CREATE DATABASE repmgr OWNER repmgr;这里我把 repmgr 用户设成超级用户是为了演示方便。生产环境建议按 repmgr 官方文档最小授权来配避免权限扩散。最小授权需要授予连接 repmgr 库、创建 schema、使用表等权限并在多个节点间保持一致。在主库上注册 primarysudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf primary register注册成功后会看到类似输出提示 repmgr schema 和元数据表已创建。此时执行sudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf cluster show预期结果中 pg-main 的角色为primary上游信息为空。4.4 用 repmgr clone 重新构建备库前文我们用 pg_basebackup 手工搭了备库但既然引入了 repmgr我更推荐把备库重新用 repmgr 的 clone 流程构建一次。这样备库的元数据会和主库保持一致避免后续注册时出现 catalog 不一致的问题。在备库 pg-standby 上执行systemctl stop postgresql-15 rm -rf /var/lib/pgsql/15/data然后 clonesudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf standby clone -h 192.168.66.101 -U replicarepmgr 会调用 pg_basebackup 从主库拉取数据并在数据目录中写入 standby.signal 文件。clone 完成后修复权限并启动备库chown -R postgres:postgres /var/lib/pgsql/15/data systemctl start postgresql-15随后把备库注册进集群sudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf standby register这里有个非常关键的坑备库上安装完 PostgreSQL 后不要先执行 initdb否则 data 目录非空repmgr standby clone 会直接报错“target directory exists and is not empty”。我第一次部署时就在这一步卡了半小时最后把目录清空重新 clone 才解决。4.5 witness 注册在 witness 节点 pg-witness 上同样安装 PostgreSQL 15 和 repmgr15。witness 可以运行一个空的 PG 实例用于保存自己的 repmgr 元数据。先初始化并启动/usr/pgsql-15/bin/postgresql-15-setup initdb systemctl start postgresql-15然后创建 repmgr 用户和库再执行 witness 注册sudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf witness register -h 192.168.66.101-h指向当前 primary 的地址repmgr 会连过去获取集群信息并在本地创建 witness 记录。注册完成后再跑一遍 cluster show完整的集群拓扑就出来了角色节点名上游节点连接信息primarypg-main-host192.168.66.101...standbypg-standbypg-mainhost192.168.66.102...witnesspg-witnesspg-mainhost192.168.66.103...看到这个拓扑说明 repmgr 已经完整接管了集群的主备关系。4.6 运维常用命令速查接下来是我自己日常用得最多的几个 repmgr 命令列成表格方便直接参考命令说明repmgr cluster show查看整个集群的角色和连接状态repmgr node status查看当前节点健康和角色信息repmgr standby status查看备库复制延迟和状态repmgr cluster crosscheck检查集群内各节点互相连通性repmgr daemon status查看 repmgrd 守护进程运行情况repmgr node rejoin让故障节点重新加入集群建议把 repmgr 命令的常用别名写到 .bashrc 里省得每次敲全路径。5. 主备切换与 repmgrd 自愈5.1 优雅切换 switchover 实操主备复制搭完如果不演练切换那这套高可用就只是摆设。切换分两类一类是计划内的优雅切换叫做 switchover另一类是主库异常失效时的强制切换叫做 failover。先演示 switchover。它的前提是当前主库健康、复制链路正常、备库已经追平 WAL。在有计划进行机房迁移、软硬件升级、内核参数调整等场景下使用。在备库 pg-standby 上执行或者在任何节点指定切换目标sudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf cluster switchover --upstream-node-id102 --siblings-follow--upstream-node-id102指定要把 pg-standby 提升为新主库--siblings-follow让其他备库自动切换上游到新主库不需要逐个手工改。switchover 的底层流程其实是一个组合动作旧主库 pg-main 先被降级为备库模式进入恢复状态目标节点 pg-standby 结束恢复模式成为读写主库其他备库重新指向 pg-standby。整个过程会有几秒钟的写不可用所以生产环境一定要放在业务低峰期并提前通知业务方。切换完成后再次执行 cluster show应该看到 pg-standby 是 primarypg-main 的 upstream 指向 pg-standby。验证数据同步也很简单在新主库写入一条测试数据再到旧主库查一下是否能查到-- 新主库写入 CREATE TABLE switch_test(id int); INSERT INTO switch_test VALUES (100); -- 旧主库查询 SELECT * FROM switch_test;能查到说明数据链路完整。5.2 强制切换 failover 实操failover 是主库已经无法提供服务时的应急操作。比如我直接停掉主库进程模拟宕机systemctl stop postgresql-15确认主库确实不可用后在备库 pg-standby 上执行提升命令sudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf standby promoterepmgr 会在做强提升前做一系列检查比如确认本节点 LSN 已达到主库的最近位置、没有其他节点也在尝试提升等。提升过程中备库会执行 pg_ctl promote并更新本地元数据把自己的角色标记为 primary。提升后立即验证sudo -u postgres psql -c select pg_is_in_recovery();返回f说明该节点已退出恢复模式现在是可以正常读写的主库。这里必须强调一个生产铁律强制切换只能在确认原主库已经失联或已彻底停止后才做。如果原主库还活着你在备库执行 promote会出现两个主库同时接受写请求的脑裂场景数据会分叉后续找回非常痛苦。5.3 自动故障切换与脑裂预防前面演示的 failover 是手工触发真正的生产环境当然希望主库宕机后系统能自动完成切换。这一步由 repmgr 的守护进程 repmgrd 承担。在三个节点的 repmgr.conf 中加入以下几行failoverautomatic promote_command/usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf standby promote follow_command/usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf standby followfailoverautomatic是开启自动切换的总开关不写这一项repmgrd 即使启动也不会在节点失联时主动 promote。promote_command定义自动提升时实际执行的命令follow_command定义备库自动跟随新主库时执行的命令。启动 repmgrd 守护进程sudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf daemon start在 systemd 环境下也可以用包自带的 service 文件来管理前提是配置好 /etc/default/repmgr15。这里我直接用 daemon start 方式演示更直观。自动切换的工作逻辑大体是这样的repmgrd 每 2 秒由 monitoring_interval 控制通过数据库连接检查上游主库状态。当它连续多次发现主库不可达时会进入候选状态。如果有 witness 节点repmgrd 会请求 witness 也验证主库的可达性综合投票结果后才决定是否提升自己。如果只有自己觉得主库死了但 witness 觉得主库还活着通常说明发生了网络分区这时不会贸然提升避免脑裂。自动切换对人的要求其实更高因为它发生在一个没人值守的时刻。我的建议是自动切换配好之后至少做三次演练分别模拟主库进程被杀、主库所在机器断电、主库网络中断三种场景确保系统行为符合预期。5.4 故障节点重新加入集群无论是 switchover 还是 failover切换之后被降级或掉线的旧主库都需要重新加入集群。以第 5.2 节为例pg-main 被强制切换后成了旧主库修复好进程后把它重新变成 pg-standby 的备库。在旧主库 pg-main 上执行sudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf node rejoin -h 192.168.66.102 --force-rewind-h指向当前新主库--force-rewind使用 pg_rewind 技术从新主库反向同步旧主库的数据分叉部分。pg_rewind 比全量备份快得多它只比对两个节点的 WAL 差异把旧主库里不一致的数据页回滚到新主库的时间线。不过 pg_rewind 有个前提旧主库必须曾经从新主库或新主库的下游复制过数据且 WAL 历史没有断层。如果旧主库离线时间太长或者本来就是手工搭建的独立节点pg_rewind 会失败此时只能重新走一遍 clone 流程sudo -u postgres /usr/pgsql-15/bin/repmgr -f /etc/repmgr/15/repmgr.conf node rejoin -h 192.168.66.102 --force-rewind --force-clone强制 clone 等于放弃旧数据从新主库拉全量物理备份。虽然耗时更长但在旧主库状态不可信时这是最稳妥的做法。生产环境重新加入节点后一定要再看一遍 cluster show确认角色和 upstream 都正确。6. 常见问题与排查技巧实录6.1 常见错误速查表把我在部署和演练过程中遇到的高频问题整理成一张表方便大家直接对照排查现象原因处理方法ERROR: role repmgr does not exist没有创建 repmgr 用户和 repmgr 数据库在主库执行 CREATE ROLE 和 CREATE DATABASEFATAL: no pg_hba.conf entry for replication connectionpg_hba.conf 缺少复制账号允许规则检查是否有host replication规则并确保备库连接来源网段匹配repmgr standby clone: target directory exists and is not empty备库 data 目录已经存在清空或重命名 data 目录后重新 cloneERROR: node pg-main is already registered重复执行 primary register用 cluster show 查看当前注册状态必要时 unregister 后重新注册repmgr: could not connect to serverconninfo 连接串写错、密码不对或网络不通用 psql 按 conninfo 中的参数手工连一次验证repmgrd: unable to connect to upstream node网络分区或主库进程异常检查节点间连通性、主库服务状态必要时切换或 rejoin切换后业务写入失败备库仍处于恢复模式或连接串仍指向旧主库检查 pg_is_in_recovery 返回值更新应用连接配置或 LB 后端pg_rewind: target data directory has not been shut down cleanly旧主库没有安全关闭先正常停止旧主库再执行 rejoin这张表里的前几项基本覆盖了新手部署阶段九成的问题。如果你遇到的报错不在里面我的排查套路是先看 PostgreSQL 日志/var/lib/pgsql/15/data/log/*.csv再看 repmgr 日志/var/log/repmgr/最后检查主备的时间差。日志是最诚实的朋友比猜可靠得多。6.2 几条拿血泪换来的经验第一条时间同步是排障时最先要确认的。repmgr 的元数据里记录了事件发生时间节点之间时钟偏差过大会导致提升判断出现错觉。我遇到过备库明明已经提升但旧主库的日志时间戳反而比它新导致监控系统误判为脑裂的情况。把 chrony 配好所有节点统一走同一时间源这种问题从源头消失。第二条配置文件的 node_id 和 node_name 不要从主库直接复制到备库。有人图省事写完主库配置直接 scp 到备库结果 node_id 重复。repmgr cluster show 输出会显示两个同 id 的节点这种状态非常容易引发误判。复制后必须逐项核对 hosts、node_id、node_name。第三条replication slots 要开但要理解它的代价。开启 use_replication_slots 后如果备库长期离线主库的 WAL 会因为复制槽没有被消费而持续堆积最终把磁盘写满。所以生产环境要配套监控复制状态一旦发现备库追不上或离线及时决定是修复还是重建。第四条应用连接不能把后端地址写死。高可用切换后主库 IP 会变成原本库的 IP如果应用还是连旧 IP即使数据库层切换成功业务也会进不来。我通常的做法是引入一个虚拟 IP 或用负载均衡器切换时把 VIP 漂移或 LB 后端摘掉旧节点加上新节点。repmgr 本身不负责 VIP 漂移这需要结合 keepalived 或者其他机制来做这也是部署时最容易遗漏的一环。第五条自动 failover 不等于万能。repmgr 的 repmgrd 解决的是“主库进程挂了”这种典型故障但如果是主库所在机器发生了诡异的网络错乱、磁盘 IO 卡顿、内核 hang自动切换可能并不会触发因为节点之间还能正常通信。越是复杂的故障越需要靠顶层监控系统兜底。我把 repmgrd 看成高可用体系里的核心执行者但不把它当成唯一决策者。部署这套 PostgreSQL repmgr 主备环境我最大的感受是高可用从来不是一个工具装完就结束的事它是一套需要反复演练、仔细雕琢的流程。repmgr 已经把注册、切换、重归这些动作封装得很成熟了但真正决定系统可靠性的还是操作者对每个参数动机的理解以及对故障场景的执行能力。建议看完这篇文章后先在测试环境把 switchover、failover、自动切换各演练三遍确保集群状态变化都在自己的掌控范围内再考虑上生产。