Skip to content

MySQL复制与备份技术

1. 复制与备份分别解决什么问题

在 MySQL 体系里,“复制”和“备份”经常一起出现,但目标不同:

  • 复制(Replication):核心是高可用与读扩展(读写分离、故障切换、跨机房容灾的基础)。
  • 备份(Backup):核心是数据可恢复(误删误更新、逻辑错误、勒索加密、机房级灾难恢复)。

一个关键结论:复制不是备份

  • 误删一条数据,会“瞬间复制”到所有从库;
  • 只有“离线的、可追溯的、可回放的”备份,才具备真正的恢复能力。

2. MySQL 复制原理:binlog 驱动的增量回放

2.1 复制链路的核心组成

以经典 “一主多从” 为例:

  1. 主库把事务变更写入 binlog
  2. 从库 I/O 线程从主库拉取 binlog,写入本地 relay log
  3. 从库 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 logbinlog 的一致性问题,会把一次事务提交拆成一个简化版的两阶段提交流程:

  1. InnoDB 先把事务写入 redo log,并标记为 PREPARED
  2. Server 层写入 binlog,并按配置决定是否刷盘。
  3. 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 也能像处理一次正常宕机那样:

  1. 从 checkpoint 找到最近的一致位置。
  2. 重放 redo log,恢复已提交但尚未落盘的数据页修改。
  3. 回滚未提交事务,保证最终库处于一致状态。

所以物理备份、存储快照和实例宕机恢复,在底层上依赖的是同一套 InnoDB 崩溃恢复能力。

4.4 PITR(Point-In-Time Recovery):全量备份 + binlog 回放

PITR 的核心链路:

  1. 先恢复一份“基线全量备份”(到某个时间点 T0)。
  2. 再把 binlog 从 T0 回放到目标时间点 T1(或回放到某个 GTID 位置)。

典型恢复步骤(概念流程):

  1. 准备新实例,恢复全量备份。
  2. 找到全量备份对应的 binlog 起点(position 或 GTID)。
  3. 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 回放,可能无法恢复出主库真实已提交的数据。
  • 恢复演练必须做:不演练就等于没有备份。