--- tags: [MySQL, MHA, Orchestrator, 高可用, 故障切换, MySQL HA] create time: 2026-05-16 14:30 --- # MHA / Orchestrator 故障切换 ## 概述 当主库宕机时,如何**快速且正确**地选出一个新的主库并完成流量切换?这就是高可用(HA)系统的核心问题——既要尽量减少停机时间,又要保证数据不丢失、不发生冲突。 本节将对比两种主流的 MySQL 自动故障切换方案: - **MHA**:由日本 DeNA 开发的经典 Perl 方案,以数据一致性著称 - **Orchestrator**:由 Spotify 开发的现代 Go 工具,侧重拓扑管理和运维便利 > [!QUESTION] 核心思考 > 在讨论具体工具之前,先问一个问题:**如果只有一个从库,它应该立刻提升为主库吗?** > > 答案并不简单。如果主库只是短暂的网络抖动,切换就是"过度响应";但如果主库真的挂了还不切,服务就不可用了。如何在「反应太快」和「反应太慢」之间找到平衡,是 HA 设计的永恒命题。 ## 故障场景分类 ```mermaid flowchart TD A["主库异常"] --> Type{"异常类型"} Type -->|"进程挂死"<| H1["检测快
切换快
可自动处理"] Type -->|"磁盘损坏"<| H2["数据可能损坏
需人工介入"] Type -->|"脑裂 Split-Brain"<| H3["最危险!
双主写入导致数据冲突"] Type -->|"网络分区"<| H4["隔离误判
假阳性切换"] style H3 fill:#EE5A24,color:#fff ``` > [!NOTE] 关键认知 > HA 工具能自动处理的大多是**进程级故障**。一旦发生磁盘损坏或网络脑裂,就需要人工判断——这也是为什么理解底层原理比单纯部署工具更重要。 ## MHA(Master High Availability) 由日本 DeNA 开发(2009年)的经典 MySQL HA 方案,以 Perl 编写。其核心设计思想是**「绝不丢失已提交的数据」**——在故障切换前,会尽力补齐最从库缺失的 binlog 事件。 ```mermaid sequenceDiagram participant M as MHA Manager participant DM as Dead Master participant MS as Most Up-to-Date Slave participant SS as Other Slaves M->>DM: ping... no response Note over M: 连续 3 次 ping 失败 M->>MS: SHOW MASTER STATUS MS-->>M: relay log 最新的位置 M->>SS: SHOW RELAYLOG STATUS SS-->>M: relay log 较旧的位置 Note over M: Step 1: 补齐最从库的 missing events M->>MS: 应用其他 slave 的 relay log 中的缺失事件 Note over M: Step 2: 提升新主 M->>MS: CHANGE MASTER TO... (无 master) Note over MS: 脱离子复制链,成为独立主库 Note over M: Step 3: 重新配置其他从库指向新主 M->>SS: CHANGE MASTER TO master=new-master-ip Note over SS: 全部切换到新主 ``` ### MHA 的核心优势 | 特性 | 说明 | |------|------| | **数据一致性保证** | 选择 relay log 最新的 slave 作为新主 | | **自动补齐** | 从其他 slave 获取 dead master 尚未传的 binlog | | **VIP 漂移** | 通过 Keepalived + VIP 实现无缝切换 | | **Phantom Manager** | Manager 节点本身也可以做数据管理 | > [!TIP] 为什么选「最从」而非「任意从」? > > 假设 Master → SlaveA → SlaveB 的级联复制结构: > - Master 挂了,SlaveA 可能比 SlaveB 更「新」 > - 如果直接提升 SlaveB,需要等待它追完所有relay log,延时长且风险大 > - MHA 的做法是:找到 relay log 最全的那个从库,确保数据丢失最小 ### MHA 组成 MHA 采用 **Manager + Node** 的分布式架构: ``` Manager Node ← 运行 mha_manager,独立部署(不放在 MySQL 节点上) Master Node ← 当前主库(可挂,不影响 Node 组件) Slaves Nodes ← 多个从库(自动检测哪个最新) App Servers ← 应用端通过 VIP 访问 ``` > [!NOTE] 部署建议 > - Manager 应部署在**独立的第三方机器**上,不要和任何 MySQL 实例同机 > - 所有节点之间必须配置 **SSH 互信**,Manager 需要通过 SSH 执行远程操作 #### 安装与配置 ```bash # 安装 RPM 包(CentOS/RHEL 7+) yum install mha4mysql-manager mha4mysql-node -y ``` ```bash # 配置文件 /etc/masterha/app1.cnf [server default] manager_workdir=/data/mha/app1 manager_log=/data/mha/app1/manager.log user=mha_user # Manager 连接 MySQL 的管理账号 password=mha_pass ssh_user=root # SSH 连接账号 repl_user=repl_user # 主从复制账号 repl_password=repl_pass [server1] hostname=10.0.1.10 candidate_master=1 # 允许被提升为主库 [server2] hostname=10.0.1.11 candidate_master=1 [server3] hostname=10.0.1.12 no_master=1 # 永远不做主库(例如数据量特别大的从库) ``` > [!TIP] candidate_master 的作用 > > 默认情况下,MHA 优先选择 relay log 最新的从库,而不看它离 Master 的距离。但如果一个从库是「级联」链路末端(Master → S1 → S2),即使 S2 的 relay log 最全,也不应该提升它——因为它一旦变主,其他从库要重新追很长的 binlog。 > > `candidate_master=1` 可以告诉 MHA:**这个节点虽然可能不是 relay log 最完整的,但仍然有资格被提升**。配合 `report_script` 还可以加入更多判断逻辑。 #### GTID 支持 MHA 0.56+ 版本开始支持 GTID 模式下的故障切换: ```ini # app1.cnf 中开启 GTID 模式 [server default] master_binlog_dir=/var/lib/mysql remote_workdir=/tmp/mha use_gtid_current_pos=1 # 使用 GTID 定位复制位置 ``` > [!NOTE] GTID vs Position 的选择 > > | 方式 | 优点 | 缺点 | > |------|------|------| > | binlog position | 兼容所有 MySQL 版本 | 需要精确计算每个 slave 丢失的事件 | > | GTID current_pos | 简化了定位逻辑,切换更可靠 | 要求 MySQL 5.6+,且需提前开启 GTID | 如果生产环境已启用 GTID,强烈建议使用 GTID 模式;否则保持默认的 binlog position 即可。 ### MHA 的局限 > [!WARNING] MHA 的问题 > 1. **Manager 单点**:虽然可以配 Phantom,但需要一个额外的管理入口 > 2. **Perl 技术栈**:生态维护活跃度下降 > 3. **不支持 GTID 之前**:GTID 出现前依赖 binlog position > 4. **脑裂风险**:如果 Master 只是网络闪断而非真宕机,可能出现双主 > > **替代方案**:Orchestrator + Go-HAProxy 或 Patroni(PostgreSQL 方向) ## Orchestrator 由 Spotify 开源的纯 Go 编写的 MySQL 拓扑发现和运维工具。核心定位是**「MySQL 拓扑的管理员」**——它首先帮你搞清楚「现在整个集群是什么样的」,然后在此基础上提供故障切换、手动切换、修复落后从库等操作。 ```mermaid flowchart TB subgraph "Orchestrator 架构" OAPI["Orchestrator HTTP API
port 3000"] ODB["SQLite/MySQL
存储拓扑信息"] OSCAN["Discovery Scan
定期 SHOW SLAVE HOSTS"] frontend["Web UI
拓扑可视化"] --> OAPI dashboard["Dashboard"] --> OAPI OSCAN --> ODB OAPI --> ODB HAProxy["Go-HAProxy /
MaxScale / ProxySQL"] -->|"重定向流量"| NEWMASTER["新主库"] end OAPI --> HAProxy ``` > [!NOTE] 设计理念差异 > > | 维度 | MHA | Orchestrator | > |------|-----|-------------| > | 首要目标 | 自动故障切换(Failover) | 拓扑管理 + 运维辅助 | > | 侵入性 | 需要在每个节点安装 node 组件 | **零侵入**,只读查询 | > | 执行方式 | Manager 直接 SSH 操作各节点 | 通过 API 调用,外部脚本接管 | > | 技术栈 | Perl | Go(单二进制文件部署) | ### Orchestrator 如何工作 Orchestrator 的核心是一个**后台扫描循环**: ``` 每 5~30 秒 ──┬──► SHOW SLAVE HOSTS / SHOW REPLICA STATUS ├──► 读取各实例的 Binlog Position ├──► 构建完整拓扑树(含级联复制关系) └──► 写入内部数据库 → Web UI 刷新显示 ``` 这意味着 Orchestrator **不主动修改任何 MySQL 配置**,它只是一个观察者 + 操作台。所有的故障切换需要外部工具(如 Go-HAProxy)配合完成。 ### 自动故障切换(Auto-Failover) 虽然 Orchestrator 以拓扑管理见长,但它同样支持全自动故障切换: ```ini # orchestrator.conf.json 关键配置 { "DiscoverByShowSlaveHosts": true, "DetectMasterFailoverWithSuperReadOnly": false, "DetectorScript": "/usr/local/bin/orchestrator-detector.sh", // 自动 Failover 的条件控制 "AutoFaildown": true, // Master 恢复后是否自动降级并重新纳入复制链 "AutoFailop": true, // Master 宕机时是否自动切换 "ExpireStatsSec": 600 // 统计信息过期时间 // 选择新主的策略 "PreferredCandidateDistances": [1, 2], // 优先选距离近的从库 "CheckSlaveLagThreadsCached": true // 自动检测 Slave 延迟 } ``` > [!QUESTION] Orchestrator 为什么不直接改 VIP? > > MHA 内置了 VIP 漂移功能,但 Orchestrator 选择了更松耦合的设计。原因是: > 1. 不同环境使用不同的代理层(HAProxy / ProxySQL / MaxScale / 云厂商 LB) > 2. 让外部系统决定「怎么切流量」更加灵活 > 3. Orchestrator 专注于做一件事:**准确知道拓扑结构并给出操作建议** > > 生产环境中常见的做法是写一个 wrapper 脚本,当 Orchestrator 检测到 Master 挂掉时自动调用它来切换 ProxySQL 或 HAProxy 的后端配置。 ### 常用 API 示例 ```bash # 1. 查看某个应用下的所有实例拓扑 curl http://localhost:3000/api/topology/app/mydb # 2. 找到最适合晋升为主库的候选者 curl http://localhost:3000/api/candidate-instances/app/mydb # 3. 强制提升某实例为主库(手动干预) curl -X POST http://localhost:3000/api/become-master/host/db/instance # 4. 自动修复脱离的从库(重新对接到新主) curl -X POST http://localhost:3000/api/recover/full/host/db/instance # 5. 获取故障切换分析(不实际执行,只看推荐方案) curl http://localhost:3000/api/fail-coordination/force/master-simulate/host/db/instance ``` > [!TIP] Simulate 模式 > > `fail-coordination` 接口支持模拟切换流程而不真正执行。在生产环境中强烈建议先用这个命令**演练一次**,确认推荐的切换方案符合预期后再正式执行。 ## 脑裂的处理 ```mermaid flowchart TD A["网络分区导致
Master 与 Slave 失联"] --> B{"HA 工具判断
Master 存活?"} B -->|否| C["提升 Slave 为新主"] C --> D{"原 Master 恢复后
是否还活着?"} D -->|是| E["⚠️ 双主!两个库都在接受写请求"] E --> F["用 binlog 比对
找出冲突数据"] F --> G["回滚冲突数据
或将原 Master 降级为从库"] D -->|否| H["原 Master 重启后
作为从库接入"] B -->|是| I["不做切换,继续等待"] style E fill:#EE5A24,color:#fff style H fill:#00D866,color:#fff ``` ### 脑裂后的数据恢复步骤 当确认发生脑裂时,标准处理流程如下: ``` Step 1 ──► 停止新主的写入(防止更多冲突) Step 2 ──► 导出两个库的 GTID 集合或 binlog position 范围 Step 3 ──► 使用 mysqlbinlog + diff 对比差异事件 Step 4 ──► 保留「正确」分支的数据 Step 5 ──► 将另一方的冲突数据标记为 rollback 或直接丢弃 Step 6 ──► 重建复制链路 ``` > [!WARNING] 预防脑裂的策略 > 1. **STONITH(Shoot The Other Node In The Head)**:通过 IPMI / 远程管理卡强制关闭疑似脑裂节点——这是最彻底的方案 > 2. **Quorum(多数派机制)**:3 节点集群中,至少 2 节点存活才允许选举,避免少数派擅自决策 > 3. **带外心跳**:除了 TCP ping,再用 SSH 或其他独立通道探测,降低单通道误判概率 > 4. **延迟备份**:保留一台物理隔离的冷备,脑裂时可从中恢复,相当于最后的保险丝 > 5. **超时阈值调优**:不要为了减少误切把超时设得太长(如超过 30s),故障期间每一秒都很宝贵 ## 选型建议 ```mermaid flowchart LR A["需要 MySQL HA
自动故障切换"] --> B{"技术栈偏好?"} B -->|"传统运维体系
已有 Perl 团队"| MHA["MHA
经典稳定"] B -->|"Go / 云原生
需要 Web UI"| ORC["Orchestrator
灵活现代"] B -->|"想要官方支持"<| INN["InnoDB Cluster
MySQL Shell"] B -->|"不想自己维护 HA"| CLOUD["云厂商 RDS
托管方案"] style MHA fill:#4A90D9,color:#fff style ORC fill:#00D866,color:#fff style INN fill:#F5A623,color:#fff style CLOUD fill:#EE5A24,color:#fff ``` ### 关键对比维度 | 维度 | MHA | Orchestrator | InnoDB Cluster | |------|-----|-------------|---------------| | **数据丢失** | 极小(自动补齐 binlog) | 较小(依赖 GTID) | 零(基于 Group Replication) | | **部署复杂度** | 中(需 SSH 互信 + RPM) | 低(单二进制文件) | 高(需 PXC/Galera) | | **故障恢复时间** | 通常 < 10s | 通常 < 15s | 秒级但检测较慢 | | **在线扩展** | 不支持 | 仅拓扑管理,不处理 DDL | 支持分布式 DDL | | **社区活跃度** | 较低(DeNA 维护) | 高(VK / 社区活跃) | 官方维护 | | **适用 MySQL 版本** | 5.6~5.7 | 5.6+(推荐 8.0) | 8.0+ | > [!TIP] 实际生产中的常见选择 > > - **中小团队(< 10 台 MySQL 实例)**:Orchestrator 是性价比最高的选择——上手简单、维护成本低、Web UI 对 DBA 友好 > - **大流量业务对数据一致性要求极高**:如果预算允许,上云厂商 RDS 的付费高可用版是最省心的 > - **自建全量多主写入**:考虑 InnoDB Group Replication 或 ProxySQL + Orchestrator 组合 ## 关联笔记 - [[hhs/MySQL/07-高可用与分布式/30-主从复制详解]] — 主从复制的配置和监控 - [[hhs/MySQL/07-高可用与分布式/32-Group Replication]] — 内置多主复制,不需要外部 HA 工具 - [[hhs/Redis/06-主从与哨兵]] — Redis Sentinel 与 MySQL HA 方案的对比