利用innodb_force_recovery 解决MySQL服务器crash无法重启问题

本文介绍了MySQL因磁盘阵列损坏导致crash后的错误信息分析,通过调整innodb_force_recovery参数来绕过恢复过程,实现数据导出并重建数据库的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 背景

   某一创业的朋友的主机因为磁盘阵列损坏机器crash,重启MySQL服务时 报如下错误:


InnoDB: Reading tablespace information from the .ibd files...
 
InnoDB: Restoring possible half-written data pages from the doublewrite

InnoDB: buffer...

InnoDB: Doing recovery: scanned up to log sequence number 9120034833

150125 16:12:51 InnoDB: Starting an apply batch of log records to the database...

InnoDB: Progress in percents: 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 150125 16:12:51 [ERROR] mysqld got signal 11 ;

This could be because you hit a bug. It is also possible that this binary

or one of the libraries it was linked against is corrupt, improperly built,

or misconfigured. This error can also be caused by malfunctioning hardware.

To report this bug, see http://kb.askmonty.org/en/reporting-bugs

We will try our best to scrape up some info that will hopefully help

diagnose the problem, but since we have already crashed, 

something is definitely wrong and this may fail.

Server version: 5.5.37-MariaDB-log

key_buffer_size=268435456

read_buffer_size=1048576

max_used_connections=0

max_threads=1002

thread_count=0

It is possible that mysqld could use up to 

key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = 2332093 K bytes of memory

41 Hope that. 

二 分析
    主要关注 mysqld got signal 11 的问题,从日志内容分析来看,数据库在机器crash 导致日志文件损坏,重启之后无法正常恢复,更无法正常对外提供服务。

三 解决
    因为日志已经损坏,这里采用非常规手段,首先修改innodb_force_recovery参数,使mysqld跳过恢复步骤,将mysqld 启动,将数据导出来然后重建数据库。
