MySQL复制与备份技术
1. 复制与备份分别解决什么问题
在 MySQL 体系里,“复制”和“备份”经常一起出现,但目标不同:
- 复制(Replication):核心是高可用与读扩展(读写分离、故障切换、跨机房容灾的基础)。
- 备份(Backup):核心是数据可恢复(误删误更新、逻辑错误、勒索加密、机房级灾难恢复)。
一个关键结论:复制不是备份。
- 误删一条数据,会“瞬间复制”到所有从库;
- 只有“离线的、可追溯的、可回放的”备份,才具备真正的恢复能力。
2. MySQL 复制原理:binlog 驱动的增量回放
2.1 复制链路的核心组成
以经典 “一主多从” 为例:
- 主库把事务变更写入 binlog。
- 从库 I/O 线程从主库拉取 binlog,写入本地 relay log。
- 从库 SQL 线程回放 relay log,把变更应用到从库数据文件。
关键文件/概念:
binlog:主库的逻辑变更日志(复制与 PITR 的核心)。relay log:从库接收的中转日志。server_id:复制节点唯一标识。
这里有一个很容易被忽略、但面试里经常追问的点:为什么主库可以放心把 binlog 作为复制和恢复依据?因为 MySQL 在开启 binlog 时,需要同时维护两套日志:
redo log:InnoDB 引擎层的物理日志,用来保证崩溃恢复后已提交事务不丢。binlog:Server 层的逻辑日志,用来做复制与 PITR。
如果两者提交口径不一致,就会出现“主库已经恢复出某个事务,但从库和 PITR 看不到它”的问题。
2.2 为什么 binlog 能作为复制依据:两阶段提交(2PC)
MySQL 为了解决 redo log 和 binlog 的一致性问题,会把一次事务提交拆成一个简化版的两阶段提交流程:
- InnoDB 先把事务写入
redo log,并标记为PREPARED。 - Server 层写入
binlog,并按配置决定是否刷盘。 - InnoDB 再把该事务标记为真正
COMMIT。
这样做的价值是:
- 如果宕机发生在写
binlog之前,那么恢复时看到事务只处于prepare状态,且binlog里没有对应记录,这个事务会被回滚。 - 如果宕机发生在
binlog已写入、但 InnoDB 还没来得及写最终commit标记时,恢复时会根据binlog中的记录把该事务补提交。
因此,崩溃恢复后,InnoDB 的最终数据状态会和 binlog 保持一致。这正是复制和 PITR 能成立的底层前提。
2.3 binlog 格式:STATEMENT / ROW / MIXED
binlog 记录“要怎么复制”,主要有三种格式:
- STATEMENT:记录 SQL 语句,体积小;但遇到非确定性函数、触发器等容易不一致。
- ROW:记录行级变更(前/后镜像或仅后镜像),一致性最好;但体积更大。
- MIXED:自动在两者间切换。
工程上更常见的选择是 ROW(尤其是对一致性敏感的业务)。
2.4 GTID:让复制定位更可靠
GTID(Global Transaction ID)为每个事务分配全局唯一 ID,使得:
- 从库追主、故障切换、补齐缺失事务更简单;
- 不必依赖“文件名 + position”去定位复制点。
故障切换场景通常建议启用 GTID,并配合自动化的 failover 工具与流程。
2.5 复制模式:异步 / 半同步(以及一致性取舍)
- 异步复制(默认):主库提交不等待从库确认;性能最好,但故障切换可能丢最近提交。
- 半同步复制:主库提交会等待至少一个从库确认“已收到 binlog”(实现细节与版本/配置有关);降低丢数据窗口,但会增加提交延迟,并受从库状态影响。
注意:半同步也不等价于“强一致”,它通常只是把“数据丢失窗口”缩小。
另外还要区分两个层次的问题:
- 事务提交后主库本机是否能在崩溃后恢复出来:主要看
redo log/binlog的持久化配置。 - 事务提交后是否已经复制到从库:主要看复制模式和从库接收状态。
所以半同步解决的是“主库到从库”这段链路的风险窗口,不是单机崩溃恢复的全部问题。
2.6 复制延迟(Replication Lag)从哪里来
常见原因:
- 从库回放能力不足(单线程回放、磁盘慢、CPU 忙)。
- 主库写入突刺导致从库追不上。
- 大事务、批量写入导致回放“卡住”。
- 从库上跑了重查询、备份、统计任务。
业务层常见坑:
- 读写分离后“写后立刻读从库”读不到(读到了旧数据)。
- 依赖从库做一致性判断(错误)。
解决方向:
- 对“写后读一致性”强的请求,走主库读或引入会话级路由(读你所写)。
- 监控并告警复制延迟,容量规划时把从库回放能力当成硬指标。
3. 常见复制拓扑与适用场景
| 拓扑 | 特点 | 优点 | 风险/代价 |
|---|---|---|---|
| 一主多从 | 最常见 | 读扩展、成本低 | 主库是单点写入瓶颈 |
| 级联复制 | 从库再挂从库 | 降低主库复制压力 | 延迟叠加、链路更复杂 |
| 双主(互为主从) | 两边都可写(容易被误用) | 某些场景下提升可用性 | 冲突处理复杂,强烈依赖约束与写入规范 |
| MGR / Group Replication | 组复制(多主/单主) | 自动成员管理、一定程度一致性 | 部署与运维复杂,性能/网络要求更高 |
4. 备份技术:逻辑备份、物理备份与快照
4.1 备份分类维度
1) 按数据形态:
- 逻辑备份:导出 SQL(表结构 + 数据)。
- 物理备份:直接备份数据文件(页、ibd、redo 等),恢复更快。
2) 按是否停机:
- 冷备:停库后拷贝,简单但不可用。
- 热备:不停机完成一致性备份(更常用)。
3) 按恢复粒度:
- 全量备份:某个时间点的完整数据集。
- 增量备份:相对上一次备份的变化部分(依赖工具与策略)。
4.2 逻辑备份:mysqldump 的正确用法
InnoDB 场景下常用:
mysqldump --single-transaction --routines --triggers --events --set-gtid-purged=OFF your_db > backup.sql
要点:
--single-transaction:基于一致性快照导出(依赖事务隔离与引擎特性),避免长时间全局锁。- 大库导出/导入慢,且对线上性能影响明显;适合中小库或用于“结构级/小表”恢复。
4.3 物理备份:更适合大库与快速恢复
常见做法:
- 使用物理备份工具做热备(例如 Percona XtraBackup 等生态工具)。
- 或使用存储快照(LVM/ZFS/云盘快照)配合 MySQL 的备份锁,获得一致性切点。
对“快照备份”的关键要求是:拿到一致性切点 + 记录可用于回放的位点(binlog position 或 GTID)。
这里的一致性切点,本质上通常是一个崩溃一致点(crash-consistent point)。也就是说,即使备份时内存里还有尚未落盘的数据页,只要相关 redo log 完整,实例在恢复并重启后,InnoDB 也能像处理一次正常宕机那样:
- 从 checkpoint 找到最近的一致位置。
- 重放
redo log,恢复已提交但尚未落盘的数据页修改。 - 回滚未提交事务,保证最终库处于一致状态。
所以物理备份、存储快照和实例宕机恢复,在底层上依赖的是同一套 InnoDB 崩溃恢复能力。
4.4 PITR(Point-In-Time Recovery):全量备份 + binlog 回放
PITR 的核心链路:
- 先恢复一份“基线全量备份”(到某个时间点 T0)。
- 再把
binlog从 T0 回放到目标时间点 T1(或回放到某个 GTID 位置)。
典型恢复步骤(概念流程):
- 准备新实例,恢复全量备份。
- 找到全量备份对应的 binlog 起点(position 或 GTID)。
- 用
mysqlbinlog解析并回放到目标时间点:
mysqlbinlog --start-datetime="2026-01-31 10:00:00" --stop-datetime="2026-01-31 10:05:00" binlog.000123 | mysql
要点:
- PITR 依赖 binlog 的保留策略与完整性(不要把 binlog 当“可有可无”)。
- PITR 之所以可信,依赖的是两阶段提交保证了
binlog与 InnoDB 已提交事务的一致口径;否则仅靠binlog回放,可能无法恢复出主库真实已提交的数据。 - 恢复演练必须做:不演练就等于没有备份。