xtrabackup备份后不能直接cp回数据目录启动,因备份默认非一致,含脏页、未提交事务和不完整redo log,须先执行xtrabackup --prepare应用日志并回滚事务,使备份达一致性状态,否则启动失败。

为什么 xtrabackup 备份后直接 cp 回数据目录起不来?
因为 xtrabackup 的物理备份默认是“非一致性”的——它在拷贝过程中 MySQL 仍在写入,所以备份文件里有未刷盘的脏页、未提交的事务、甚至不完整的 redo log。直接替换数据目录会导致实例启动失败,常见报错是 InnoDB: Database page corruption 或 mysqld: unknown variable 'innodb_log_checksums'(版本不匹配时)。
必须执行 xtrabackup --prepare 才能完成崩溃恢复模拟,把 redo log 应用到数据文件,回滚未提交事务,让备份达到“一致性状态”。
-
--prepare是必做步骤,不能跳过;生产环境建议加--apply-log-only做增量合并时用 - 如果备份时用了
--no-timestamp,--prepare要指定完整备份路径,例如:xtrabackup --prepare --target-dir=/backup/full_20240501 - MySQL 8.0+ 默认启用
innodb_log_checksums=ON,但老版本备份在新版本上--prepare会失败,需加--use-memory=2G和--innodb-log-checksums=OFF(仅限兼容性临时绕过)
恢复时要不要停 MySQL?mysqld 必须完全停止
物理恢复本质是替换整个 datadir 下的文件,MySQL 运行时会锁住 ibdata1、ib_logfile* 等关键文件,哪怕只读也不行。强行覆盖会导致文件句柄残留、元数据损坏,后续启动必然报错 Operating system error number 2 in a file operation。
正确做法是:先 systemctl stop mysqld(或 kill -15 $(cat /var/run/mysqld/mysqld.pid)),确认进程消失、端口释放,再清空目标 datadir(别只删表空间!要删干净 ibdata1、ib_logfile*、mysql/ 系统库等)。
- 清空前务必确认
my.cnf中datadir路径和你要恢复的目标路径一致 - 恢复命令用
xtrabackup --copy-back --target-dir=/backup/full_20240501,不是cp -r - 恢复后要改属主:
chown -R mysql:mysql /var/lib/mysql,否则启动报Can't start server : Bind on unix socket
xtrabackup 备份时加了 --stream=tar,怎么还原?
流式备份不会落地为目录结构,而是输出到 stdout,常配合压缩和远程传输,比如:xtrabackup --backup --stream=tar ./ | gzip > backup.tar.gz。这种备份不能直接 --prepare,必须先解包还原出原始备份目录结构。
还原步骤分两步:先解压出完整备份树,再走标准 prepare + copy-back 流程。
- 解包命令:
gunzip (<code>-i表示忽略 tar header 中的 uid/gid,避免权限问题) - 解包后检查:
/tmp/xb-restore下应有xtrabackup_checkpoints、backup-my.cnf、mysql/等,否则说明流式过程出错 - 注意:流式备份不包含
my.cnf,恢复时要用原环境的配置,尤其确认innodb_page_size、innodb_log_file_size是否与备份时一致
MySQL 8.0 的 data_dictionary 表空间能被 xtrabackup 正确处理吗?
可以,但仅限 xtrabackup 8.0+ 版本(对应 Percona XtraBackup 8.0.x)。旧版(如 2.4)无法识别 8.0 新增的 mysql.ibd 和数据字典表空间,恢复后会卡在 Starting crash recovery... 或报 Tablespace is missing for table mysql/innodb_table_stats。
关键点在于:XtraBackup 版本必须与 MySQL 主版本严格对齐。8.0.33 的 MySQL 就得用 XtraBackup 8.0.33,混用 8.0.30 或 2.4 都可能失败。
- 验证方式:
xtrabackup --version输出必须含based on MySQL server 8.0.xx - 备份时若看到警告
Ignoring table mysql.* because it's managed by data dictionary,说明版本不匹配,立刻停用 - 8.0 的
mysql.ibd是只读的,--prepare会自动跳过它,但copy-back仍需确保目标目录下没有残留的旧mysql/子目录
恢复最难的不是操作步骤,是判断备份是否真正可用——--prepare 成功不代表能启动,copy-back 成功也不代表数据可查。最常被跳过的验证动作是:启动后连上去执行 SELECT COUNT(*) FROM mysql.user; 和 SHOW ENGINE INNODB STATUS\G 看有没有 UNDO LOG 错误。


















