主从复制、高可用与分库分表

单机 MySQL 在容量、性能与容灾上都有上限。复制用于扩展读能力与容灾,分库分表用于突破单机容量。本章讲清原理与权衡。

复制原理

MySQL 复制基于 binlog,三个关键线程:

主库                             从库
┌──────────────┐   binlog    ┌──────────────┐
│  写入 + binlog│ ─────────► │ I/O 线程      │
└──────────────┘             │   ▼           │
                             │ relay log     │
                             │   ▼           │
                             │ SQL 线程 重放 │
                             └──────────────┘
  1. 主库把变更写入 binlog
  2. 从库 I/O 线程拉取 binlog,写入本地 relay log
  3. 从库 SQL 线程重放 relay log,应用变更。

binlog 格式

格式特点
STATEMENT记录 SQL 语句,日志小,但函数/随机结果可能不一致
ROW记录每行的前后值,最安全,日志较大
MIXED自动在两者间切换
Tip

生产推荐 binlog_format=ROW,它是数据恢复与 CDC 工具(如 Debezium、Canal)的基础,也是 GTID 与多线程复制的前提。

配置主从(简版)

[mysqld]
server-id=1
log-bin=mysql-bin
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON
CREATE USER 'repl'@'%' IDENTIFIED BY 'strong-password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='10.0.0.1',
  SOURCE_USER='repl',
  SOURCE_PASSWORD='strong-password',
  SOURCE_AUTO_POSITION=1;   -- 使用 GTID

START REPLICA;
SHOW REPLICA STATUS\G        -- 关注 Slave_IO_Running / Slave_SQL_Running 与 Seconds_Behind_Master

复制延迟

从库重放通常慢于主库写入,表现为 Seconds_Behind_Source 增大。常见原因与对策:

  • 大事务 / 大批量 DML → 拆小批量,分多次提交。
  • 从库单线程回放 → 开启多线程复制(replica_parallel_workers)。
  • 从库承担大量读 → 增加从库或读写分离路由。
  • 无主键表 + ROW 格式 → 补主键(否则回放全表扫描)。
Warning

读写分离下的复制延迟会导致「写后读不到」。对一致性敏感的操作(如支付后立即查询),应强制走主库,或用会话级路由保证同一请求读到最新数据。

高可用方案

方案思路特点
半同步复制至少一个从库确认后才返回降低丢数据风险,略有延迟
MHA / Orchestrator自动选主、切换传统方案,运维复杂
MySQL Group ReplicationPaxos 多副本原生高可用,配置较重
InnoDB Cluster / MGR官方整合方案推荐新集群使用
云托管(RDS)云厂商代管省运维,成本较高

分库分表

当单表数据量达到千万级、单库写入逼近上限时,考虑水平拆分。

拆分维度

  • 垂直拆分:按业务/字段拆表拆库(如订单库、用户库)。
  • 水平拆分:按分片键把同一张表的数据分散到多个库/表。

分片键选择

分片键优点风险
用户 ID查询聚合自然以订单号查询需额外映射
订单号单笔查询高效按用户维度查询需广播
时间便于归档热点集中在新分片

分片算法

取模:shard = hash(id) % N          简单,但扩容需迁移
范围:按 id 区间 / 时间区间          易扩容,易热点
一致性哈希 / 虚拟槽:平滑扩容        实现复杂(Redis Cluster 采用)

中间件

  • 客户端分片:ShardingSphere-JDBC、TSharding。
  • 代理分片:ShardingSphere-Proxy、MyCat、Vitess。
Warning

分库分表是最后手段,会带来跨库事务、跨库 JOIN、全局排序、分布式 ID、扩容迁移等一系列复杂度。上分片前先穷尽:加索引、读写分离、归档冷数据、表分区、缓存等手段。

小结

  • 复制基于 binlog,用 ROW 格式与 GTID 更安全可靠。
  • 复制延迟无法完全消除,关键读必须路由主库。
  • 高可用优先考虑官方 InnoDB Cluster / MGR 或云托管。
  • 分库分表成本高昂,先优化再拆分的顺序不可颠倒。