mysqldump 无法导出所有数据

环境

环境:docker、mysql 5.7

使用 mysqldump 备份数据库,总是在备份到 16G 的时候备份失败,去 /var/log/mysql 中并没有找到相关的错误日志。通过 docker ps 发现 mysql 发生了重启,通过 docker logs 查看到了 mysql 的崩溃日志,如下:

错误日志

1
2
3
2022-02-11T09:01:21.513263Z 0 [ERROR] InnoDB: Database page corruption on disk or a failed file read of page [page id: space=54, page number=1318229]. You may have to recover from a backup.
2022-02-11T09:01:21.513283Z 0 [Note] InnoDB: Page dump in ascii and hex (16384 bytes):
len 16384; hex 265ed70a00141d5500141d5400141d5600000009e6f96ad345bf00000000000000000000003600033a80800b00000000339a0002000800090000000000000000000000000000000000380000000000000000000000000000000000000000010002001f696e66696d756d0006000b000073757072656d756d2639fa9d420000101e9c0122d29300000000446bbc00000a4425ca010122da349990b743de8000000000483c703e49276d2074727969

关键信息:
InnoDB:磁盘上的数据库页面损坏,或页面[page id:space=54,page number=1318229]的文件读取失败。您可能需要从备份中恢复。

原因可能是最近的虚拟机环境重设,然后多次 copy 了 mysql docker volume 的文件,在 copy 过程中文件发生了损坏。

解决方案

设置 my.cnf 的 innodb_force_recovery=1,然后重启 mysql,再次运行 mysqldump,发现可以正常导出数据。

innodb_force_recovery 参数的详细解释:

Mysql 文档-Forcing InnoDB Recovery

innodb_force_recovery 取值范围 1-6:

1 (srv_force_ignore_corrupt)

让服务器运行,即使它检测到一个损坏的页面。试图使SELECT * FROM tbl_name跳过损坏的索引记录和页面,这有助于转储表。

2 (srv_force_no_background)

防止主线程和任何清除线程的运行。如果在清除操作中会发生意外退出,这个恢复值可以防止它。

3 (srv_force_no_trx_undo)

在崩溃恢复后不运行事务回滚。

4 (srv_force_no_ibuf_merge)

防止插入缓冲区的合并操作。如果它们会导致崩溃,则不做这些操作。不计算表的统计数据。这个值会永久地破坏数据文件。在使用这个值之后,要准备放弃并重新创建所有的二级索引。将InnoDB设置为只读。

5 (srv_force_no_undo_log_scan)

在启动数据库时不查看撤销日志。InnoDB甚至将不完整的事务视为已提交。这个值会永久地破坏数据文件。将InnoDB设置为只读。

6 (srv_force_no_log_redo)

不做与恢复有关的重做日志滚动。这个值会永久地破坏数据文件。使数据库页面处于过时的状态,这反过来又可能给B树和其他数据库结构带来更多的损坏。将InnoDB设置为只读。