数据库高可用架构:主从复制、自动故障切换、脑裂防护与 RTO/RPO 工程

数据库挂了,业务就挂了——高可用(HA)的目标是把"数据库不可用"的概率压到最低,并在不可避免的故障发生时自动、快速、无感知地完成切换。但高可用不是"买几台机器做主从"这么简单:主从复制只是基础,真正难的是故障检测(怎么判断主库真挂了)、自动切换(谁能成为新主)、脑裂防护(双主都 …

数据库挂了,业务就挂了——高可用(HA)的目标是把"数据库不可用"的概率压到最低,并在不可避免的故障发生时自动、快速、无感知地完成切换。但高可用不是"买几台机器做主从"这么简单:主从复制只是基础,真正难的是故障检测(怎么判断主库真挂了)、自动切换(谁能成为新主)、脑裂防护(双主都以为自己活着)、数据一致性(切换不能丢数据)。本指南系统梳理数据库高可用的完整工程:复制方案选型、故障检测与切换协议、MHA/Orchestrator/Patroni 等工具、脑裂与防脑裂设计、RTO/RPO 指标量化,以及云原生托管方案的实践。

一、高可用目标与量化

1.1 RTO / RPO 的定义

RPO(Recovery Point Objective):可接受的最大数据丢失量
  · RPO=0  :切换零丢失(需要同步复制/共享存储)
  · RPO<5s :异步复制可接受小丢失
  · RPO=5m :定时备份场景

RTO(Recovery Time Objective):可接受的最大停机时长
  · RTO<30s:自动切换(秒级-分钟级)
  · RTO<5m :脚本化手动切换
  · RTO=1h :依赖重建/备份恢复

目标设定决定架构:
  RPO=0 + RTO=0  → 共享存储 + 集群(昂贵、复杂)
  RPO<1s + RTO<30s → 半同步 + 自动切换(绝大多数业务)
  RPO=5m + RTO=5m → 备份恢复 + 预演(低成本)

ℹ️ 核心洞察:高可用设计的一切取舍,都是 RPO 与 RTO 的平衡——同步复制保 RPO 但牺牲可用性(主从都慢),异步复制保可用性但可能丢数据。先定业务目标,再选架构。

1.2 高可用等级

L0:单实例 + 备份        (宕机 = 停机恢复)
L1:主从异步复制         (故障切换靠人工,可能丢数据)
L2:半同步 + 自动切换     (秒级 RTO,毫秒级 RPO)
L3:强一致复制/分布式     (RPO≈0,需集群协议)
L4:多可用区/多地域       (区域级容灾)

二、复制方案选型

2.1 异步 vs 半同步 vs 同步

方案原理RPO可用性代价
异步主库先提交,binlog 异步送达可能丢几秒无
半同步主库等至少一个从库 ack 才提交≈0(正常)从库慢则主库变慢
同步所有从库 ack 才提交0任一从库慢=全慢
-- MySQL 半同步配置(5.7+ 半同步增强版)
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 3000;  -- 3s 超时降级异步
-- 从库
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;

⚠️ 关键权衡:半同步在"从库 ack 超时"后降级为异步——这保证了主库可用性,但也意味着降级期间可能丢数据。半同步减少风险、不根除风险。

2.2 PostgreSQL 同步/异步

-- PG 同步流复制(synchronous_standby_names)
ALTER SYSTEM SET synchronous_standby_names = '2 (standby1, standby2)';
-- "2" 表示至少 2 个从库确认
-- 无从库确认时主库阻塞(强一致牺牲可用性)

2.3 多从 + 级联拓扑

常见拓扑:
  · 一主一从(最小 HA)
  · 一主多从(读扩展 + 容灾)
  · 一主一备一从(备=切换目标,从=读)
  · 级联(从库再挂从库,节省主库 binlog 负担)
  · 主从主(环形,慎用,容易脑裂)

建议:
  · 切换目标建议选"半同步从库"(数据最新)
  · 一个从库专门做报表/备份(可延迟同步)

三、故障检测:怎么判断"主库挂了"

3.1 检测维度

故障检测信号:
  · 网络层:ping / TCP 探活
  · 协议层:SELECT 1 / SHOW STATUS(主库进程活着但挂起?)
  · 应用层:写请求持续失败
  · 复制层:从库与主库失去心跳

判断原则:
  · 不能只看"一次探活失败"就切换(误判)
  · 需连续 N 次失败 / 超时窗口确认
  · 多个观察者(如 Orchestrator 三节点)多数派判定
  → 避免"单点误判触发灾难性切换"

3.2 探活与心跳

# heartbeat_probe.py — 连续失败判定故障
FAIL_THRESHOLD = 3
WINDOW = 5  # seconds

def detect_master_failure(probe):
    failures = 0
    while True:
        if probe.ok():
            failures = 0
        else:
            failures += 1
            if failures >= FAIL_THRESHOLD:
                return True      # 连续 3 次失败 → 判定故障
        time.sleep(WINDOW / FAIL_THRESHOLD)

四、自动切换的核心问题

4.1 切换流程

完整故障切换:
  1. 故障检测(多数派确认主库不可用)
  2. 选举新主(选择数据最新的从库)
  3. 提升新主(激活写入)
  4. 重定向流量(VIP / DNS / 应用配置)
  5. 其余从库 re-point 到新主
  6. 通知 / 记录 / 复盘

每步都可能出问题,HA 工具就是把这些自动化 + 加防护

4.2 脑裂(Split-Brain)问题

脑裂场景:
  · 主库与工具/观察者网络断开,但主库进程还活着
  · 观察者判定主库死亡 → 提升从库为新主
  · 旧主恢复网络 → 两个"主库"同时在写 → 数据分叉

防脑裂手段:
  · 多数派仲裁(quorum):切换需大多数节点同意
  · STONITH(fencing):确认旧主无法再写(杀进程/断网)
  · 独立仲裁节点(如 ZooKeeper/etcd/Orchestrator 多节点)
  · 心跳隔离(旧主被隔离时才允许新主接管)

⚠️ 核心原则:宁可停机,不可脑裂。双主分叉比短暂不可用严重得多——它让数据无法合并、后续全部基于错误基线。防脑裂的第一道防线是"fencing":提升新主前确保旧主真的不能再写。

4.3 数据一致性检查(切换前)

切换前评估各从库数据位置:
  · 对比各从库 binlog 位点/GTID
  · 选"最新"的从库作为新主(丢失最小)
  · 记录切换时点(供事后对账)
  · 若差异过大,考虑阻止切换(人工决策)

五、MySQL HA 工具:MHA 与 Orchestrator

5.1 MHA(经典方案)

MHA(Master High Availability):
  · 检测主库故障
  · 找出数据最新的从库
  · 补齐其余从库的 binlog 差距
  · 提升新主 + 重配置其他从库
  · 切换通常 30s-1min

局限:
  · 无内置多数派/仲裁(单 Manager 单点)
  · 维护已放缓,社区转向 Orchestrator
# mha.conf 关键配置
[server default]
manager_log=/var/log/masterha/manager.log
master_binlog_dir=/var/lib/mysql
user=root
password=***
manager_workdir=/var/log/masterha

[server1]
hostname=db-master
[server2]
hostname=db-standby
[server3]
hostname=db-read-1

5.2 Orchestrator(Raft 仲裁 + 拓扑管理)

Orchestrator 特性:
  · 拓扑可视化(发现/接管/拖挂)
  · 自动故障检测 + 恢复(Raft 多数派仲裁)
  · 优雅切换(手动/计划)
  · 防脑裂:三节点 Raft 集群,只有多数派可切换
  · 可探测 MySQL 从属关系(GTID)

更适合现代 MySQL HA:
  · 三节点 Orchestrator + 半同步从库
  · RTO 通常 <30s
# orchestrator CLI 常见命令
orchestrator -c topology -i db-master          # 查看拓扑
orchestrator -c discover -i db-master
orchestrator -c graceful-master-takeover -i db-master   # 计划切换
orchestrator -c recover -i db-master           # 手动恢复

5.3 MySQL Group Replication / InnoDB Cluster

MySQL InnoDB Cluster(官方 HA):
  · Group Replication:Paxos 协议,多数派写入
  · MySQL Router:自动路由读写
  · 单主 + 多读;自动故障转移(秒级)
  · RPO≈0(组复制多数派确认)

适用:新部署 / 对官方方案友好 / 接受组复制约束

六、PostgreSQL HA:Patroni 与 Repmgr

6.1 Patroni(Kubernetes 时代主流)

Patroni = PG 高可用控制器 + 分布式共识(etcd/ZooKeeper/Consul)
  · leader 选举:当前主库持有 lease
  · 故障:多数派认可后 promote 备库
  · 自动配置同步/动态参数
  · 与 K8s Operator 深度集成(CloudNativePG/Zalando)

配置要点:
  · 每个 PG 实例跑 Patroni
  · 共享 etcd 集群做决策源
  · synchronous_mode 可选(RPO=0)
# patroni.yml
scope: postgres-ha
namespace: /pg/
name: pg-0
restapi:
  listen: 0.0.0.0:8008
  connect_address: pg-0:8008
etcd:
  hosts: [etcd-0:2379, etcd-1:2379, etcd-2:2379]
bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    postgresql:
      use_pg_rewind: true          # 旧主回归用 rewind 对齐
      use_slots: true
      parameters:
        synchronous_mode: "off"    # 或 on 换取 RPO=0
postgresql:
  listen: 0.0.0.0:5432
  data_dir: /var/lib/postgresql/data

6.2 Repmgr

Repmgr(轻量 PG HA):
  · 监控复制 + 故障检测
  · failover 自动/手动
  · 无外部依赖(较 Patroni 简单)
  · 防脑裂:repmgr 用 witness 节点仲裁(可选)
适用:简单集群,不想引入 etcd

七、读写分离 + VIP 与流量切换

7.1 VIP 漂移

VIP(虚拟 IP)+ keepalived:
  · 主库持有 VIP
  · 切换时 VIP 漂移到新主
  · 应用连 VIP,无感知

缺点:
  · 单子网内可用,跨 AZ/跨机房需 DNS/负载均衡
  · keepalived 本身需防脑裂配置(VRRP 优先 + 主从约束)

7.2 连接层切换

现代方案:
  · MySQL Router(InnoDB Cluster 官方)
  · ProxySQL(读写分离 + 故障路由)
  · DNS + TTL(切 DNS 有缓存延迟)
  · 应用连接池 + 探活重连
  → 建议:ProxySQL/Router 负责"切换对应用透明"
# proxysql.cnf — 主从分组 + 故障切换
mysql_replication_hostgroups = 0,1
mysql_servers:
  hostname=db-master  port=3306 hostgroup=0      # 写组
  hostname=db-standby port=3306 hostgroup=1      # 读组
mysql_monitor:
  monitor_username=monitor
  monitor_password=***
  monitor_ping_interval=5000
# 主库故障 → ProxySQL 自动把写组切到 standby

八、云原生与托管 HA

8.1 云数据库(AWS/Azure/GCP/阿里云)

托管数据库自带 HA:
  · 自动故障切换(RDS Multi-AZ、Aurora)
  · 多 AZ 部署、自动备份 + PITR
  · RTO 通常 1-2 分钟(托管 SLA)
  · 无需自建 MHA/Orchestrator

优点:省运维、SLA 保障、跨 AZ 容灾
注意:切换行为由云厂商定义(不透明窗口),需验证

8.2 K8s 上的数据库

· Zalando Postgres Operator / CloudNativePG(PG on K8s)
· KubeBlocks(多数据库统一 Operator)
· Vitess(MySQL 分布式 + K8s 原生)
→ 把 HA 变成"声明式配置",自动恢复 + 滚动切换

九、演练与验证

9.1 故障演练

必须演练的场景:
  · 主库进程挂掉(kill -9)
  · 主库网络断开(防火墙规则)
  · 主库所在节点宕机(整机)
  · 半同步从库全部失效(降级路径)
  · 仲裁节点故障(etcd/Orchestrator 部分可用)
  · 脑裂模拟(旧主恢复网络)

演练验证:
  · RTO 是否达标(记录切换耗时)
  · RPO 是否可接受(对比切换后数据)
  · 应用是否自动重连(连接池/Proxy 行为)
  · 监控告警是否准确

9.2 监控指标

# HA 健康指标
master_role_current{instance}         # 谁是当前主库
replica_seconds_behind_master         # 从库延迟
semi_sync_status                      # 半同步是否生效
ha_failover_total                     # 切换次数
ha_last_failover_duration             # 最近切换耗时
# 告警:从库延迟超阈值、半同步降级、仲裁不可用

9.3 常见坑速查

坑后果对策
单 Manager 无仲裁误判切换Orchestrator Raft
无 fencing脑裂双写STONITH/隔离
全异步切换丢数据半同步 + 记录位点
未演练切换时才暴露问题定期故障演练
VIP 跨网段切换失败用连接层路由
从库数据旧被提升大量丢数选最新从库 + 对账

总结:数据库 HA 决策表

环节关键动作
目标先定 RTO/RPO,再选架构
复制半同步优先(RPO≈0 且可用性可接受)
检测连续探活失败 + 多数派仲裁
切换选最新从库 + fencing 防脑裂
工具MySQL: Orchestrator;PG: Patroni
路由VIP / ProxySQL / Router 透明切换
演练定期故障演练验证 RTO/RPO
演进托管/K8s Operator 省运维

数据库高可用的本质,是把"主库挂了"从事故变成例行流程——检测、选举、提升、隔离、重定向,全部自动化并加上脑裂防护。它不是你买来的某个工具,而是"目标(RTO/RPO)→ 复制方案 → 检测 → 切换协议 → 防脑裂 → 流量切换 → 演练验证"的一整套工程闭环。落地守住四件事:半同步减少丢失、多数派仲裁防误判、fencing 防脑裂、演练验证 RTO/RPO。把 HA 当作产品来运营(有指标、有演练、有复盘),数据库才能真正成为业务的"可靠底座"而非"最大风险源"。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「database」更多文章

  1. 数据库安全加固与审计实战:权限最小化、加密、脱敏与合规
  2. 数据库容量规划与资源治理:从评估、监控到扩展路径
  3. 数据库字符集、排序规则与乱码实战:utf8mb4、Collation 选择与排查