innodb_force_recovery可以设置为1-6,大的数字包含前面所有数字的影响。
  1. (SRV_FORCE_IGNORE_CORRUPT):忽略检查到的corrupt页。
  2. (SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程需要执行full purge操作,会导致crash。
  3. (SRV_FORCE_NO_TRX_UNDO):不执行事务回滚操作。
  4. (SRV_FORCE_NO_IBUF_MERGE):不执行插入缓冲的合并操作。
  5. (SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存储引擎会将未提交的事务视为已提交。
  6. (SRV_FORCE_NO_LOG_REDO):不执行前滚的操作。
注意 
  a 当设置参数值大于0后,可以对表进行select,create,drop操作,但insert,update或者delete这类操作是不允许的。
  b 当innodb_purge_threads 和 innodb_force_recovery一起设置会出现一种loop现象:  
 



150125 17:07:42 InnoDB: Waiting for the background threads to start
 
150125 17:07:43 InnoDB: Waiting for the background threads to start

150125 17:07:44 InnoDB: Waiting for the background threads to start

150125 17:07:45 InnoDB: Waiting for the background threads to start

150125 17:07:46 InnoDB: Waiting for the background threads to start

150125 17:07:47 InnoDB: Waiting for the background threads to start 

在my.cnf中修改以下两个参数
innodb_force_recovery=6
innodb_purge_thread=0


重启MySQL 



150125 17:10:47 [Note] Crash recovery finished.
 
150125 17:10:47 [Note] Server socket created on IP: '0.0.0.0'.

150125 17:10:47 [Note] Event Scheduler: Loaded 0 events

150125 17:10:47 [Note] /vdata/webserver/mysql/bin/mysqld: ready for connections.

Version: '5.5.37-MariaDB-log' socket: '/tmp/mysql.sock' port: 3306 Source distribution 

立即对数据库做逻辑导出 ,完成之后将innodb_force_recovery设置为0 ,innodb_purge_thread=1 ,然后重建数据库 。
另外 MySQL 版本 5.5以及之前 ,当innodb_purge_threads =1,innodb_force_recovery >1 的情况会出现上文提到的循环报warning 问题(=1 没有问题),
原因:
MySQL 的源代码中显示  当innodb_purge_threads 和 innodb_force_recovery一起设置会出现loop循环


while (srv_shutdown_state == SRV_SHUTDOWN_NONE) { 
 
      if (srv_thread_has_reserved_slot(SRV_MASTER) == ULINT_UNDEFINED 

          || (srv_n_purge_threads == 1 

          && srv_thread_has_reserved_slot(SRV_WORKER) 

          == ULINT_UNDEFINED)) { 

          ut_print_timestamp(stderr); 

          fprintf(stderr, " InnoDB: Waiting for the background threads to start\n"); 
          os_thread_sleep(1000000); 

      } else { 

          break; 

      } 

  } 

所以当需要设置innodb_force_recovery>1的时候需要关闭 innodb_purge_threads,设置为0(默认)。

四 小结 
   MySQL crash 或者 MySQL 数据库服务器 crash 会导致各种各样的问题 ,比如主备之间的 error 1594 (5.6 版本开启 crash-safe ,会最大程度上避免 error 1594的问题,以后会写5.6新特性介绍该功能 ), error 1236, 日志损坏数据文件损坏 ,等等,本案例只是其中的一种,细心从日志中找的相关错误提示,逐步解决即可。


iot-database | 2025-07-04T08:35:21.579433Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority(). iot-database | 2025-07-04T08:35:21.591130Z 0 [ERROR] [FATAL] InnoDB: Table flags are 0 in the data dictionary but the flags in file ./ibdata1 are 0x4800! iot-database | 2025-07-04 08:35:21 0x7fb876c66880 InnoDB: Assertion failure in thread 140430243424384 in file ut0ut.cc line 921 iot-database | InnoDB: We intentionally generate a memory trap. iot-database | InnoDB: Submit a detailed bug report to http://bugs.mysql.com. iot-database | InnoDB: If you get repeated assertion failures or crashes, even iot-database | InnoDB: immediately after the mysqld startup, there may be iot-database | InnoDB: corruption in the InnoDB tablespace. Please refer to iot-database | InnoDB: http://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html iot-database | InnoDB: about forcing recovery. iot-database | 08:35:21 UTC - mysqld got signal 6 ; iot-database | This could be because you hit a bug. It is also possible that this binary iot-database | or one of the libraries it was linked against is corrupt, improperly built, iot-database | or misconfigured. This error can also be caused by malfunctioning hardware. iot-database | Attempting to collect some information that could help diagnose the problem. iot-database | As this is a crash and something is definitely wrong, the information iot-database | collection process might fail.
最新发布
07-05
<think>我们面对的是一个MySQL容器启动失败的问题,错误日志显示InnoDB存储引擎在启动过程中遇到了严重错误。 关键错误信息: [ERROR] [FATAL] InnoDB: Table flags are 0 in the data dictionary but the flags in file ./ibdata1 are 0x4800! 随后触发了断言失败,导致mysqld进程崩溃(signal 6)。 问题分析: 1. 错误原因:InnoDB数据字典(存储在系统表空间文件ibdata1中)的表标志(table flags)与内存中的数据字典不匹配。 2. 可能场景: - 数据文件损坏(可能是由于不正常的关机、磁盘故障等) - MySQL版本升级或降级后,数据文件格式不兼容 - 在复制或移动数据文件时出现了问题 解决方案: 根据MySQL官方文档(参考链接:https://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html), 我们可以尝试通过强制恢复模式启动MySQL来修复。 具体步骤: 步骤1:在my.cnf配置文件中设置强制恢复模式 - 在[mysqld]部分添加配置:innodb_force_recovery = N (N的取值从1到6,逐级提高) - 建议从1开始尝试,如果无法启动则逐步增加,直到能启动为止 步骤2:启动MySQL并导出数据 - 在恢复模式下启动后,MySQL处于只读状态,需要立即备份数据库 - 使用mysqldump导出所有数据 步骤3:重建数据目录 - 删除原有数据目录(包括ibdata1, ib_logfile*等文件) - 重新初始化MySQL,然后导入备份的数据 步骤4:移除恢复模式配置并正常启动 在Docker环境中的操作示例: 1. 修改docker-compose.yml,在环境变量或配置文件中设置恢复模式: ```yaml environment: - MYSQL_ROOT_PASSWORD=Qinyu456 # 添加恢复模式环境变量(对应my.cnf中的配置) - MYSQL_INNODB_FORCE_RECOVERY=1 ``` 或者通过挂载自定义配置文件: ```yaml volumes: - ./custom-my.cnf:/etc/mysql/conf.d/custom-my.cnf ``` 在custom-my.cnf中写入: ```ini [mysqld] innodb_force_recovery=1 ``` 2. 启动容器并尝试导出数据: ```bash docker exec -it iot-database mysqldump -u root -p --all-databases > full_backup.sql ``` 3. 停止容器,删除数据卷(或清空数据目录): ```bash docker-compose down sudo rm -rf ./db-data/* ``` 4. 移除恢复模式配置(删除环境变量或配置文件中的设置),重新启动容器。 5. 导入备份数据: ```bash docker exec -i iot-database mysql -u root -p < full_backup.sql ``` 注意事项: - 强制恢复模式级别说明: 1 (SRV_FORCE_IGNORE_CORRUPT): 忽略损坏的页 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): 不进行前滚恢复 - 在恢复模式下,只能进行SELECT(级别1-3)或只读操作(级别4以上),不能进行DDL操作。 如果以上方法无法恢复,可能需要从备份中恢复数据,或者使用专业的数据恢复工具。 §§相关问题§§ 1. 如何判断InnoDB数据文件损坏的具体原因? 2. 在Docker环境中,如何安全地删除MySQL数据卷并重新初始化? 3. 除了强制恢复模式,还有哪些方法可以修复损坏的InnoDB表? 4. 如何配置MySQL的定期备份策略以防止数据丢失? 5. 在Kubernetes环境中如何实现MySQL数据卷的自动备份和恢复?</think>### MySQL容器因InnoDB文件损坏崩溃的解决方案 #### 错误分析: 日志显示核心错误: ```log [ERROR] [FATAL] InnoDB: Table flags are 0 in the data dictionary but the flags in file ./ibdata1 are 0x4800! ``` 这表明 **InnoDB系统表空间文件(ibdata1)损坏**,常见原因包括: 1. **异常关机**:容器被强制终止导致数据未刷盘 2. **磁盘空间不足**:写操作中断导致文件损坏 3. **版本升级问题**:MySQL版本变更后数据文件不兼容 4. **硬件故障**:底层存储设备问题 --- ### 修复步骤: #### 1. 强制恢复模式启动 修改配置文件 `my.cnf`: ```ini [mysqld] innodb_force_recovery = 4 # 恢复级别1-6,从低到高尝试 ``` - 级别1:忽略损坏页 - 级别4:禁止回滚日志 - 级别6:禁用redo日志 #### 2. 数据备份(只读模式) 启动容器后立即备份: ```bash docker exec iot-database mysqldump -u root -p --all-databases > full_backup.sql ``` #### 3. 重建数据目录 ```bash # 停止容器 docker-compose down # 重命名损坏目录(保留原始文件) mv ./db-data ./db-data-corrupted # 创建新目录 mkdir ./db-data && chown 999:999 ./db-data ``` #### 4. 恢复数据 ```bash # 启动新容器 docker-compose up -d # 导入备份 docker exec -i iot-database mysql -u root -p < full_backup.sql ``` --- ### 预防措施: 1. **启用双写缓冲**(MySQL 8.0默认开启): ```ini innodb_doublewrite = ON ``` 2. **定期验证数据文件**: ```bash docker exec iot-database mysqlcheck -u root -p --all-databases --check ``` 3. **配置崩溃安全写入**: ```yaml # docker-compose.yml environment: - INNODB_FLUSH_METHOD=O_DIRECT - INNODB_FLUSH_LOG_AT_TRX_COMMIT=1 ``` 4. **使用数据卷备份**: ```bash # 每日快照备份 tar -czvf mysql-backup-$(date +%F).tar.gz ./db-data ``` --- ### 损坏文件分析工具: ```mermaid graph LR A[损坏文件] --> B[innochecksum] A --> C[ibd2sdi] A --> D[MySQL Utilities] B --> E[验证页校验和] C --> F[提取元数据] D --> G[可视化分析] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值