Skip to content

MySQL 高可用与容灾

复制是高可用的基础组件,但复制本身不等于高可用。完整方案还需要故障检测、选主、流量切换、防脑裂、数据补偿和演练。

先定义 RPO 与 RTO

  • RPO:可接受丢失多少数据,例如 0 秒、30 秒或 5 分钟。
  • RTO:故障后可接受多久恢复服务。

没有 RPO/RTO 就无法判断异步、半同步、多机房和备份投入是否合理。

复制模式

模式提交语义优点风险与代价
异步复制主库本地提交即可返回延迟低、吞吐好主库突然丢失时,未传到副本的事务可能丢失
半同步复制至少一个副本确认收到日志后返回缩小数据丢失窗口网络或副本异常会增加提交延迟,并可能退化
Group Replication组通信与一致性协议协调成员自动成员管理、支持单主/多主模式部署与故障语义更复杂,仍需理解一致性和路由

半同步通常确认的是副本收到并写入 relay log,不等于业务已经能从副本读取到该事务。

故障切换流程

mermaid
flowchart TD
    A["监控发现主库异常"] --> B["多信号确认并隔离旧主"]
    B --> C["比较候选副本 GTID 与延迟"]
    C --> D["选择数据最完整的健康副本"]
    D --> E["提升为新主并更新拓扑"]
    E --> F["切换代理、DNS 或服务发现"]
    F --> G["验证读写、复制和业务指标"]
    G --> H["修复旧主并作为副本重新加入"]

最危险的问题是脑裂:旧主实际仍能写,新主也开始接收写入。必须通过 fencing(隔离电源、网络、存储或撤销写入口)保证同一时刻只有一个可写主节点。

GTID

GTID 为每个已提交事务提供全局标识,能帮助判断事务集合、切换复制来源和跳过已执行事务。它简化拓扑管理,但不能自动解决:

  • 业务写入幂等。
  • 已丢失事务恢复。
  • 冲突数据合并。
  • 故障检测误判。
  • 新旧主同时写入。

读写分离的一致性

异步副本可能读不到刚写入的数据。常见策略:

  • 强一致读固定走主库。
  • 写后一定时间或同一会话内读主库。
  • 等待特定 GTID 已在副本执行后再读。
  • 根据复制延迟动态摘除副本。
  • 业务使用版本号或状态机容忍旧值。

不能简单用固定 sleep 保证同步,它既不可靠又增加延迟。

跨机房与多地域

距离会增加网络 RTT,同步确认会直接拉高事务提交延迟。设计要权衡:

  • 单地域同步、多地域异步的 RPO。
  • 地域级故障切换是否允许人工确认。
  • DNS、代理、连接池缓存和客户端重连时间。
  • 数据合规和跨境限制。
  • 演练时如何避免真实双写。

高可用不等于备份

误删、错误 DDL、应用 Bug、勒索和逻辑损坏可能快速复制到所有副本。必须独立保留全量备份、binlog、异地副本或不可变副本,并定期做恢复演练。

演练清单

  1. 主库进程崩溃、主机宕机、网络分区分别如何检测。
  2. 切换是否先隔离旧主,谁有权限触发。
  3. 候选副本落后多少,预计丢失哪些事务。
  4. 应用连接池多久重连,长事务如何处理。
  5. 新主容量是否足够,其他副本如何重建复制。
  6. 是否能在目标 RTO 内完成,最终 RPO 如何核对。
  7. 切回还是继续运行,旧主数据如何校验和处理。

高频面试题

主库宕机后是不是直接提升从库

不能。先确认故障并隔离旧主,防止脑裂;比较候选副本的健康、延迟和 GTID 集合,选择数据最完整者;提升后切换流量并验证读写,再重建复制。还要根据异步或半同步语义说明可能的数据丢失窗口。

半同步能保证不丢数据吗

不能无条件保证。它缩小主库独自持有事务的窗口,但确认点、超时退化、网络分区、副本是否落盘以及故障切换选择都会影响结果。严格目标要由具体配置、拓扑和故障模型证明。