一、备份的基本概念与分类
1.1 为什么要备份
备份是数据安全的最后一道防线,用于应对:误删除/误更新(DML 误操作、DROP TABLE)、硬件故障、软件 Bug、机房灾难、数据被恶意篡改等。衡量备份方案的两个核心指标:
- RPO(恢复点目标):最多能容忍丢失多少数据(比如丢 5 分钟、丢 1 小时);
- RTO(恢复时间目标):最多能容忍多长时间恢复服务。
1.2 备份的三个正交分类维度
| 分类维度 | 类型 | 区分依据 |
|---|---|---|
| 按备份内容/方式 | 逻辑备份 vs 物理备份 | 备份的是 SQL 文本还是原始数据文件 |
| 按备份范围 | 全量 vs 增量 vs 差异 | 备份哪些数据 |
| 按备份时数据库状态 | 热备 vs 温备 vs 冷备 | 备份期间数据库能否对外读写 |
1.3 逻辑备份 vs 物理备份
逻辑备份 :导出数据库的结构和数据,表现为 SQL 语句(CREATE/INSERT)或分隔文本(CSV)。代表工具 mysqldump。
- 优点:文件是纯文本,可读、可编辑、跨平台/跨版本兼容性好、可只恢复单个库或单表;
- 缺点:备份和恢复都要经过 SQL 层(导出是查询、导入是逐行执行 INSERT),大数据量下很慢。
物理备份 :直接拷贝数据库在磁盘上的原始文件(数据文件、日志文件、配置文件等)。代表工具 XtraBackup、文件系统快照(LVM、云盘快照)。
- 优点:文件拷贝级别的速度,备份恢复都很快,适合大数据量;
- 缺点:文件与 MySQL 版本、操作系统、配置绑定,可移植性差,不能直接查看其中某条数据,通常按整个实例恢复。
1.4 全量、增量、差异备份
- 全量备份(Full) :备份某一时刻数据库的全部数据;
- 增量备份(Incremental):以上一次备份(全量或上一次增量)为基准,只备份之后变化的数据;
- 差异备份(Differential) :以最近一次全量备份为基准,备份全量之后所有变化的数据。
| 类型 | 每次备份量 | 恢复时需要 | 恢复速度 |
|---|---|---|---|
| 增量 | 小(只备最近变化) | 全量 + 依次回放所有增量(依赖链) | 慢 |
| 差异 | 越来越大(累积全量后的变化) | 全量 + 最近一次差异(只需两个副本) | 快 |
XtraBackup 原生支持的是增量备份(靠 LSN 对比)。
1.5 热备、温备、冷备
- 热备(Hot) :数据库正常运行,读写都不受影响 地完成备份。InnoDB 下用
mysqldump --single-transaction或 XtraBackup 可实现; - 温备(Warm) :数据库运行但被置为只读或加锁,能查不能写(如对 MyISAM 表锁表导出);
- 冷备(Cold) :先停掉 mysqld,再直接拷贝文件,最简单且数据一定一致,但期间服务中断。
1.6 物理热备为什么必须配合 redo log(WAL 原理)
InnoDB 采用 WAL(Write-Ahead Logging,预写日志) :事务提交时先把 redo log 刷盘,再异步把内存中的脏页刷到数据文件 。因此正常运行时,磁盘上的数据文件内容可能落后于内存和 redo log。
这带来一个关键结论:
- 冷备直接拷数据文件即可(停机后所有数据已落盘,是一致的);
- 热备在服务运行中直接拷贝数据文件是不行的------拷贝持续一段时间,期间文件在不断变化,且部分最新数据还在内存里,拷出来的文件处于"撕裂"的不一致状态。
所以物理热备的正确做法是:拷贝数据文件的同时,持续记录这段时间产生的 redo log,最后回放 redo log 把备份推到一个一致状态(这正是 XtraBackup 做的事,见第四章)。
二、mysqldump 逻辑备份
2.1 原理与特点
mysqldump 通过查询数据库,把库表结构和数据导出为一组 SQL 语句(DROP/CREATE/INSERT),执行这些 SQL 即可重建数据。兼容性好、跨平台、易恢复,但单线程、逐行处理,大数据量慢,一般适合 10G 以下的备份。
2.2 基本语法
# 导出(用 mysqldump,重定向到文件)
mysqldump [options] > dump.sql
# 导入(用 mysql 客户端,不是 mysqldump!)
mysql [options] < dump.sql
2.3 常用选项
| 选项 | 作用 |
|---|---|
--all-databases,-A |
备份所有数据库 |
--databases db1 db2,-B |
备份指定多个库(会带 CREATE DATABASE) |
--tables t1 t2 |
备份指定表(须放在最后,其后名称都视为表名) |
--no-data,-d |
只导出表结构,不导出数据 |
--no-create-info,-t |
只导出数据,不生成 CREATE TABLE |
--no-create-db,-n |
不生成 CREATE DATABASE |
--extended-insert,-e |
用一条多值 INSERT 插入多行(默认开启,减小文件、加快导入) |
--add-drop-table |
每个 CREATE TABLE 前加 DROP TABLE IF EXISTS(默认开启) |
--add-drop-database |
每个 CREATE DATABASE 前加 DROP DATABASE |
--add-locks |
每张表用 LOCK TABLES / UNLOCK TABLES 包裹(默认开启,加快导入) |
--lock-tables,-l |
导出前锁定当前库的所有表(只读锁,适合 MyISAM) |
--lock-all-tables,-x |
导出期间锁定所有库的所有表(全局读锁) |
--single-transaction |
InnoDB 一致性热备(不锁表,见 2.4) |
--source-data[=1/2] |
记录 binlog 位点(8.0;5.7 叫 --master-data,见 2.5) |
--flush-logs,-F |
开始导出前切换 binlog,便于增量恢复定位起点 |
--routines,-R |
导出存储过程和函数 |
--triggers |
导出触发器(默认开启,--skip-triggers 关闭) |
--events,-E |
导出事件调度器 |
--ignore-table=db.table |
跳过指定表(可多次使用) |
--no-tablespaces |
不处理表空间,避免导出时需要 PROCESS 权限 |
--set-gtid-purged=off |
GTID 环境下普通恢复/迁移时使用,避免导入时写 gtid_purged 报错 |
--force,-f |
导出中遇到 SQL 错误也继续 |
--no-autocommit |
每张表的导入包在 SET autocommit=0; ... COMMIT; 之间,加快导入 |
--default-character-set=utf8mb4 |
指定字符集,避免中文乱码 |
2.4 一致性热备:--single-transaction(重点)
默认导出过程中数据还在被修改,会产生三类不一致:
- 备份到未提交事务写入的数据(事务后来回滚了,备份却留下了脏数据);
- 备份期间发生回滚,导致备份中包含已被删除/修改的数据;
- 备份期间新插入的数据,部分表导到、部分表没导到,跨表不一致。
--single-transaction 的原理(仅对 InnoDB 等事务引擎有效):
- 短暂执行
FLUSH TABLES WITH READ LOCK加全局读锁; - 开启 RR 隔离级别的事务并建立一致性快照:
START TRANSACTION WITH CONSISTENT SNAPSHOT; - 若同时用了
--source-data,在锁内读取当前 binlog 位点; - 释放全局读锁;
- 之后全程基于 MVCC 快照逐表导出,快照建立时刻的数据被固定,不阻塞其他事务写入。
注意:它只对 InnoDB 有效;MyISAM 不支持事务,导出 MyISAM 表仍必须锁表(温备)。
2.5 --source-data 与 binlog 位点
--source-data=2:在 dump 文件中以注释 形式写入CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='binlog.xxx', SOURCE_LOG_POS=位点,记录备份对应的 binlog 位置;=1:该语句不注释、会生效(用于搭建从库)。
这个位点是"全量备份 + binlog 时间点恢复"的衔接点(见第五章)。
2.6 使用样例与文件头解读
mysqldump -ubackup_user -p -h127.0.0.1 -P3306 \
-B testdb --default-character-set=utf8mb4 \
--single-transaction --source-data=2 \
--triggers --events --routines \
--set-gtid-purged=off > /backup/mysql/$(date +%Y%m%d)_0.sql
dump 文件开头的一串 SET 是为了导入时又快又安全:临时关闭外键检查、唯一性检查、设置字符集和时区等,导入结束后恢复原值:
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
2.7 恢复方式
# 方式1:命令行重定向(最常用)
mysql -uroot -p < /backup/mysql/xxx.sql
# 方式2:进入 MySQL 后用 source
mysql> source /backup/mysql/xxx.sql;
mysql> \. /backup/mysql/xxx.sql;
# 方式3:管道流式迁移(一台机器导出,直接导入另一台,不落盘)
mysqldump -ubackup_user -p -h127.0.0.1 -B testdb \
--single-transaction --source-data=2 \
--triggers --events --routines --set-gtid-purged=off \
| mysql -uroot -p -h192.168.100.237 -P3306
用 pv 查看导入进度(安装命令是 apt install pv):
# 显示进度条;-L 用于限速(字节/秒,如 -L 10M)
pv /backup/mysql/dump.sql | mysql -uroot -p -h127.0.0.1 -P3306
2.8 权限与注意事项
- 导出表需 SELECT 权限;导出视图需 SHOW VIEW ;导出触发器需 TRIGGER;
- 未用
--single-transaction时需 LOCK TABLES ;未用--no-tablespaces时需 PROCESS; - 默认不备份
INFORMATION_SCHEMA、performance_schema、sys,需要时显式指定; - mysqldump 是单线程,大数据量耗时长;对 MyISAM 会长时间锁表影响业务;
- 恢复时间通常是备份时间的数倍(要逐条执行 INSERT、建索引),故大数据量应改用物理备份。
三、SELECT INTO OUTFILE / LOAD DATA / mysqlimport 备份
这是比 INSERT 更快的文本数据导入导出方式(制表符/CSV 分隔的纯数据,适合简单数据迁移和大批量导入)。
-- 导出:查询结果写到服务器端文件(注意:文件不能已存在,防止覆盖)
SELECT * FROM student INTO OUTFILE '/var/lib/mysql-files/student.txt'
FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';
-- 导入:把服务器端文件数据装入表
LOAD DATA INFILE '/var/lib/mysql-files/student.txt'
INTO TABLE student
FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';
要点:
- 文件位置由服务端变量
secure_file_priv限制(NULL表示禁用,指定目录表示只能在该目录读写,空表示不限制);INTO OUTFILE生成的是服务器端文件,需要 FILE 权限; LOAD DATA INFILE读服务器端 文件;加LOCAL关键字(LOAD DATA LOCAL INFILE)读客户端 文件并上传;-
mysqlimport 是
LOAD DATA INFILE的命令行封装:mysqlimport -uroot -p [--local] dbname student.txt它靠文件名确定表名:去掉扩展名后的文件名必须等于目标表名(student.txt → student 表)。
-
四、XtraBackup 物理热备
4.1 工具与原理
Percona XtraBackup 是 Percona 开源、免费的 MySQL 物理热备工具(8.0 版本对应 MySQL 8.0,2.4 对应 5.7)。它对 InnoDB 表可以真正热备、不阻塞读写,支持全量和增量备份。
热备原理(对应 1.6 节):
- 后台线程拷贝数据文件(此时数据库正常运行);
- 拷贝期间持续记录新产生的 redo log(存为 xtrabackup_logfile);
- 数据文件拷贝完成后,得到的是不一致副本;
- 恢复前执行
--prepare,回放 redo log(前滚已提交事务)、回滚未提交事务,让备份达到一致性状态。
4.2 全量备份
xtrabackup --defaults-file=/etc/mysql/my.cnf \
--host=localhost --port=3306 --user=backup_user --password=123456 \
--use-memory=1G --parallel=2 \
--backup --target-dir=/backup/mysql/full
| 参数 | 作用 |
|---|---|
--defaults-file |
配置文件路径(必须放在第一位),用于确定 datadir 等 |
--use-memory=1G |
prepare 阶段可用的内存(主要在准备阶段提速) |
--parallel=2 |
并行拷贝/恢复的线程数 |
--backup |
表示执行备份 |
--target-dir |
备份输出目录 |
4.3 备份目录中的关键文件
- xtrabackup_binlog_info:备份完成时的 binlog 文件名、position(和 GTID),用于 PITR/搭从库;
- xtrabackup_checkpoints :备份类型和 LSN 信息(
from_lsn、to_lsn、last_lsn),增量备份就靠 LSN 对比; - xtrabackup_info:备份的元信息(版本、时间、引擎、GTID 等);
- xtrabackup_logfile:备份期间累积的 redo log。
4.4 恢复流程(prepare → copy-back)
# 1)停止 mysqld,清空(或移走)旧的 datadir,再建同名空目录
systemctl stop mysqld
rm -rf /var/lib/mysql/*
mkdir -p /var/lib/mysql
# 2)prepare:回放/回滚日志,把备份推到一致性状态(可加大 --use-memory)
xtrabackup --prepare --use-memory=1G --target-dir=/backup/mysql/full
# 3)copy-back:把准备好的文件拷回 datadir
xtrabackup --defaults-file=/etc/mysql/my.cnf \
--copy-back --parallel=2 --target-dir=/backup/mysql/full
# 4)修正属主(手工新建的目录属主是 root,mysqld 无法读写)
chown -R mysql:mysql /var/lib/mysql
# 5)启动
systemctl start mysqld
注意:
--prepare后的数据才是一致可用的;--copy-back要求 datadir 为空(除非用 --force-non-empty-directories)。也可以用--move-back直接移动而非复制。
4.5 增量备份(简述)
# 全量
xtrabackup --backup --target-dir=/backup/mysql/full ...
# 第一次增量(基于全量)
xtrabackup --backup --target-dir=/backup/mysql/inc1 \
--incremental-basedir=/backup/mysql/full ...
# 第二次增量(基于第一次增量)
xtrabackup --backup --target-dir=/backup/mysql/inc2 \
--incremental-basedir=/backup/mysql/inc1 ...
# 准备全量恢复
xtrabackup --prepare --apply-log-only --target-dir=/backup/mysql/full
# 准备第⼀次增量恢复
xtrabackup --prepare --apply-log-only --target-dir=/backup/mysql/full \
--incremental-dir=/backup/mysql/inc1
# 准备第⼆次增量恢复
xtrabackup --prepare --apply-log-only --target-dir=/backup/mysql/full \
--incremental-dir=/backup/mysql/inc2
......
# 最后一次增量恢复
xtrabackup --prepare --target-dir=/backup/mysql/full \
--incremental-dir=/backup/mysql/incn
恢复时要按顺序合并:先 prepare 全量(加 --apply-log-only 保持可继续合并),再依次合并各增量(最后一个增量不加 --apply-log-only 以便回滚未提交事务),最后再 copy-back。
五、全量备份 + binlog 时间点恢复(PITR)
全量备份只能恢复到"备份那一刻",要恢复到备份之后、故障之前的任意时间点,必须配合上一篇讲的 binlog:
时间轴: 全量备份点 ────────────────▶ 误操作发生
│ │
│ ① 恢复全量备份 │
│ ② 从备份位点开始重放 binlog,停在误操作前
▼
恢复到任意时间点
操作步骤:
-
全量备份时记录 binlog 位点(mysqldump 的
--source-data=2,或 XtraBackup 的xtrabackup_binlog_info); -
故障后先恢复全量备份;
-
用 mysqlbinlog 从该位点开始,按位置或时间截取并重放 binlog,跳过误操作:
mysqlbinlog --start-position=位点 --stop-position=误操作前位点
/var/lib/mysql/binlog.0000xx | mysql -uroot -p
这就是"定期全量 + 持续 binlog"的经典备份策略:全量备份提供基线,binlog 负责把数据前滚到任意时间点,RPO 可低至接近 0。
六、三种备份手段对比
| 维度 | mysqldump | SELECT INTO OUTFILE / LOAD | XtraBackup |
|---|---|---|---|
| 类型 | 逻辑备份(SQL 文本) | 逻辑备份(分隔文本) | 物理备份(数据文件+redo) |
| 备份方式 | 单线程逐表查询 | 单表数据导出 | 多线程文件拷贝 |
| 大数据量速度 | 慢(10G 以下) | 快(仅数据) | 很快 |
| 热备 | InnoDB 加 --single-transaction 可热备 |
运行中可用 | InnoDB 真热备 |
| 恢复方式 | 执行 SQL(慢) | LOAD 装入单表 | 拷回文件(快) |
| 粒度/可读性 | 可单库单表、文本可读 | 单表纯数据、可读 | 整实例、不可读、移植性差 |
| 典型场景 | 小库、迁移、逻辑快照 | 大批量数据导入导出 | 大库生产备份、增量备份 |
七、核心总结
- 备份分三个正交维度:逻辑/物理(备份什么)、全量/增量/差异(备份范围)、热/温/冷(备份时数据库状态)。
- 增量 以上一次备份为基准、恢复需全量+所有增量;差异以最近全量为基准、恢复只需全量+最近差异。
- InnoDB 是 WAL(先写 redo log 再刷脏页);冷备直接拷文件,**物理热备必须"拷数据文件 + 记录并回放 redo log"**才能保证一致。
mysqldump导出用mysqldump >、导入用mysql <;--single-transaction靠 RR 一致性快照实现 InnoDB 不锁表热备;--source-data=2记录 binlog 位点;--extended-insert是多值 INSERT。- mysqldump 单线程、恢复慢,适合小库;
INTO OUTFILE/LOAD DATA是更快的纯文本导入导出,文件在服务器端受secure_file_priv限制,mysqlimport 靠文件名确定表名。 - XtraBackup 是开源物理热备工具 :
--backup备份 →--prepare回放 redo log 得到一致副本 →--copy-back拷回 datadir →chown -R mysql:mysql后启动;增量备份靠 LSN。 - 生产标准策略是"定期全量(物理或逻辑)+ 持续 binlog ",用全量做基线、binlog 做时间点恢复(PITR),并根据 RPO/RTO 设计频率,且要定期做恢复演练(能恢复的备份才算备份)。