全量备份对innodb表几乎总需加--single-transaction,否则锁表阻塞写入;增量备份只能依赖binlog;mysqldump易漏--routines、--events、--set-gtid-purged=off;压缩备份须校验完整性。

全量备份必须加 --single-transaction 吗?
不是必须,但对 InnoDB 表几乎总是要加。不加会导致备份期间锁表(FLUSH TABLES WITH READ LOCK),业务写入阻塞;加了则靠 MVCC 快照保证一致性,不影响线上写入。
常见错误现象:mysqldump 执行时应用报 “Lock wait timeout exceeded”,或监控看到大量 Waiting for table flush 状态。
- 仅对 InnoDB 有效,MyISAM 表仍会锁表,需搭配
--lock-tables=false+--skip-lock-tables(但一致性无法保障) - 若实例启用了
read_only=ON或账号无RELOAD权限,--single-transaction会静默失效,转为默认锁表行为——务必检查备份日志里是否出现Warning: Using a password on the command line interface can be insecure之后紧跟着的锁表提示 - 大事务运行中执行 dump 可能触发 long rollback,建议避开业务高峰或先查
SELECT TRX_ID, TRX_STARTED FROM INFORMATION_SCHEMA.INNODB_TRX
增量备份只能靠 binlog 吗?
是。MySQL 自身不提供类似 PostgreSQL 的 WAL 归档或 Oracle 的归档日志打包机制,mysqldump 是纯逻辑工具,不产生增量文件。所谓“增量备份”实际是:全量备份 + 持续收集并保留 binlog 文件。
使用场景:恢复到某秒级时间点(PITR),或缩小恢复窗口。
- 必须开启
log_bin=ON,且确认binlog_format=ROW(语句模式在跨版本/函数调用时易出错) - 定期用
mysqlbinlog --base64-output=DECODE-ROWS -v抽样检查 binlog 内容,避免因expire_logs_days过早清理导致断链 - 不要依赖
mysqlbinlog --stop-datetime直接恢复——它可能停在事务中间。正确做法是先用mysqlbinlog --start-position定位到全量备份结束位置(从mysqldump输出的CHANGE MASTER TO行提取),再按 position 截取
mysqldump 备份脚本里最容易漏掉的三个参数
漏掉它们不会让命令失败,但会让备份不可靠或难恢复。
-
--routines:不加则存储过程、函数不进备份,恢复后得手动重建 -
--events:事件调度器里的定时任务默认不导出 -
--set-gtid-purged=OFF:在 GTID 模式下,不加这个会强制写入SET @@GLOBAL.GTID_PURGED,若目标实例已有不同 GTID 集合,导入直接报错ERROR 1840 (HY000)
顺带一提:--databases 和 --all-databases 不是等价的——前者导出含 CREATE DATABASE 语句,后者不含,恢复时若库不存在会失败。
备份文件压缩与校验怎么做才不翻车?
直接 gzip 压缩没问题,但别跳过校验。很多团队用 mysqldump | gzip > backup.sql.gz 一气呵成,结果某天发现 gzip 过程被 kill,文件损坏却没报警。
- 先生成未压缩 SQL,用
head -20看是否含CREATE TABLE或INSERT INTO,再 gzip —— 避免管道中断导致空文件 - 压缩后立即跑
gunzip -t backup.sql.gz,成功才删原文件 - 加个简单校验:备份末尾追加
echo "CHECKSUM: $(sha256sum backup.sql.gz | cut -d' ' -f1)" >> backup.sql.gz(注意别破坏 gzip 格式,应写入独立行,解压时忽略)
真正麻烦的是跨机房传输后的 silent corruption:gzip 校验通过,但磁盘坏道导致部分 block 读错。所以生产环境至少保留两份物理隔离的副本,别只信一个 NFS 挂载点。











