这是《MySQL 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 主从复制让一份数据拥有多个副本,用于容灾、读写隔离、异地容灾和水平扩展读能力。它也带来延迟、一致性和运维复杂度。
24.1 复制的基本流程
异步复制流程:
主库提交事务
-> 写 Binlog
-> Dump Thread 推送 Binlog
-> 从库 Receiver Thread 写 Relay Log
-> 从库 Applier Thread 重放 Relay Log
-> 从库数据更新
关键点:
- 主库提交不等待从库应用;
- 从库可能落后;
- 主从间传输的是 Binlog 事件;
- 重放顺序要保证事务一致性;
- 从库位点必须持久可靠。
24.2 位点与 GTID
文件位点
mysql-bin.000010:123456
查看主库:
SHOW BINARY LOG STATUS;
查看从库:
SHOW REPLICA STATUS\G
老版本使用:
SHOW SLAVE STATUS\G
GTID
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-100
GTID 让事务有全局身份,主从切换和重建更容易。
配置示例:
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON
log_bin = mysql-bin
log_replica_updates = ON
read_only = ON
super_read_only = ON
24.3 搭建主从
主库创建账号:
CREATE USER 'repl'@'10.0.%' IDENTIFIED BY 'Repl123456!'
REQUIRE SSL;
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.0.%';
备份主库:
mysqldump -h10.0.0.11 -uroot -p \
--single-transaction \
--source-data=2 \
--routines --triggers --events \
--all-databases > primary_backup.sql
恢复到从库:
mysql -h10.0.0.12 -uroot -p < primary_backup.sql
GTID 自动定位:
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='10.0.0.11',
SOURCE_USER='repl',
SOURCE_PASSWORD='Repl123456!',
SOURCE_AUTO_POSITION=1,
SOURCE_SSL=1;
START REPLICA;
检查:
SHOW REPLICA STATUS\G
必须确认:
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Seconds_Behind_Source: 0
Last_IO_Error:
Last_SQL_Error:
24.4 复制线程
| 线程 | 职责 |
|---|---|
| Binlog Dump | 主库推送 Binlog |
| Replica I/O | 从库接收并写 Relay Log |
| Replica SQL | 从库应用 Relay Log |
| Coordinator | 并行复制协调器 |
| Worker | 并行应用事务 |
查看线程:
SHOW PROCESSLIST;
IO 停说明网络、权限或 Binlog 位点问题;SQL 停说明应用冲突、表结构差异或数据不一致。
24.5 异步复制
默认模式:
主库提交完成即返回客户端;
优点:
- 延迟低;
- 主库不依赖从库;
- 结构简单。
风险:
- 主库崩溃时未传事务丢失;
- 自动切换需要额外仲裁;
- 不适合零 RPO 场景;
- 异地延迟会影响更强同步方案。
24.6 并行复制
传统单线程应用是复制延迟的常见瓶颈。MySQL 8.0 支持基于组提交的逻辑时钟并行:
SHOW VARIABLES LIKE 'replica_parallel_type';
SHOW VARIABLES LIKE 'replica_parallel_workers';
SHOW VARIABLES LIKE 'binlog_transaction_dependency_tracking';
配置示例:
replica_parallel_type = LOGICAL_CLOCK
replica_parallel_workers = 8
binlog_transaction_dependency_tracking = WRITESET
适用:
- 主库并发高;
- 事务粒度小;
- 写入模型可并行;
- 从库 CPU 和 IO 有余量。
局限:
- 单个大事务仍无法拆开;
- 热点行顺序限制并行度;
- Worker 不是越大越好;
- 主库必须提供依赖信息。
24.7 主从延迟
常见原因:
| 来源 | 原因 |
|---|---|
| 主库 | 大事务、高频写入、Binlog 洪峰 |
| 网络 | 带宽不足、跨地域 RTT |
| 从库 | 单线程应用、机器规格差、IO 慢 |
| 查询 | 从库重查询、锁等待 |
| 表结构 | 从库缺少索引导致重放慢 |
| 资源 | CPU、内存、磁盘瓶颈 |
排查:
SHOW REPLICA STATUS\G
重点:
Seconds_Behind_Source
Replica_IO_Running
Replica_SQL_Running
Last_SQL_Error
Retrieved_Gtid_Set
Executed_Gtid_Set
更精细的 Performance Schema:
SELECT *
FROM performance_schema.replication_applier_status_by_worker;
Seconds_Behind_Source 有局限:网络长时间断开、时钟差异或状态更新时机都可能让它不准确。需要结合位点差、GTID 差和心跳表监控。
24.8 复制过滤
过滤可以只复制指定库或表:
replicate_do_db = shop
replicate_ignore_db = audit_log
风险:
- GTID 一致性管理复杂;
- 容易造成主从数据差异;
- 切换后拓扑混乱;
- 备份和恢复范围不完整;
- 应用和数据库过滤规则不完全等价。
高可用集群内节点应尽量保持完整复制。过滤更适合同步特定数据的下游只读节点,并且要有明确标识。
24.9 读写分离
典型应用:
写 -> 主库
强一致读 -> 主库或延迟确认的从库
可容忍旧数据读 -> 从库
一致性问题:
1. 写主库;
2. 立即读从库;
3. 从库还没应用;
4. 用户看到旧数据;
处理方式:
- 写后固定时间读主库;
- 会话粘性;
- 关键路径读主库;
- 使用 GTID 等待从库追上;
- 版本号或缓存失效;
- 明确业务可接受的旧数据窗口。
从库执行等待示例:
SELECT WAIT_FOR_EXECUTED_GTID_SET('<gtid_set>', 1);
不要把所有读都无条件打到从库,也不要把所有读都打到主库。
24.10 主从一致性校验
常用工具:
- Percona
pt-table-checksum; pt-table-sync;- 云厂商一致性校验;
- 自研抽样对账;
- 业务级指标对账。
原则:
- 定期校验核心表;
- 低峰执行;
- 控制校验范围和频率;
- 发现差异先备份;
- 分析根因后修复;
- 禁止未确认的随意覆盖;
- GTID 不代表数据一定一致。
24.11 从库重建
触发条件:
- 数据不一致;
- 位点丢失;
- 复制错误无法安全跳过;
- 从库磁盘损坏;
- 大范围 DDL 后需要重建;
- 主从延迟长期无法收敛。
流程:
1. 评估从库是否仍承载流量;
2. 选择主库低峰备份;
3. 使用物理备份或 Clone Plugin;
4. 恢复到新节点;
5. 配置 GTID 自动定位;
6. 追平延迟;
7. 校验一致性;
8. 恢复流量;
Clone Plugin 示例:
INSTALL PLUGIN clone SONAME 'mysql_clone.so';
CLONE INSTANCE FROM
'clone_user'@'10.0.0.11':3306
IDENTIFIED BY 'Clone123456!';
24.12 常见复制错误
1062 主键冲突
原因可能是从库被写入、位点重复、数据损坏或双写。
不要立刻跳过,先确认事务来源和影响。
1032 记录不存在
常见于 STATEMENT 复制、从库缺数据或手工修改。
1396 权限错误
检查复制账号、密码、SSL 和来源主机。
网络中断
确认 Replica_IO_Running 和错误日志,GTID 自动定位后通常可重连。
处理原则:
- 保留日志和状态;
- 判断单事务差异还是整库差异;
- 能重建就重建;
- 跳过必须记录 GTID;
- 事后校验一致性;
- 补齐告警和防再发措施。
本章小结
主从复制通过 Binlog、Relay Log 和 Applier 线程传播数据。GTID 简化位点管理和切换,并行复制缓解应用瓶颈。读写分离必须明确一致性策略,延迟监控不能只依赖 Seconds_Behind_Source,核心数据要定期校验并具备快速重建能力。
思考题
- 主从复制的三个关键线程分别做什么?
- GTID 相比文件位点有什么优势?
- 主从延迟的常见来源有哪些?
- 读写分离后如何避免写后读旧数据?
- 设计一套从库延迟超阈值的应急处理流程。