故障切换

主库故障、从库故障时的检测机制与切换流程详解。

Pigsty 的高可用系统支持两种切换模式:自动故障转移(Failover)和 主动切换(Switchover)。


故障检测

故障检测由 Patroni 和 Etcd 共同完成:

  1. 心跳机制:集群领导者(主库)持有 Etcd 租约,需要定期续期
  2. 租约超时:如果领导者在 TTL 时间内(默认 30s)未续期,租约释放
  3. 健康检查:HAProxy 通过 Patroni REST API 检测实例状态

检测时间线

0s      主库故障发生
        ↓
~10s    Etcd 租约即将过期,Patroni 最后一次心跳失败
        ↓
~15s    租约过期,领导者锁释放
        ↓
~20s    从库 Patroni 检测到领导者空缺,开始竞选
        ↓
~25s    新领导者当选,从库提升为主库
        ↓
~30s    HAProxy 检测到角色变化,流量切换完成

自动故障转移(Failover)

当主库因硬件故障、网络分区或进程崩溃而不可用时,系统自动执行故障转移。

流程详解

  1. 故障发生

    • 主库 Patroni 进程崩溃或网络不可达
    • Etcd 租约停止续期
  2. 领导者选举

    • 租约过期后,所有候选从库开始竞争领导者锁
    • 选举依据:数据完整性(LSN 位点最高者优先)
    • 如果 LSN 差距超过 pg_rpo 阈值,拒绝自动切换
  3. 主库提升

    • 胜选从库执行 pg_ctl promote 提升为主库
    • 其他从库重新配置,指向新主库
  4. 流量切换

    • Patroni REST API 返回新的角色信息
    • HAProxy 将写流量路由到新主库

对业务的影响

  • 写服务:不可用 15s ~ 30s,期间写请求失败或阻塞
  • 读服务:短暂闪断后恢复,从库继续提供只读服务

主动切换(Switchover)

在计划维护、滚动升级等场景下,可以主动将主库角色转移到指定从库。

执行方式

# 使用 patronictl 执行切换
patronictl -c /pg/bin/patroni.yml switchover

# 或使用 Pigsty 封装的命令
pg switchover <cluster>

流程详解

  1. 发起切换

    • 管理员通过 patronictl 或 API 发起 switchover 请求
    • 指定目标从库(可选)
  2. 优雅降级

    • 当前主库停止接受新的写入
    • 等待所有进行中的事务完成
    • 等待从库追上复制位点
  3. 角色交换

    • 原主库降级为从库
    • 目标从库提升为新主库
  4. 流量切换

    • HAProxy 检测角色变化,更新路由

对业务的影响

  • 写服务:短暂闪断(通常 < 5s)
  • 读服务:几乎无感知

从库故障

从库故障的处理相对简单:

  1. HAProxy 检测:健康检查失败,将从库从后端池移除
  2. 流量转移:只读请求路由到其他健康从库
  3. 降级处理:如果所有从库都故障,只读流量由主库承担

对业务的影响

  • 写服务:无影响
  • 读服务:正在该从库上执行的查询中断,后续请求自动路由到其他节点

脑裂防护

脑裂是分布式系统最危险的场景:网络分区导致出现多个主库。

Pigsty 的防护机制

  1. DCS 仲裁:领导者锁由 Etcd 集群统一管理,网络分区时只有能访问多数派的节点才能持有锁

  2. Failsafe 模式:Patroni 默认启用 failsafe_mode,当无法联系 DCS 时,主库降级为只读

  3. 看门狗(可选):启用硬件看门狗后,失去 DCS 联系的主库会被强制重启

    patroni_watchdog_mode: automatic  # 或 required
    
  4. VIP 漂移:vip-manager 从 Etcd 获取领导者信息,只有真正的主库才能绑定 VIP


故障恢复

原主库恢复

当故障的原主库重新上线时:

  1. 角色降级:原主库发现已有新领导者,自动降级为从库
  2. 数据同步:如果数据差异在 pg_rpo 范围内,使用 pg_rewind 快速同步
  3. 重新加入:作为从库重新加入集群

手动干预场景

以下情况可能需要人工干预:

  • 数据差异超过 pg_rpo 阈值
  • 时间线分叉严重
  • 需要从备份恢复数据
# 查看集群状态
patronictl -c /pg/bin/patroni.yml list

# 手动重新初始化成员
patronictl -c /pg/bin/patroni.yml reinit <cluster> <member>

最佳实践

  1. 至少三节点:生产环境建议 1 主 2 从,确保故障切换有足够候选

  2. 跨机架/机房部署:避免单点故障影响整个集群

  3. 监控告警:配置复制延迟、连接数等告警

  4. 定期演练:通过 switchover 验证故障切换流程

  5. 备份策略:HA 不能替代备份,配合 PITR 应对逻辑错误