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

本文针对MySQL服务器因磁盘阵列损坏导致crash的情况,详细介绍了如何通过调整innodb_force_recovery参数来绕过恢复过程,实现数据导出及数据库重建的方法。

背景
      MySQL服务器因为磁盘阵列损坏机器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, 日志损坏,数据文件损坏 ,等等,本案例只是其中的一种,细心从日志中找的相关错误提示,逐步解决即可。

转载于:https://www.cnblogs.com/vadim/p/7380654.html

<think>我们正在处理用户关于MySQL 8.4.5在异常重启后执行InnoDB初始化导致数据丢失的问题。用户还希望确认当前配置是否正确。根据之前的对话历史,用户已经遇到了初始化后数据库丢失的问题,并且我们给出了一系列的排查步骤。现在用户的问题更具体:在异常重启后,执行初始化导致数据丢失,以及配置检查。 根据引用内容,我们可以提取以下有用信息: 引用[1]:提到了InnoDB缓冲池参数的设置注意事项,包括`innodb_buffer_pool_size`和`innodb_buffer_pool_instances`,以及它们对性能的影响和设置建议。还提到了在MySQL 8.0中引入的`innodb_buffer_pool_chunk_size`。 引用[2]:提供了问题描述和解决方案的框架,包括修正系统时间、检查数据目录完整性、重新初始化数据目录和调整MySQL配置等步骤。 引用[3]:在Windows下安装MySQL 8.4.5的教程,其中提到使用`--initialize-insecure`初始化会生成空密码,并自动生成Data文件夹。 引用[4]:在TencentOS中安装MySQL 8.0.42的步骤,包括编译部署、初始化数据库和启动数据库。 用户当前的问题:异常重启后执行初始化导致数据丢失。这里需要明确的是,初始化(initialize)操作通常是在首次安装或者需要重建数据目录时才执行的操作。如果用户在生产环境中异常重启后执行了初始化,那么这很可能是数据丢失的原因,因为初始化会重建系统表空间和系统数据库,覆盖原有数据。 因此,我们需要向用户解释: 1. 初始化操作(mysqld --initialize)的用途:它应该在第一次安装MySQL或者需要重新创建数据目录时使用,而不是在异常重启后恢复时使用。 2. 异常重启后,正确的恢复步骤应该是直接启动MySQL服务(因为InnoDB有崩溃恢复机制),而不是执行初始化。 3. 如果用户错误地在异常重启后执行了初始化,那么数据目录会被覆盖,导致数据丢失。此时,如果没有备份,数据可能难以恢复。 同时,我们需要检查用户当前的配置,特别是与InnoDB崩溃恢复相关的配置,确保在异常重启后能够自动进行恢复。 解决方案: 1. 确认是否误执行了初始化:检查错误日志,看是否有初始化的记录,以及初始化之前的数据目录状态。 2. 如果已经执行了初始化并且覆盖了数据,尝试从备份中恢复数据。 3. 如果没有备份,尝试使用数据恢复工具(如undrop-for-innodb)来恢复,但成功率不高。 4. 配置检查:确保InnoDB的配置能够支持崩溃恢复,特别是以下参数: - `innodb_force_recovery`: 通常设置为0(正常启动),如果无法启动,可以尝试设置为1-6,但只能用于导出数据,不能长期运行。 - `innodb_fast_shutdown`: 设置为0、1或2,默认1。在崩溃后启动时,MySQL会自动进行恢复。 5. 预防措施:设置正确的配置,避免误操作。 详细步骤: 步骤1:确认问题原因 - 查看MySQL错误日志(通常在数据目录下,文件名为hostname.err,或者通过`show variables like 'log_error';`查询),寻找在异常重启后是否有初始化操作的记录。初始化操作会在日志中留下“Initialization of mysqld complete”等类似信息。 - 如果发现确实执行了初始化,那么数据丢失是因为初始化重建了数据目录。 步骤2:数据恢复尝试 - 如果用户有备份(物理备份或逻辑备份),则使用备份恢复。 - 如果没有备份,且数据非常重要,可以尝试使用数据恢复工具(如undrop-for-innodb)来恢复被覆盖的数据文件,但注意:初始化已经覆盖了原来的ibdata1和系统表空间,恢复难度很大。 步骤3:配置检查 - 检查MySQL配置文件(my.cnf或my.ini)中关于InnoDB的配置,确保以下参数设置合理: innodb_buffer_pool_size = 系统内存的50%-70% [^1] innodb_buffer_pool_instances = 建议设置为innodb_buffer_pool_size除以1GB(但不能超过64) [^1] innodb_log_file_size:通常设置为缓冲池大小的25%左右,但不超过2GB(在MySQL 8.0中,可以动态调整,但需要正确操作) innodb_flush_log_at_trx_commit = 1 # 保证事务持久性,但会降低性能。如果对数据安全性要求高,保持为1。 sync_binlog = 1 # 保证二进制日志的持久性 innodb_force_recovery = 0 # 正常启动,崩溃恢复时自动进行恢复 - 另外,确保数据目录(datadir)的权限正确,MySQL用户有读写权限。 步骤4:预防措施 - 避免在异常重启后执行初始化操作。正确的恢复步骤是直接启动MySQL服务,因为InnoDB有崩溃恢复机制(通过重做日志redo log进行前滚,未提交的事务通过undo log回滚)。 - 定期备份数据(物理备份和逻辑备份)。 - 设置监控,当MySQL服务异常停止时,能够通知管理员手动处理,而不是盲目执行初始化。 步骤5:后续操作 - 如果数据已经丢失且无法恢复,只能重新初始化并重建数据库(注意:这次初始化是必要的,因为之前的数据已经被覆盖)。然后从备份中恢复数据,或者重新构建。 关于配置正确性的检查,我们可以给出一个配置片段示例: 示例配置(my.cnf): ``` [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock # InnoDB settings innodb_buffer_pool_size = 4G # 根据实际内存调整 innodb_buffer_pool_instances = 4 # 如果buffer pool size是4G,则设置为4(4G/1G=4) innodb_log_file_size = 1G # 注意:修改此参数需要先停止MySQL,删除旧的日志文件,再启动 innodb_flush_log_at_trx_commit = 1 sync_binlog = 1 ``` 注意:在修改配置后,需要重启MySQL服务(除了动态参数)。 最后,强调一点:初始化操作(mysqld --initialize)只能在安装或明确需要重建数据目录时使用,不能作为恢复数据库的手段。 相关问题: 1. 如何正确配置InnoDB缓冲池以提高性能? 2. MySQL异常重启后,正确的恢复步骤是什么? 3. 如何设置MySQL的自动备份策略? 4. 如何监控MySQL的崩溃恢复过程?</think>### MySQL 8.4.5 InnoDB 异常重启后初始化导致数据丢失的解决方案 #### 问题核心原因分析 当 MySQL 8.4.5 在异常重启后执行 InnoDB 初始化(`mysqld --initialize`)导致数据丢失时,根本原因通常是: 1. **初始化操作覆盖数据目录** `--initialize` 会重建系统表空间(`ibdata1`)和系统数据库,**覆盖原有数据文件**(引用[3])。 $$ \text{初始化命令} \rightarrow \text{新建 } \texttt{ibdata1} + \texttt{ib\_logfile} \rightarrow \text{覆盖原数据} $$ 2. **异常重启破坏事务一致性** InnoDB 依赖重做日志(redo log)保证崩溃恢复。若异常重启导致日志损坏,MySQL 可能无法自动恢复(引用[4])。 3. **配置错误引发二次故障** 关键参数(如 `datadir` 路径、缓冲池设置)配置不当会加剧问题(引用[1][2])。 --- ### 一、紧急数据恢复步骤 #### 场景 1:已执行初始化但未覆盖磁盘 若数据目录未被完全覆盖(如 `ibdata1` 文件还存在旧数据): ```bash # 停止 MySQL 服务 sudo systemctl stop mysql # 备份当前数据目录(关键!) sudo cp -R /var/lib/mysql /var/lib/mysql_backup # 尝试崩溃恢复 sudo mysqld --innodb-force-recovery=6 --datadir=/var/lib/mysql_backup ``` - `innodb-force-recovery=6` 是最高恢复级别,强制 InnoDB 跳过损坏页(引用[2]) - 成功后立即用 `mysqldump` 导出数据 #### 场景 2:数据已被初始化覆盖 若已执行初始化且原数据被覆盖: 1. **尝试文件恢复工具** 使用 `extundelete` 或 `testdisk` 恢复被删除的文件: ```bash sudo extundelete /dev/sdX --restore-directory /var/lib/mysql ``` 2. **从备份恢复** 若有物理备份(如 `xtrabackup`): ```bash sudo innobackupex --copy-back /path/to/backup ``` > ⚠️ **注意**:初始化操作会重置 `root` 密码,新密码在错误日志中(引用[3])。 --- ### 二、当前配置正确性检查与修正 #### 1. 关键参数验证 检查 `/etc/mysql/my.cnf`: ```ini [mysqld] # 必须与实际数据目录一致 datadir = /var/lib/mysql # 缓冲池大小(建议系统内存的 50-70%) innodb_buffer_pool_size = 4G # 缓冲池实例数(= 缓冲池大小/1GB,上限64) innodb_buffer_pool_instances = 4 # 日志文件大小(建议缓冲池的 25%) innodb_log_file_size = 1G ``` - 使用公式验证:$\text{pool\_instances} = \min(64, \lfloor \frac{\text{buffer\_pool\_size}}{1\text{GB}} \rfloor)$(引用[1]) - 修改后**必须重启生效**:`sudo systemctl restart mysql` #### 2. 崩溃安全配置 ```ini # 保证事务持久性(默认1) innodb_flush_log_at_trx_commit = 1 # 双写缓冲防部分写(默认ON) innodb_doublewrite = ON # 崩溃恢复保护(MySQL 8.0+ 默认启用) innodb_redo_log_crash_safe = ON ``` #### 3. 权限与目录检查 ```bash # 确认数据目录所有权 sudo chown -R mysql:mysql /var/lib/mysql # 验证目录完整性 sudo mysqlcheck --all-databases --check-upgrade ``` --- ### 三、预防措施与最佳实践 1. **禁用危险操作** - 生产环境**严禁**使用 `--initialize` 恢复数据 - 异常重启后直接启动服务:`sudo systemctl start mysql` 2. **启用崩溃自动恢复** InnoDB 默认在启动时执行崩溃恢复: ```bash sudo mysqld --innodb-auto-recovery # 默认启用 ``` 3. **备份策略强化** ```bash # 每日物理备份(使用官方工具) mysqlbackup --backup-dir=/backups --user=root --password backup-and-apply-log ``` - 保留至少 7 天备份 - 定期验证备份可恢复性 4. **监控配置** 添加监控项: - InnoDB 崩溃恢复状态:`SHOW ENGINE INNODB STATUS` - 缓冲池利用率:`SELECT * FROM sys.metrics WHERE variable_name LIKE '%buffer_pool%'` > 💡 **重要**:MySQL 8.4.5 的 **Clone Plugin** 支持快速重建实例,优先于手动初始化(引用[4])。 --- ### 四、配置验证清单 执行以下 SQL 确认配置健康: ```sql -- 检查 InnoDB 状态 SHOW ENGINE INNODB STATUS\G -- 验证关键参数 SELECT VARIABLE_NAME, VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME IN ( 'innodb_buffer_pool_size', 'innodb_buffer_pool_instances', 'innodb_log_file_size', 'datadir' ); -- 检查未完成事务 SELECT * FROM information_schema.INNODB_TRX; ``` 正常输出应显示: - `innodb_buffer_pool_instances` 符合计算规则 - `datadir` 路径存在且可写 - `INNODB_TRX` 无长期未提交事务 --- ### 总结流程图 ```mermaid graph TD A[异常重启] --> B{自动崩溃恢复} B -- 成功 --> C[正常服务] B -- 失败 --> D[检查错误日志] D --> E[尝试innodb-force-recovery] E -- 成功 --> F[导出数据重建实例] E -- 失败 --> G[从备份恢复] G --> H[验证配置] H --> I[启用监控告警] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值