ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PostgreSQL高可用实战:repmgr+keepalived实现主从切换与VIP漂移

PostgreSQL高可用实战:repmgr+keepalived实现主从切换与VIP漂移 1. 为什么是PostgreSQL repmgr keepalived这套组合PostgreSQL 的高可用方案数来数去就那几类Patroni 全家桶、Pgpool-II 读写分离集群、repmgr 主从复制再就是云厂商托管。我在生产环境里实际跑过 PG 的复制架构最常推荐给同事的还是 repmgr keepalived 这个组合。它不复杂依赖少出了问题也容易讲清楚很适合绝大多数从单机 PG 往高可用方向升级的业务。repmgr 解决的问题是PostgreSQL 节点之间的复制关系怎么管理它把主库、备库组织成一个集群负责 standby 的克隆、注册、监控以及主库故障时把某个备库提升为新的主库。keepalived 解决的问题更简单粗暴用一个虚拟 IPVIP对外提供固定入口哪台机器是主库VIP 就漂到哪台机器上应用不用改连接串。两者一配合数据库层面由 repmgr 决定谁是主网络层面由 keepalived 决定流量进谁家中间再用脚本把两件事串起来一套高可用集群就活了。这套方案适合谁来用我认为是这几类场景业务库量级在单机性能内、但又忍受不了单点故障的团队从 PostgreSQL 单实例迁移到高可用架构的运维同学以及不想引入 etcd、consul 这类分布式协调组件、希望一切都在 PostgreSQL 生态内闭环的项目。至于已经有了成熟容器平台、或者对自动切换要求极高的核心交易系统那可能 Patroni 更合适但那是另一种复杂度后面可以单独聊。1.1 三者的分工复制、切换、漂IP各管一段先把职责边界划清楚后面配置才不会乱。PostgreSQL 自身负责数据层的基础复制能力也就是 WAL 日志流复制。主库产生 WAL备库通过网络实时接收并回放这是 repmgr 的底层依赖。你完全可以用手写 pg_basebackup recovery.conf 的方式搭主从但那样没有切换管理、没有状态监控、没有节点注册表故障时要靠人去判断和执行命令那不叫高可用叫有备库。repmgr 在这层之上加了一个集群认知每个节点都有唯一的 node_id、node_name元数据存在一个 repmgr 数据库里。它知道谁是 primary、谁是 standby当你执行 repmgr standby promote它会把选中的备库切成新的主库并自动把其他 standby 重新指向新主库。它还支持 event notification可以在主库故障时触发各种外围动作这是做自动化切换的基础。keepalived 则完全工作在 TCP/IP 层。它跑的是 VRRP 协议多个节点抢同一个虚拟 IP优先级高的节点成为 VIP 的持有者。数据库本身健康不健康keepalived 并不知道所以要靠外面的探活脚本告诉它我这台机器上的 PG 还活着吗。这就是三件套里最需要自己写代码的部分也是这套方案最容易出幺蛾子的地方。1.2 这套方案的边界能抗住哪些抗不住哪些我一般会在开工前就跟业务方把丑话说在前头。repmgr keepalived 能抗住的故障是主库机器宕机、PG 进程崩溃、主库网络失联这个需要配合仲裁机制看情况。在这些场景下备库能在几十秒内接管服务VIP 漂移过去应用只要配置了连接重试基本无感。抗不住的场景也要说清楚。第一磁盘满导致数据库全部只读这种故障切换了也没用因为备库大概率也满第二数据损坏或误操作比如 truncate 一个大表复制流会把坏操作同步到备库切换过去一样是坏数据这类问题要靠备份和 PITR 解决第三脑裂和数据争抢纯用 keepalived repmgr 在没有第三方仲裁的情况下其实是有限制的我后面专门讲脑裂怎么防。把这个边界想清楚后面的设计和演练才有意义。2. 环境规划架构图上没写出来的关键点很多教程上来就给命令但实际部署高可用集群最先卡住的往往不是命令而是环境规划。IP 怎么分、hostname 怎么配、防火墙放不放行、参数是不是一致这些不弄清楚后面 repmgr clone 的时候一堆莫名其妙的报错等着你。2.1 节点规划与VIP分配我按最常用的方案来讲一台主库、一台备库这是能支撑业务的最小集合。条件允许的话我强烈建议再加一台 witness 节点它不存业务数据只跑 repmgr 的元数据服务和仲裁逻辑部署成本很低但能把脑裂误判的概率降一个档次。我的规划习惯如下假设网段是 192.168.10.0/24节点IP用途repmgr node_idkeepalived prioritypg-primary192.168.10.11主库初始 primary1150pg-standby192.168.10.12备库初始 standby2100pg-witness192.168.10.13witness仲裁用3不参与 VIPVIP192.168.10.200应用连接入口--hostname 我建议就叫 pg-primary、pg-standby、pg-witness并在每台机器的 /etc/hosts 里固定好。为什么repmgr 的 conninfo 里可以用 IP但我强烈建议用主机名。切换后 follow 和 reconnect 流程依赖节点身份识别主机名稳定比 IP 稳定更重要IP 变了改 hosts 就行不用动 repmgr 配置。还有一个细节VIP 尽量预留一个固定 IP不要参与 DHCP 分配。否则 DHCP 把同一个地址分给别的机器keepalived 启动时就会跟人冲突表面看是 keepalived 报错实际是地址被占。2.2 安装前的系统层准备系统层面我在 Rocky Linux 9 和 Ubuntu 22.04 上都部署过这里以 Rocky Linux 为例细节对 CentOS 7 也通用。首先把三台机器的时间同步好。主从复制对时钟误差不是特别敏感但 repmgr 的事件记录、日志排查都依赖时间线一致我的习惯是用 chrony 统一指向内网 NTP 服务器开机自启。然后是 hosts 解析和三台机器的网络连通性。repmgr 执行 standby clone 时本质是通过 pg_basebackup 从主库拉数据走的是 PostgreSQL 的复制协议所以不一定需要 SSH 互信。但 repmgr 5.x 的一些场景比如 switchover会用到远程命令我通常还是会把 postgres 用户的 SSH 密钥互信配好省得演练切换时还要输密码。防火墙只放必要端口PostgreSQL 的 5432、keepalived 的 VRRP 通告多播 224.0.0.18、协议号 112。如果用 firewalld大致是这样firewall-cmd --permanent --add-servicepostgresql firewall-cmd --permanent --add-rich-rulerule protocol valuevrrp accept firewall-cmd --reload如果你像我一样被 SELinux 折腾过记得在装上 PostgreSQL 后检查一下getenforce如果是 Enforcing要么把 PG 数据目录的上下文配好要么先临时设成 Permissive 跑通流程再收紧。我踩过一次 SELinux 导致 keepalived 脚本里调 pg_isready 权限不足的坑后面踩坑部分细说。2.3 PostgreSQL 参数核对这些不改复制起不来很多人以为 repmgr 装上就能用其实 repmgr 对 PostgreSQL 的参数有硬性要求。以 PG 14 为例postgresql.conf 里这几项必须改wal_level replica max_wal_senders 10 max_replication_slots 10 hot_standby on archive_mode on archive_command test ! -f /backup/pg_archive/%f cp %p /backup/pg_archive/%f wal_keep_size 512 shared_preload_libraries repmgr简单解释一下wal_level 决定主库能不能产生复制所需的 WAL 信息max_wal_senders 和 max_replication_slots 提供并发复制通道hot_standby 让备库能提供只读查询archive_mode 看起来不是必需项但 repmgr 的 clone 过程依赖 pg_basebackup归档打开能让新备库在追 WAL 时更从容同时也留了一条 PITR 的后路。shared_preload_libraries 加 repmgr 必须重启 PG 进程才会生效repmgr 的监控函数 repmgr.get_primary() 就靠这个库提供。这里提醒一句主备两台机器的 PG 参数最好完全一致别主库开了归档、备库没开后续做 switchover 时新主库会拿着一套残缺参数上生产。另外archive_command 里引用的 /backup/pg_archive 目录要提前创建好并让 postgres 用户有写权限否则数据库一启动就报归档错误。3. 从零到主从repmgr搭建的真实命令行过程环境准备好以后就可以开始装数据库和 repmgr 了。这一节我直接用命令走一遍完整流程照着做基本能跑通。安装方式上我建议用官方 PGDG 仓库的二进制包比自己源码编译省事得多。如果在内网离线环境就把 rpm 包和依赖拷到本机用 yum localinstall 装上效果一样。3.1 PostgreSQL 基础安装与版本选择PostgreSQL 版本方面我在生产上目前偏好 14 和 16。14 生态最成熟repmgr 5.3 支持得最好16 新特性多repmgr 需要用 5.4 及以上否则会有版本兼容警告。如果你对版本选择没把握保守做法是PG 14 repmgr 5.3 keepalived 2.2.x这套组合我在多套环境里验证过兼容问题最少。安装命令Rocky 9使用 PGDG 仓库dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm dnf install -y postgresql14-server postgresql14-contribrepmgr 也要装对应 PG 大版本的包否则扩展和 PG 版本不匹配后面会直接报错dnf install -y repmgr14装完以后先别急着初始化和启动。repmgr 要求扩展库在 PG 的 lib 路径下通常装 repmgr14 会自动放到正确位置。但如果你是自己下载源码编译的 repmgr一定要确认它和当前 PG 主版本一致。我见过有人在 PostgreSQL 14 下装了 repmgr13 的包register 的时候直接报 repmgr extension is not available排查半天发现是版本对不上。3.2 初始化数据目录与 repmgr 基础配置主库上初始化并启动 PG/usr/pgsql-14/bin/postgresql-14-setup initdb systemctl enable --now postgresql-14然后切到 postgres 用户创建 repmgr 专用的数据库用户和数据库sudo -u postgres createuser -P repmgr sudo -u postgres createdb -O repmgr repmgrrepmgr 用户不需要超级权限但复制角色是必须的。在 pg_hba.conf 里把主备和 witness 网段都加上host replication repmgr 192.168.10.0/24 md5 host all repmgr 192.168.10.0/24 md5 host all all 192.168.10.0/24 md5注意第三行是为了应用连接和 repmgr 管理连接都走同网段如果生产环境有独立应用网段按实际情况收窄别学我图省事开整段。接着在主库写 repmgr 配置文件。我的习惯是放在 /etc/repmgr/14/repmgr.conf内容如下node_id1 node_namepg-primary conninfohostpg-primary userrepmgr dbnamerepmgr port5432 connect_timeout2 data_directory/var/lib/pgsql/14/data failovermanual promote_command/usr/pgsql-14/bin/repmgr standby promote -f /etc/repmgr/14/repmgr.conf follow_command/usr/pgsql-14/bin/repmgr standby follow -f /etc/repmgr/14/repmgr.conf log_file/var/log/repmgr/repmgr.log log_levelINFO这里最关键的三个字段node_id 必须全局唯一node_name 要和 hosts 里的主机名对应conninfo 是 repmgr 用来连接本节点 PG 的连接串。promote_command 是当 repmgr 决定把当前节点提升为主库时执行的命令follow_command 是备库在新主库确定后重新指向新主的命令。这两个命令填错自动切换就是摆设。failover 我故意写成 manual。如果你沿用我后面介绍的 keepalived 脚本驱动方式切换动作应该由脚本显式触发保持 manual 可以避免 repmgrd 和脚本两头抢着提升主库。如果将来想交给 repmgrd 自动接管再改成 automatic 并配置 event notification。配置好以后把主库注册到 repmgrsudo -u postgres /usr/pgsql-14/bin/repmgr -f /etc/repmgr/14/repmgr.conf primary register如果没问题你会看到类似 successfully registered node 1 (pg-primary) 的输出。这里提醒一句注册之前一定要确保 shared_preload_libraries 已经包含 repmgr 并重启过否则 register 会卡在权限或函数缺失的报错上而且这类报错往往不太直观。3.3 备库克隆三行命令从零拉到主从备库上的 PG 数据目录一开始是空的repmgr 会通过 pg_basebackup 从主库把整个数据目录克隆过来。克隆前先在备库装好同一个 PostgreSQL 和 repmgr 包然后写好 repmgr.conf注意 node_id 和 node_name 要换成备库自己的node_id2 node_namepg-standby conninfohostpg-standby userrepmgr dbnamerepmgr port5432 connect_timeout2 data_directory/var/lib/pgsql/14/data克隆之前先执行 --dry-run 检查环境这一步能提前暴露绝大多数问题sudo -u postgres /usr/pgsql-14/bin/repmgr -h pg-primary -U repmgr -d repmgr \ -f /etc/repmgr/14/repmgr.conf standby clone --dry-run如果提示连接失败先回头查 pg_hba.conf 和防火墙不要急着往下走。dry-run 通过后去掉 --dry-run 执行真正的克隆sudo -u postgres /usr/pgsql-14/bin/repmgr -h pg-primary -U repmgr -d repmgr \ -f /etc/repmgr/14/repmgr.conf standby clone克隆完成后备库数据目录里会自动生成 standby.signalPG 12 之后的做法说明它已经是一个只读备库。启动备库 PG然后注册备用节点systemctl start postgresql-14 sudo -u postgres /usr/pgsql-14/bin/repmgr -f /etc/repmgr/14/repmgr.conf standby register查看整个集群的状态sudo -u postgres /usr/pgsql-14/bin/repmgr -f /etc/repmgr/14/repmgr.conf cluster show正常输出会显示 ID2 的节点Role 是 standbyWAL 接收状态正常。看到这个主从复制算是搭成功了。3.4 验证复制状态的几个常用命令集群状态正常只是第一步我习惯再补几项验证。第一主库上查复制槽SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots;repmgr 会自动创建类似 repmgr_slot_2 的复制槽active 应该是 true。第二备库上验证只读查询同步sudo -u postgres psql -c select now();跟主库时间对比正常情况下差异在秒级以内。第三确认 repmgr 元数据没有分歧sudo -u postgres /usr/pgsql-14/bin/repmgr -f /etc/repmgr/14/repmgr.conf cluster status这里多嘴一句不要只看 cluster show 里绿色的 ok 就放心。lag 那一列单位是字节有时候备库追不上也不会立刻标红最好结合 pg_replication_slots 的 restart_lsn 和当前 WAL 位置做趋势判断我后面巡检建议里会说怎么做。4. keepalived整合把切换从手动变成自动repmgr 负责把备库提升为主库但应用不会自己找到新的主库所以需要 keepalived 的 VIP 来完成入口切换。这一章是整套方案里最需要自己写逻辑的地方也是踩坑最多的地方。4.1 VIP 漂移配置三台机器都安装 keepaliveddnf install -y keepalivedkeepalived 的配置文件是 /etc/keepalived/keepalived.conf。主库的 priority 要高备库低witness 不参与 VIP。我的主库配置如下global_defs { router_id pg_ha } vrrp_instance PG_HA { state MASTER interface ens192 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass pg_ha_2024 } virtual_ipaddress { 192.168.10.200/24 dev ens192 label ens192:0 } notify_master /etc/keepalived/notify.sh master notify_backup /etc/keepalived/notify.sh backup notify_fault /etc/keepalived/notify.sh fault }备库配置基本相同只是 state 改 BACKUP、priority 改成 100。注意 VRRP 的 auth_pass 只是简单的明文校验不是安全机制别把它的重要性想太高真正需要注意的是同一组 keepalived 节点的 virtual_router_id 必须一致否则它们各玩各的VIP 会同时出现在多台机器上。interface 要指定正确的网卡名查一下ip addr别照抄我的 ens192。VIP 可以绑定在物理网卡上也可以像这样用 label 建一个虚拟子接口实际使用中我更推荐 label 方式方便排查时一眼看出哪块 IP 是 VIP。4.2 探活脚本keepalived 和 repmgr 之间的桥梁keepalived 默认只认 VRRP 心跳它不会主动检查 PostgreSQL 是否还活着。我的做法是每台节点上放一个周期性检查脚本由 keepalived 的 vrrp_script 调用脚本里结合 pg_isready 和 repmgr 的状态决定是否把本节点的 keepalived 停下来。vrrp_script 定义大概是这样vrrp_script check_pg { script /usr/local/bin/check_pg.sh interval 2 weight -20 fall 2 rise 2 }然后把它挂到 vrrp_instance 里track_script { check_pg }check_pg.sh 的核心逻辑我按主库挂了就自动停 keepalived备库尾随接管的思路写。下面是一个简化但能跑通的版本#!/bin/bash VIP192.168.10.200 PG_BIN/usr/pgsql-14/bin # 本机 PG 进程异常先尝试拉起一次失败则踢掉 keepalived if /usr/pgsql-14/bin/pg_isready -q -h 127.0.0.1 -p 5432; then : else systemctl restart postgresql-14 sleep 3 if ! /usr/pgsql-14/bin/pg_isready -q -h 127.0.0.1 -p 5432; then systemctl stop keepalived exit 1 fi fi # 判断本机是不是备库pg_is_in_recovery() 返回 t 说明当前是只读备库 ROLE$(sudo -u postgres /usr/pgsql-14/bin/psql -Atqc select pg_is_in_recovery()) if [ $ROLE t ]; then # 备库联系不上主库才考虑提升 if ! timeout 5 bash -c /dev/tcp/pg-primary/5432 2/dev/null; then sudo -u postgres /usr/pgsql-14/bin/repmgr -f /etc/repmgr/14/repmgr.conf standby promote exit 0 fi fi exit 0这段脚本有两个设计决策值得解释。第一主库故障时我不提倡直接在脚本里 promote更稳妥的是检测到本地 PG 死掉就停掉本地 keepalived让 VIP 漂到备库然后由 notify_master 回调在备库成为 MASTER 后执行 promote。上面这个简化版为了控制篇幅在备库场景直接执行了 promote但完整方案里我强烈建议把 promote 放到 notify_master 回调里通过事件驱动来做减少误杀概率。第二备库主动执行 promote 前必须加仲裁条件。那个/dev/tcp/pg-primary/5432探测本质是确认主库端口是否可达。如果主库只是网络抖动实际还活着且能写备库一 promote两个主库同时写数据的问题就出现了。所以这个脚本一定要配合 witness 节点做二次确认生产版本里我还加了 pid 锁和状态标记避免重复执行 promote。这里的简化版只为演示逻辑别直接搬上生产。4.3 脑裂风险与仲裁设计脑裂是这类 keepalived 数据库脚本方案里最需要警惕的问题。keepalived 基于 VRRP 的优先级抢占当主备之间网络不通它们互相认为对方死了各自都可能把 VIP 抢起来应用流量就会被切到两个主库上数据写重了后面就是灾难。我降低脑裂风险会从三个层面做。第一层是充分依赖 keepalived 自身的心跳机制advert_int 设 1 秒、failure 阈值设小让 VIP 抢占有优先级和延迟的区分第二层是探活脚本里的判断多条件化比如备库要 promote必须满足主库 IP 完全不可达 witness 节点仲裁同意两个条件才允许否则保持观望第三层是切换动作要收口把 repmgr 的 failover 设成 manual让切换操作完全掌握在 keepalived 脚本手里避免 repmgrd 和脚本两头抢着提升主库。witness 节点在这里就能发挥作用了。它是一台不存业务数据、只运行 repmgr 元数据的节点配置很简单装好 PG 和 repmgr在 repmgr.conf 里写好 node_id、node_name、conninfo然后注册为 witnesssudo -u postgres /usr/pgsql-14/bin/repmgr -f /etc/repmgr/14/repmgr.conf witness register -h pg-primary不同版本文本略有差异先跑 --dry-run 确认。注册之后witness 会持续记录它能看到的主库心跳。当备库联系不上主库、但 witness 也确认主库失联时才认为主库真的出问题。我在生产环境里见到的绝大多数伪故障比如主库网络抖动、进程 hang 住但还能写都是靠这一层仲裁拦下来的。5. 故障演练实录主库宕机之后发生了什么配置写得再漂亮不演练等于白配置。高可用系统的价值不是看平时正不正常而是看故障那一刻能不能自己兜住。我在部署完这套集群后一定会拉着业务方做至少三轮演练一轮手动切换、一轮自动故障转移、一轮原主库回归集群。5.1 手动切换演练先让胆小的同事练手手动切换是 repmgr 的 switchover 功能它的好处是优雅先把目标备库追平到最新 WAL再做角色切换基本不丢数据。执行前先看集群状态sudo -u postgres /usr/pgsql-14/bin/repmgr -f /etc/repmgr/14/repmgr.conf cluster show确认两个节点状态正常、WAL 追平以后在备库节点上执行 switchoversudo -u postgres /usr/pgsql-14/bin/repmgr -f /etc/repmgr/14/repmgr.conf standby switchoverrepmgr 会做一系列检查当前主库是否可达、目标备库是否处于 follow 状态、候选节点是不是最新。检查通过后它会自动完成 promote并尝试让其他备库跟随新主库。切换完成后有一个必须做的动作VIP 同步对调。因为 keepalived 里主库 priority 150、备库 100switchover 只改数据库角色keepalived 的角色不会自动变。如果不处理VIP 还停在原主库上而原主库已经降级成备库应用的写操作直接报错。我第一次做演练就漏过这一步业务方当场发现连接串指向的机器已经不是主库了。所以 notify 脚本最好能感知 repmgr 角色变化自动调整 keepalived 的 priority这一步省不了。5.2 自动故障转移实测kill 掉主库主进程自动转移的演练最简单直接在主库上pkill -9 postgres让一个真故障发生然后观察备库和 VIP 的反应。按我设计的脚本流程事件顺序是这样的主库 PG 进程死掉后主库上的 check_pg.sh 在连续探测失败后停止本机 keepalived主库从 VRRP 竞争中退出备库收到主库心跳丢失加上 witness 仲裁确认主库不可达开始执行 repmgr standby promote提升成功后备库的 notify_master 回调把 VIP 绑定到本机同时更新 keepalived priority整个切换在几秒到十几秒之间完成应用侧只要配了重连逻辑体验就是一次短暂的连接中断。这里有个容易被忽略的点自动转移后新主库上的 repmgr 状态要重新确认。promote 之后repmgr 会把新主库注册为 primary旧主库被标记为 failed 或 unreachable这是预期内的。等旧主库修好后再拉回来。演练之后别急着收工我建议顺手检查三件事新主库能否正常写入、旧主库的 WAL 有没有积压、VIP 是否只出现在新主库一张网卡上。尤其第三件事用ip addr | grep 192.168.10.200在每台机器上查一遍确保没有出现两个节点同时持有 VIP 的情况。5.3 旧主库重新加入集群旧主库修好以后不能直接 start 了事。它现在是一个曾经的主库数据时间线已经和集群分离直接启动会跟新主库抢 WAL 且时间线不一致。标准做法是把旧主库降级成一个全新的备库重新通过 repmgr clone。步骤很清晰。第一步停掉旧主库的 PG 服务第二步确认它不会再被 keepalived 拉起来先停 keepalived第三步清理旧数据目录后用 repmgr standby clone 从新主库重新拉一份数据第四步standby register 注册第五步恢复 keepalived让 priority 重新参与 VIP 竞争。systemctl stop postgresql-14 systemctl stop keepalived rm -rf /var/lib/pgsql/14/data/* sudo -u postgres /usr/pgsql-14/bin/repmgr -h pg-standby -U repmgr -d repmgr \ -f /etc/repmgr/14/repmgr.conf standby clone systemctl start postgresql-14 sudo -u postgres /usr/pgsql-14/bin/repmgr -f /etc/repmgr/14/repmgr.conf standby register systemctl start keepalived我特别强调一下 rm -rf 那一步。如果你不确定旧数据目录里有什么先 tar 备份再删别学网上某些教程直接删。旧主库的数据在故障切换那一刻可能已经落后新主库好几个事务留着反而是隐患——你并不需要它来恢复业务你需要的是让节点以全新备库身份回到集群。6. 运维落地踩坑记录、巡检清单与最后的碎碎念主流程跑通以后还有一件更重要的事把它养好。生产环境和实验室最大的区别就是会在各种奇怪的地方踩坑。我在多套集群上摸爬滚打挑几个典型的写下来希望能帮你省掉排查时间。6.1 实战踩坑这些问题我基本都遇到过第一个坑是 repmgr 版本和 PG 版本不匹配。有一次我在 PG 14 环境里用 repmgr 5.2register 时一切正常但 standby clone 时冒出一个含糊的 repmgr does not support this PostgreSQL version 错误折腾很久才发现是 repmgr 版本太旧。后来我固定了选型PG 14 配 repmgr 5.3PG 16 配 repmgr 5.4每次组合先用 dry-run 验证过再上生产。第二个坑是 keepalived 的 weight 设计。我一开始把 check_pg 脚本的 weight 设成 -100觉得权重降得越低越好结果主库 PG 恢复后脚本检测正常但 keepalived 的 priority 已经降得太低VIP 在备库上回不来了。后来我改成 weight 与 priority 差值留出余量并且 rise 阈值设成 2 次成功才算恢复避免抖动。第三个坑是 SELinux 拦截脚本。keepalived 调用的 check_pg.sh 如果放在 /etc/keepalived 下SELinux 可能把它当有问题的脚本上下文处理导致脚本里连 pg_isready 都执行不了但日志只显示 keepalived_script failed非常迷惑。解决方法是把脚本放到 /usr/local/bin然后刷新 SELinux 上下文或者直接restorecon -R -v /usr/local/bin。第四个坑是归档目录膨胀。archive_modeon 加上 archive_command 指向本机磁盘平时看不出问题时间长了归档堆积把备份盘写满导致 WAL 无法归档、主库产生积压。这个不是 repmgr 的问题是高可用方案的连带隐患。我后来在巡检脚本里加了归档目录使用率检查超过阈值就告警。6.2 日常巡检清单照着做能省掉半夜电话最后给出一份我日常巡检用的检查清单不用多每天一次脚本化跑一遍即可。检查项命令/方法期望结果repmgr 集群状态repmgr cluster show所有节点 role 正确status 为 ok复制延迟psql 查 pg_stat_replicationreplay_lag 小于 10 秒复制槽状态pg_replication_slots无失效 slotactive 正常VIP 绑定ip addrVIP 只出现在当前主库keepalived 日志journalctl -u keepalived无频繁状态切换记录归档目录空间du -sh /backup/pg_archive使用率低于 80%时间同步chronyc tracking系统时间误差小于 100ms数据库连通pg_isready -h VIP返回 accepting connections这些检查项不用都做成复杂监控能定期跑、异常时能报警就够。更关键的其实是切换演练的频率——我建议每个季度至少做一次完整的自动故障转移演练。高可用系统是平时越安静、故障时越考验人的东西脚本里任何一个逻辑变更都可能让下次真实故障变成事故。最后再分享一个我个人的体会repmgr keepalived 这套架构配置只是半天的事真正的成本在演练和运维习惯。把 5.2 的 kill -9 演练流程完整走一遍业务侧对这套系统的信任度比看十篇方案文档都管用。
返回列表