Skip to content
Charles Shao
Go back

MySQL 内核 · 主从复制与高可用

views

单库内核(存储、事务、日志、优化)齐了之后,生产还要面对:副本怎么跟上、主挂了怎么切、读能不能摊到从库。分库分表是「容量扩展」主线(见 数据库扩展);本篇只讲单逻辑实例上的复制与高可用——广告配置只读扩展和计费防丢的交汇点。

本文是 MySQL 内核系列的第 5 篇(主从复制与高可用 · 收官)。 全系列 5 篇:

  1. MySQL 内核(开篇)· InnoDB 存储结构与 B+ 树索引
  2. MySQL 内核 · 事务隔离、MVCC 与锁
  3. MySQL 内核 · redo log、undo log 与 binlog
  4. MySQL 内核 · 执行计划与慢查询优化
  5. MySQL 内核 · 主从复制与高可用(本篇)

一句话定位:复制 = 主库 binlog 事件经 Dump/IO/SQL(或并行 worker)在从库回放;半同步换「至少一副本收到」的耐久;HA 负责探活升主;读写分离必须显式处理复制延迟。

TL;DR

Table of contents

Open Table of contents

1. 复制在解决什么

前提是 binlog 可靠且与引擎一致——所以回到 双 1 与 2PC。位点演进出 GTID,切换与对账更清晰,现代部署优先开 GTID。

复制过滤(replicate-do-table 等)、只读从库上的临时表、以及「有人在从库误开可写」都会制造漂移。广告配置若存在「从库手工改一笔救急」,后面切换成主时会变成长达数周的幽灵 bug——从库必须只读,救急走正式变更。

数据库扩展 的边界再说一次:

问题本篇(复制/HA)扩展系列
单库读顶不住加只读从
单库写顶不住最多垂直拆分思路分库分表 / 队列削峰
主挂了升从、MGR
数据量无限涨归档 + 从库备份分片、冷热分离

不要指望「多挂几个从」解决写容量——写仍然砸在主上。

2. 复制链路:三线程心智

Master 上 binlog 与 Dump,Replica 上 IO Thread、relay log 与 SQL/并行 workers 的流水线。

延迟 = 拉日志延迟 + 回放排队;监控要拆开看 Seconds_Behind_Source 背后到底卡在哪段。

  1. Binlog Dump(主):把事件推给(或被)从库;
  2. IO Thread(从):收事件写入 relay log
  3. SQL Thread / Coordinator+Workers(从):解析 relay,应用到存储引擎。

旧版单线程 SQL 回放在写密集计费库几乎必堆积;并行复制按库、按事务间依赖(LOGICAL_CLOCK)或 writeset 冲突检测,把无冲突事务并行落库。

大事务(一次改几十万行)是延迟杀手:即便并行,也挡不住「一个事件堵住流水线」。广告侧批量改价、刷状态要切批、控制事务大小。

ROW 格式下,没主键/合适唯一键的表在从库回放更新可能要扫大量行来定位,延迟会离谱——每张被复制的表都应有主键,这是复制场景的硬纪律,不只是范式要求。

级联复制(A→B→C)曾用于跨机房,但排障复杂、延迟叠加;今日更常见是主库扇出多个从,或用中间件/云产品做拓扑。计费库慎用「深度级联」当 HA 主路径。

并行复制调参直觉:

3. 异步 vs 半同步

异步复制提交即返回事后传 binlog,与半同步等 Replica ACK 后再返回客户端的对比。

半同步保证的是「至少一从库收到并落 relay」,不是「已经应用完」——读从仍可能短暂落后。

模式提交返回时机主宕机风险
异步本机提交完即可未传出 binlog 可能丢
半同步至少一个从库 ACK耐久更好;从库慢拖主库;超时降级

rpl_semi_sync_master_wait_pointAFTER_SYNC(常见推荐)与 AFTER_COMMIT 决定 ACK 与引擎提交的相对顺序,选型时按版本文档核对。计费/账本倾向:双 1 + 半同步;纯配置只读从可接受异步,但要承认丢提交窗口。

观察半同步是否真在工作:主库状态里应能看到 ACK 客户端数;若频繁超时降级成异步,等于你以为有耐久其实没有——要告警「降级次数」。从库磁盘打满、网络抖动都会让半同步拖主库提交,此时要扩从或修盘,而不是默默忍受。

全同步(等所有从或 majority apply)延迟更高,MGR 单主模式用组复制协议做到一致性与自动选主,代价是冲突与网络更敏感。

4. 高可用拓扑

