在要求输入邮箱的文本域,请填写真实的邮件地址。非真实邮件地址,将收不到回复信息。

MYSQL InnoDB引擎日志表损坏修复

MySql 清风 752℃ 0评论

背景

客户发消息说系统突然登录不上,验证码都出不来。当看到这个消息的时候觉得应该挺简单的,觉得大概率是应用程序挂了,决定临时使用重《重启》大法。登录应用服务进行查看发现服务在重启中,尝试重启也无效,就查看了相关日志发现是MySQL服务连接不上了。接下来就只能看下MySQL 服务出现什么问题并想办法尝试解决。

问题

登录MySQL服务器发现服务在启动中并且一直处于这个状态。停止服务MYSQL服务并尝试重启,问题依然存在。MYSQL的状态一直就是这个Server startup in progress,如下所示:


mysqld.service – MySQL Server
Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Wed 2024-05-29 13:57:58 CST; 2s ago
Docs: man:mysqld(8)
http://dev.mysql.com/doc/refman/en/using-systemd.html
Process: 1849957 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
Process: 1849986 ExecStart=/usr/sbin/mysqld $MYSQLD_OPTS (code=exited, status=2)
Main PID: 1849986 (code=exited, status=2)
Status: “Server startup in progress”
mysql服务启动失败

通过以上错误内容来看,疑似MySQL 配置参数出现问题,再通过了解得知客户并没有修改任何参数,这样由MySQL配置导致的原因几乎不太可能。这样的话只能通过MySQL的日志文件来看一看,能否发现有用的信息。找到MySQL日志文件mysqld.log,发现此文件非常大,57G多。嗯!文件大也没有办法的,也得下载来看看。

日志下载完成后就发现了相关问题,MySQL日志文件错误内容显示如下:


2024-05-29T13:24:15.276510Z 0 [ERROR] [MY-011971] [InnoDB] Tablespace ‘innodb_undo_002’ Page [page id: space=4294967278, page number=555] log sequence number 13653079935 is in the future! Current system log sequence number 13649029879.
2024-05-29T13:24:15.276563Z 0 [ERROR] [MY-011972] [InnoDB] Your database may be corrupt or you may have copied the InnoDB tablespace but not the InnoDB log files. Please refer to http://dev.mysql.com/doc/refman/8.0/en/forcing-innodb-recovery.html for information about forcing recovery.
2024-05-29T13:24:15.276576Z 0 [ERROR] [MY-011971] [InnoDB] Tablespace ‘innodb_undo_002’ Page [page id: space=4294967278, page number=524] log sequence number 13652559170 is in the future! Current system log sequence number 13649029879.
2024-05-29T13:24:15.276604Z 0 [ERROR] [MY-011971] [InnoDB] Tablespace ‘innodb_undo_002’ Page [page id: space=4294967278, page number=433] log sequence number 13654464601 is in the future! Current system log sequence number 13649029879.
MYSQL InnoDB引擎日志表损坏修复-第1张图片

引起以上问题的原因可能存在以下几种:

  • 异常关机,例如:断电、强行关机
  • MySQL服务被强行终止

无论是何种原因,问题最终还是要解决。

解决方案

根据上述错误内容以及互联网经验来看,需要恢复备份数据来解决。使用备份数据来恢复?使用时不可能使用的,不要问为什么不用备份数据,不是没有,是时间间隔比较长,之前的备份数据只能作为最后的备选方案。

在没有最近的备份数据的时候,需要将数据进行导出后再导入来解决,尝试导出数据有一个前提,那就是需要把MySQL服务先正常启动。根据提示/etc/my.cnf 配置文件中[mysqld]节点下新增innodb_force_recovery参数来尝试启动。

仅在紧急情况下将 innodb_force_recovery 设置为大于 0 的值,以便 可以启动和转储表。以前 这样做时,请确保在 如果您需要重新创建它。值为 4 或更大时,可以 永久损坏的数据文件。仅使用innodb_force_recovery设置 在生产服务器实例上达到 4 或更大 已成功在单独的物理副本上测试了该设置 您的数据库。强制恢复时, 您应该始终从 innodb_force_recovery=1 开始,并且 仅根据需要逐步增加该值。

