HG_REPMGR自动故障转移实践:PostgreSQL高可用切换与VIP漂移
发布时间:2026/10/8 9:28:09 作者:尧图编辑部 阅读量:1,286

数据库高可用这件事做过的人都清楚主备架构只是第一步真正麻烦的是“切换”。以前主库一宕机值班 DBA 要登录备库确认延迟、检查时间线、执行 promote熟练工跑完全套动作也得五分钟起步业务早就投诉了。所以我一直在找能自动化替换这一套人工流程的方案。后来我在瀚高数据库HighGo生产环境里用上了 HG_REPMGR 的自动故障转移功能也就是 autofailover主库一旦确认不可用备库会自动提升配合 VIP 漂移业务中断时间从“分钟级”降到“几十秒级”。这篇文章适合正在选型高可用方案、或对 PostgreSQL 系自动切换感兴趣的运维和 DBA我会把架构、配置、常见坑一次讲透。1. HG_REPMGR 自动故障转移的整体架构与选型思路1.1 HG_REPMGR 的定位与实际价值HG_REPMGR 是瀚高数据库团队在复制管理组件基础上做的二次开发专门用于 PostgreSQL 系数据库的主备复制管理和故障切换。和原生态工具相比它针对 HighGo 的运行习惯做了不少适配比如监控连接方式、命令交互逻辑、日志格式等但核心操作思路仍然遵循 repmgr 的成熟模式。简单说它的定位就是数据库高可用里的“自动挡”你只需要把主从节点搭好它负责监控主库健康、维护备库状态、在主库异常时自动选出新主库。我在生产环境里实际感受到的价值有三点一是故障发现真的快常规监控系统通常每分钟拉一次指标repmgrd 按秒级做连接探活感知问题的粒度完全不同二是切换动作标准化不会因为值班人手生疏或者半夜精神紧张漏掉归档确认、忘了改 VIP三是整个过程可回溯每次切换事件都会写入集群日志事后审计、复盘都方便。这三点看着简单但都是我踩过坑之后才真正认同的不是看文档得出的结论。1.2 自动故障转移的四个核心组件一套能自动切换的 HG_REPMGR 环境至少要有四个角色主库primary、备库standby、见证节点witness、守护进程repmgrd。主库对外提供读写服务备库持续接收并重放 WALwitness 不存业务数据但参与仲裁投票repmgrd 负责在每台节点上常驻运行并执行切换动作。角色职责是否承载业务数据primary对外提供读写服务生成 WAL是standby接收并重放 WAL随时准备提升是但只读witness仲裁网络分区防止脑裂否repmgrd监控状态、决策、执行切换命令否这里必须强调一下witness 不是可有可无的。两节点环境下备库检测不到主库时它无法区分“主库死了”和“备库自己被网络隔离了”如果直接提升恢复网络后很容易出现两个主库分叉。加一个 witness 节点备库提升前会先和 witness 通信相当于多了一个公正的裁判。生产环境如果条件允许我建议不要省这个节点。1.3 自动切换比手动切换强在哪手动切换的不可靠不在于命令难写而在于执行流程因人而异。同样一次主库宕机有经验的 DBA 会先看pg_stat_replication确认备库延迟、检查时间线是否一致新手可能直接pg_ctl promote结果把事务丢了一地。HG_REPMGR 的自动切换把这一串动作固化成了判断逻辑所有节点执行同一套规则从机制上减少主观判断带来的偏差。但自动切换不等于“完全不用管”。它只是把切换动作自动化了决策参数和外部依赖还需要运维提前设计好比如 VIP 漂移脚本、应用连接池刷新、回退策略。我之前遇到过一次误切换原因是网络抖动触发了备库提升虽然业务很快恢复但数据一致性检查花了大半天。后来调大了重试窗口、加了 query 级别的探活才把误判率压下去。这个案例我放到后面常见问题里细说。1.4 多数派机制如何防脑裂自动切换最怕的不是切不了而是切出双主。想象一个灾备场景两个机房网络断开备库监测不到主库但它所在的机房还有业务流量它会不会把自己提升如果没有仲裁机制它大概率会。等网络恢复后两边都接受写入复制关系和业务数据彻底分叉这个局面比宕机更难受。HG_REPMGR 的防线是“多数派机制”。备库在决定提升前必须确认自己能联系到仲裁集合里的多数节点通常是它自己加 witness。如果备库连不上主库但能连上 witness说明主库侧故障成立允许提升如果备库连 witness 也连不上说明自己处于网络孤岛禁止提升。这套逻辑覆盖了最常见的主库宕机和网络分区场景实际使用下来防脑裂效果非常稳。2. 从零搭建部署 HG_REPMGR 的完整操作步骤2.1 三节点规划与 SSH 互通准备我先给一个标准的三节点规划这是比较稳妥的最小高可用集主库 hgdb-p01 使用 192.168.56.11备库 hgdb-s01 使用 192.168.56.12见证节点 hgdb-w01 使用 192.168.56.13。操作系统用 CentOS 7.9数据库版本是 HighGo Database 6.x数据目录放在/data/hgdb。HG_REPMGR 安装后命令在/usr/bin/repmgr系统包一般会一起带过来不需要额外配置环境变量。三台机器之间必须配置 SSH 免密因为 HG_REPMGR 在克隆备库、执行 pg_rewind、rejoin 等操作时需要远程执行命令。生成 SSH 密钥后把各节点的公钥都放进对端~/.ssh/authorized_keys。这里建议使用专门的 repmgr 系统账号不要用 root 跑管理命令否则后面日志文件归属、脚本权限都会很别扭。2.2 数据库参数和 repmgr 账号准备在所有数据节点上都要调整postgresql.conf。我常用的基线配置是wal_level replica max_wal_senders 10 max_replication_slots 10 wal_keep_size 1GB archive_mode on archive_command cp %p /backup/archive/%f这里有几个关键点。wal_level如果低于replica备库根本拿不到 WAL复制直接不成立。max_wal_senders要根据备库数量和外部同步连接数放大两节点加 witness 的时候开 10 个基本够用。archive_mode我建议一定打开否则旧主库回归时pg_rewind可能找不到足够的 WAL 来追平时间线后面就只剩下删数据重新克隆一条路了。然后创建 repmgr 账号和数据库CREATE USER repmgr WITH SUPERUSER LOGIN REPLICATION PASSWORD your_password; CREATE DATABASE repmgr OWNER repmgr;为什么要用超级用户因为 repmgrd 需要执行pg_promote()、pg_rewind这类高权限操作。如果安全要求严格可以限制这个账号只能从特定网段登录并在pg_hba.conf里把来源 IP 收紧不要开放到公网。2.3 repmgr.conf 参数逐项说明三台节点使用同一套配置模板只是节点标识和连接串不同。下面是我经常用的主库配置node_id1 node_namehgdb-p01 conninfohost192.168.56.11 port5432 userrepmgr dbnamerepmgr connect_timeout5 data_directory/data/hgdb failoverautomatic promote_commandrepmgr standby promote -f /etc/repmgr.conf --log-level DEBUG follow_commandrepmgr standby follow -f /etc/repmgr.conf monitor_interval_secs5 connection_check_typeping reconnect_attempts3 reconnect_interval10 log_levelINFO log_file/var/log/repmgr/repmgrd.log备库节点只需改node_id、node_name和conninfo里的 host 为 192.168.56.12。witness 节点没有业务数据目录配置里不需要data_directory但要显式加一行node_typewitness。三个核心参数要特别解释。failoverautomatic是自动切换的总开关注册完了没改这个值repmgrd 只会告警不会动作。monitor_interval_secs决定探活频率我改成 5 秒既能快速感知故障又不会因为高频探测产生一堆无效连接。connection_check_type有 ping 和 query 两种模式ping 只做连接层检查query 会执行SELECT 1确认数据库真正能响应可靠性更高代价是每个周期多一条 SQL。2.4 从注册主库到启动守护进程搭建顺序是固定的别跳步。先在主库执行repmgr -f /etc/repmgr.conf primary register这条命令会把主库节点信息写入 repmgr 元数据库并创建监控相关辅助对象。然后到备库执行克隆repmgr -f /etc/repmgr.conf standby clone -h 192.168.56.11 -U repmgr -d repmgr克隆相当于把主库数据完整的复制到备库同时自动建立复制关系。完成后在备库注册repmgr -f /etc/repmgr.conf standby register最后在备库和主库上分别启动守护进程repmgr -f /etc/repmgr.conf daemon start启动后用repmgr cluster show查看状态。正常情况下输出里应该有两个节点一个是 primary一个是 standby且 standby 后面有Standby following指向主库。如果这里状态不对先别忙着继续调参把注册和连接关系重新核一遍否则后面所有自动切换都是空的。3. 自动故障转移的探活、选举与切换细节3.1 repmgrd 的探活机制与两种模式repmgrd 的探活不是简单的ping IP而是通过 libpq 建立真实的数据库连接。在connection_check_typeping模式下它执行PQping本质是完成 TCP 握手和协议启动包交换在query模式下它会进一步执行SELECT 1并等待返回结果。两种模式对应不同的故障感知粒度生产环境我更推荐 query虽然多一次 SQL但能区分“主机活着但数据库卡死”和“主机直接宕机”。每次探活失败后节点并不会立刻切换而是记录一次失败进入 degraded 状态。后续按照reconnect_attempts参数重试只有当连续失败达到阈值才正式宣布主库不可用。这个“确认窗口”非常重要它用来消化网络微抖和服务器瞬时负载也是防止误切换的第一道闸门。3.2 备库选举与多数派判定多个备库并存时谁有资格成为新主库HG_REPMGR 会结合备库的 WAL 接收进度和节点 ID 来选。同机房场景下复制进度最接近主库的备库会被优先选出因为它包含事务最全丢数据的风险最小。如果进度一致则倾向于选择节点 ID 更小或者配置里优先级更高的节点。整个过程自动完成不需要人工参与但前提是候选备库必须通过多数派仲裁。如果你生产环境只部署了两节点我建议至少补上一个 witness形成三节点仲裁。两节点时备库检测不到主库根本不敢做判断三节点时即使出现网络分区也总有一侧能通过仲裁胜出。这个成本很低却能把自动切换的可靠性提高一个量级。3.3 一次真实故障切换的时间线我用自己环境里一次真实的 kill 主库演练来说明。在主库上执行kill -9 postmaster_pid后盯着备库日志和监控时间线大致是这样的第 0~5 秒repmgrd 的探活请求超时日志出现connection to primary failed的 NOTICE。第 5~20 秒进入重试窗口每隔 10 秒重试连续 3 次失败确认主库不可达。第 20 秒左右备库触发本地提升执行pg_ctl promote数据库开始把 WAL 尾部 apply 完并移除只读限制。第 25 秒左右备库以 primary 身份对外提供读写repmgr 元数据库更新节点角色。第 30 秒左右配置了 VIP 漂移脚本的话虚拟 IP 会切到新主库业务连接开始恢复。整套流程下来业务中断时间在 30 秒上下。如果想压到 10 秒以内可以把reconnect_attempts降到 1、reconnect_interval降到 3但误判风险会同步升高。这个取舍没有标准答案只能结合业务容忍度来定。3.4 让应用自动连上新主库VIP 漂移数据库完成了 promote只是“数据库内部”的新主应用要真正用上还需要一层外部连接入口。我在生产里常用的方案是虚拟 IP 加 keepalivedVIP 始终指向当前主库。切换发生时promote_command 除了让数据库提升还会触发 VIP 漂移脚本把地址从旧主库移到新主库。对应的配置是promote_commandrepmgr standby promote -f /etc/repmgr.conf --log-level DEBUG /usr/local/bin/vip_move.sh这里有个容易坑人的地方脚本必须写幂等。如果只是简单执行ip addr add重复运行可能报“地址已存在”的错误。我现在的脚本会先检查 VIP 是否已经落在本机如果在就跳过不在才执行添加和 arping 广播保证无论 promote_command 被触发多少次都不会把网络搞乱。3.5 监控参数与切换速度的平衡我把常用的参数组合分成两套方便你按业务需求选择。稳健模式monitor_interval_secs10reconnect_attempts5reconnect_interval15connection_check_typequery。适合网络环境一般、业务能容忍一两次短暂抖动的场景。快速模式monitor_interval_secs3reconnect_attempts1reconnect_interval5connection_check_typeping。适合 RTO 要求高、机房内部网络可靠的场景。不管选哪种log_file路径都要提前创建好目录权限要给 repmgr 用户写。我遇到过因为/var/log/repmgr权限不对repmgrd 起不来排查了半天才发现是目录属主问题。这些细节不致命但会消耗你宝贵的故障处理时间。4. 切换不执行、误切换、连不上高频问题排查实录4.1 切换不执行先查这五个点repmgrd 明明在跑主库也真的挂了但备库就是不动这是我被问最多的问题。按概率从高到低排序原因通常有五个failover没设为automatic这是配置阶段最容易漏掉的。备库上的 repmgrd 没启动或者启动后被系统杀掉了。conninfo里写死了错误的节点地址导致探活打到了一个无关机器。repmgr 元数据库中备库节点没完成注册repmgrd 不知道它有提升资格。日志被 logrotate 切了repmgrd 因为权限问题突然退出。排查路径很简单先ps aux | grep repmgrd再跑repmgr cluster show最后tail -n 100 /var/log/repmgr/repmgrd.log。按这个顺序走五分钟内能定位到绝大多数问题。4.2 频繁误切换的调参思路自动切换做过头了比不切换更麻烦。我处理过一次典型误切换机房高峰时段主库 CPU 被打满监控连接大量超时备库连续失败达到阈值后自动提升。实际上主库还在正常服务业务只是没来得及响应探活。这次切换的连锁反应是应用连接全部中断VIP 重新收敛事后还要对比数据一致性搞得大家都很累。我的建议是三管齐下。第一connection_check_type改成query用真实 SQL 返回结果判断数据库是否存活第二reconnect_attempts提到 3 以上让系统容忍短时资源争抢第三优先排查网络抖动如果交换机丢包频繁再短的参数都救不了。把误切换阈值适当调大短期看 RTO 变高了长期看稳定性反而更好。4.3 切换后应用连不上一步步定位这种问题八成出在数据库外部。先确认新主库是否已经可写psql -h 192.168.56.12 -U repmgr -d repmgr -c select pg_is_in_recovery();如果返回f说明数据库侧已经提升成功。接下来看 VIP 有没有漂移用ip addr show检查业务地址是否落在新主库。如果 VIP 还挂在旧主库上手动执行预先准备的漂移脚本再检查应用连接池是否刷新了后端节点列表。很多数据库中间件会缓存节点信息必要时需要通过管理接口刷新或重启连接池。还有一个容易被忽略的坑旧主库虽然宕机但客户端网络缓存里可能还残留旧地址的 ARP 信息。切换后立刻在另一台机器上ping VIP或telnet VIP port验证一下不要让业务告警替你做这个测试。4.4 旧主库回归不要直接启动切换完成后旧主库处于分叉状态绝对不能直接启动。我见过有同事把旧主库拉起来然后主库备库互相抢占连接日志刷得满天飞。正确流程是先把旧主库的数据库服务停掉然后用 rejoin 把它并回集群repmgr -f /etc/repmgr.conf node rejoin -h 192.168.56.12 -U repmgr -d repmgr --force-rewind这条命令会优先用pg_rewind把旧主库时间线回退到新主库让其作为备库重新追随。前提是archive_mode打开且有足够 WAL 可以追平。如果pg_rewind失败说明差距太大最稳妥的方案是清空数据目录重新standby clone。虽然耗时长但至少不会产生数据逻辑错误。回归后记得重新注册备库节点并再次确认cluster show里所有节点都是 active。我习惯在 rejoin 后手动检查复制延迟是否归零避免后续业务读到了旧数据。4.5 一张排查清单覆盖四个层面我现在处理 HG_REPMGR 相关故障基本按这张清单来顺序不能乱先看所有节点 repmgrd 进程是否正常存活。再看repmgr cluster show输出确认角色和状态。检查主备节点pg_stat_replication确认 walsender 和 walreceiver 是否配对。翻/var/log/repmgr/repmgrd.log搜索WARNING、ERROR、NOTICE关键行。确认业务虚拟 IP 落在哪个节点。最后检查应用连接池有没有拿到最新主库地址。这套流程覆盖了检测、仲裁、数据复制、连接入口四个层面基本能把问题圈定在一个很小的范围。别一上来就重启服务先看日志和状态90% 的故障其实在日志里都有答案。最后再唠叨一句。HG_REPMGR 的自动故障转移不是装完就万事大吉它只是一个把“故障切换”固化成自动流程的框架真正决定业务恢复速度的还是你平时有没有把 VIP 漂移脚本、应用连接池刷新、旧主库回归这些环节反复演练。我自己的习惯是每个季度做一次真实的 kill 主库演练并且故意制造一次网络分区看看仲裁表现。前两次肯定会有意外但演练暴露出来的问题恰恰是生产环境早晚要踩的坑。趁业务还能容忍你折腾的时候多折腾几回比真到了凌晨三点被电话叫起来强得多。