左侧传统主从加 MHA/Orchestrator;右侧 MGR 单主加 Secondary;底部 Proxy 读写分离。

扩展容量(分片)不在本篇;这里只保证「一台逻辑主」的复制与切换。

4.1 传统主从 + 编排

MHA、Orchestrator、各类云厂商 RAS:探活 → 选最新从库 → 补齐差异 → 提升为主 → 改 VIP/DNS/代理路由。要点:

误切换代价:短暂双主、GTID 分叉、对账几天。所以自动切换的阈值与人工确认门槛要按库的关键级分开:计费库可以「自动只读 + 人工确认升主」,配置库可以更激进。

4.2 MGR / InnoDB Cluster

组复制基于多数派共识思想(与 Raft/Paxos 系列 同类问题),故障时自动选主。适合希望少人工切换的中小集群;也要注意网络分区时的可写性、以及多主模式下冲突。广告配置库很多团队仍用「单主 + 半同步 + 编排」以求简单可控。

MGR 多主模式理论上多点可写,但冲突认证失败要回滚,广告「同行列改预算」类冲突密集,实践里少用多主扛计费写——单主更可预期。

4.3 读写分离

Proxy(如 ProxySQL、云中间件)或应用层路由:UPDATE 走主,SELECT 走从。最大坑永远是:

写后立刻读从库 → 读到旧快照。

对策按场景组合:

也可以在中间件做「事务粘滞」:同一会话在写过后一段时间内强制走主。实现简单,但连接池/多路复用下要定义清「会话」边界,否则粘滞失效或把过多读打回主库。

三种常见架构组合(广告配置):

  1. 主 + 2 半同步从 + Proxy 读写分离:经典,因果读要代码兜底;
  2. MGR 单主 + Router:少人工切换,网络与冲突要评估;
  3. 云托管主从 + 只读地址:省运维,仍然逃不开写后读旧,SLO 自己定。

选型看团队熟练度与「能不能接受短暂只读」:自动切换越猛,越要保证应用幂等与连接回收。

5. GTID 与切换时要注意什么

GTID(全局事务 ID) 让「每个事务在集群里有唯一身份证」,好处:

切换检查单(无论 MHA 还是人工):

  1. 确认旧主已 fence(只读或下线路由),防脑裂双写;
  2. 选中的新主 relay/复制进度够新(半同步场景通常更安心);
  3. 代理 / DNS / VIP 原子切到新主;
  4. 应用连接排空与重试;幂等写避免「超时已成功又重放」;
  5. 从库重新挂到新主,并验证 GTID 集合一致。

云托管 RDS 把很多步骤产品化了,但应用层幂等与连接失效处理仍然是你自己的活——和 高可用实践 同一套心智。

切主后常见「应用层症状」:

所以 HA 不只是 DBA 脚本,是应用连接策略 + 幂等键 + 观测三件套。

6. 延迟治理清单

  1. 开并行复制并验证 worker 数;
  2. 消灭超大事务与无主键表全表更新(无主键的 row 更新可能扫全表回放);
  3. 从库硬件不低于主太多(磁盘与 CPU);
  4. 半同步 ACK 慢时区分「网络 / 从库刷盘 / 主库等待」;
  5. 监控:Seconds_Behind_Source、relay 积压、worker 活跃度、半同步状态与降级次数;
  6. 只读从库别跑比主库更重的「偷偷全表分析」,否则自己制造延迟。

Seconds_Behind_Source 是估算值,极端时钟或多线程回放下可能抖;结合 relay 未应用字节数看更稳。

延迟跑高时的最短路径:

  1. 看是 IO 线程落后还是 SQL/worker 积压;
  2. SHOW PROCESSLIST / performance_schema 找从库正在回放的大事务;
  3. 对照主库 binlog 是否刚暴增(批量刷数、大 DDL);
  4. 必要时临时把分析流量挪走,给复制让 IO;
  5. 根治仍是:拆大事务、保主键、并行复制、硬件对齐。

系列地图(回顾)

核心问题
InnoDB 与 B+ 树行怎么存、索引怎么找
MVCC 与锁并发怎么看见对的版本、冲突怎么串行
redo/undo/binlog提交如何 crash-safe、如何可复制
执行计划慢在哪、怎么改计划
本篇副本怎么跟、主挂怎么切、读如何摊

参考


views
Share this post on:

Previous Post
OLAP(开篇)· 列式存储原理与 ClickHouse/Doris
Next Post
特征构建:切配、换角度、片下部位——把原始料做出新味道