innodb_force_recovery0 默认值(正常启动,不强制恢复)。允许的 innodb_force_recovery 的非零值为16。 较大的值包括较小值的功能。例如,值3包括值的所有功能12

如果能够转储innodb_force_recovery值为3或者更少,那么你就相对安全了,只有一些数据 损坏的单个页面丢失。值为4或更大为被认为是危险的,因为数据文件可能是永久性的 损坏。值6被认为是巨大的,因为数据库页面处于过时状态,这反过来可能会引入对B-Tree和其他数据库结构的更多损坏。

作为一项安全措施,当innodb_force_recovery更大时,可防止 INSERTUPDATE DELETE 操作。

  • 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)
    • 防止插入 缓冲区合并操作。如果它们会导致崩溃, 不做他们。不计算表统计信息。此值 可能会永久损坏数据文件。使用此值后,是 准备删除并重新创建所有二级索引。设置为只读。
  • 5 (SRV_FORCE_NO_UNDO_LOG_SCAN)
    • 不看撤消 启动数据库时的日志:甚至处理未完成的事务 如承诺。此值可能会永久损坏数据文件。 设置为只读。
  • 6 (SRV_FORCE_NO_LOG_REDO)
    • 不执行与恢复相关的重做日志前滚。此值可以 永久损坏的数据文件。将数据库页保留在 过时的状态,这反过来可能会带来更多的腐败 变成 B 树和其他数据库结构。设置为只读。

依次尝试使用1234作为参数innodb_force_recovery的值均启动失败,此时有一种非常不妙的感觉。终于在尝试5的时候MySQL成功启动,此时才有一种庆幸的感觉,终究还是给了个机会。参数innodb_force_recovery配置示例如下:


[mysqld]
user=mysql
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
lower_case_table_names = 1 # 不区分大小写
sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO'
default-time_zone = '+8:00'
max_connections= 8000
max_user_connections= 10000
max_connect_errors= 4000
local_infile= ON
innodb_force_recovery=5

MySQL强制恢复参数设置,服务启动成功

接下来就需要将数据导出,使用MySQL自带的mysqldump导出数据库。


mysqldump -u账号 -p密码  -p3306 数据库名称> 保存文件名.sql

示例:


mysqldump -uroott -p123456  -p3306 mydata> mydata_bak.sql

接下来需要对MySQL数据库进行重新初始化,初始化需要进行如下步骤:

  • 备份mysql数据目录(以防备用)
  • 彻底删除mysql数据目录
  • 重新修改/etc/my.cnf配置文件,增加记录binlog,去掉innodb_force_recovery或置为0
  • 执行命令重新初始化mysql

MySQL初始化命令如下:


mysqld --initialize --user=mysql

mysql的数据目录权限需要是mysql:mysql

导出MySQL 数据内容

数据库初始化完毕以后,需要修改掉初始密码,再导入备份的数据内容。手动创建各个数据库,然后通过命令导入各数据库。


mysql -u用户名 -p密码 数据库名称 < 备份数据文件.sql

示例:

mysql -uroot -p123456 mydata < mydata_bak.sql
可能还需要手动加回原来需要的mysql用户名,并授权访问各个库的权限。

总结

生产环境最好要做定时备份,以防止意外情况发生。关机最好避免强制关机或者切断电源,虚拟机器避免强制挂起或者强制关机。这个客户没有对数据进行备份,负责实施的同事也没有设置定时备份,今后还是要避免这种请款的发生。



转载请注明:清风亦平凡 » MYSQL InnoDB引擎日志表损坏修复

喜欢 (0)or分享 (0)
支付宝扫码打赏 支付宝扫码打赏 微信打赏 微信打赏
头像
发表我的评论
取消评论

CAPTCHA Image
Reload Image
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址