背景:
MySQL
page corruption通常会导致查询或者后台线程crash或者是甚至会导致innodb前滚恢复crash,这样的page corruption产生通常是由于数据库的意外事件,如:断电、强行kill等。在这种情况下,我们可以使用innodb_force_recovery选项强制InnoDB存储引擎启动,并阻止后台操作运行,以便我们导出表的数据。
参数值分析:
innodb_force_recovery共有七个值0-6
0(
normal startup without forced recovery ):这是默认值,即正常启动
1
(
SRV_FORCE_IGNORE_CORRUPT
):即使检测到脏页,仍然启动,启动后,在select * from table_name时,会尝试跳过损坏的索引页与数据页,方便我们dump;值得注意的是,该dump通常能保证数据的完整性,因为这里的损坏的页通常是我们不需要的。
2 (SRV_FORCE_NO_BACKGROUND):阻止master thread和purge thread的运行,如果mysql崩溃的原因是purge pages失败,那么设置为2会阻止purge线程启动,从而让mysqld启动;值得注意的是设置为innodb_force_recovery较高的值包含了较低值的所有功能,其实目的只有一个,就是要启动,dump出数据。
3 (SRV_FORCE_NO_TRX_UNDO) :阻止事物回滚,(innodb崩溃恢复过程中,要将active状态的事物回滚),同样这里包括了2、1的所有功能。
4
(
SRV_FORCE_NO_IBUF_MERGE
):阻止insert buffer merge操作,即阻止merge线程(这会产生永久的脏数据文件,当然insert buffer是对于二级索引而言的,我们当然可以重建索引),同样这里也会包括3、2、1的功能,从5.7.3开始,还会设置innodb为read_only。
5 (SRV_FORCE_NO_UNDO_LOG_SCAN) :终止undo log的扫描,把未提交的事物当成提交(innodb崩溃恢复过程中,要遍历undo log以便于重构事物),该操作会对数据文件做永久性改变,同样该操作也会包含4、3、2、1的功能,
从5.7.3开始,还会设置innodb为read_only。
6
(
SRV_FORCE_NO_LOG_REDO
) :阻止redo的前滚操作,该操作会对数据文件做永久性改变,同样改操作包含5、4、3、2、1的功能,
从5.7.3开始,还会设置innodb为read_only。
看了以上7个值的,或许你还不清楚,我们先来了解下MySQL的崩溃恢复流程,这里简单概括下:
1.获取MySQL的LSN,如果MySQL有多个日志文件,那就取文件中的最大值LSN
2.从LSN开始,APPLY BATCH redo;
3.
遍历系统所有的
Rollback Segment Header Page
,读取其中的
Undo Slot
指向的
Undo Log Header Page
来重构事物(recreate transaction)
4.删除未创建完成的索引,对于active状态的事物进行回滚
从这个恢复流程,我们可以看出,innodb_force_recovery是从崩溃恢复流程的四个阶段(注意顺序4->1)来阻止相关线程的动作来防止数据库起不来,最终的目的是为了让我们能导出数据。
恢复步骤:
1.通过递增设置innodb_force_recovery的值,直到能启动mysql。
为什么要递增设置?
从参数分析部分,我们可以看出来4-6对数据的完整性是有很大损坏的,值越小,完整性越能保证。
1-3我们基本能保证数据一致性,4我们可以通过重建索引,来保证一致性,而5-6则不行
2.用select * from table_name outfile...导出数据。
3.drop table table_name;
4.设置innodb_force_recovery=0,重新启动。
5.重新导入数据。
实战:
在一个数据库中,我模拟删除t12.ibd文件(这种情况在真事情况下也是存在,当trucate table 时,恰好mysql挂了,就会有.idb文件被删除的情况)
1.看一段启动日志
2017-03-29 23:37:40 7121 [Note] InnoDB: Reading tablespace information from the .ibd files...
2017-03-29 23:37:40 7121 [ERROR] InnoDB: Attempted to open a previously opened tablespace. Previous tablespace test/playerdiamond uses space ID: 1 at filepath: ./test/playerdiamond.ibd. Cannot open tablespace test/t12 which uses space ID: 1 at filepath: /datatest/test/t12.ibd
2017-03-29 23:37:40 7fa8e7c6f840 InnoDB: Operating system error number 2 in a file operation.
InnoDB: The error means the system cannot find the path specified.
InnoDB: If you are installing InnoDB, remember that you must create
InnoDB: directories yourself, InnoDB does not create them.
InnoDB: Error: could not open single-table tablespace file ./test/t12.ibd
InnoDB: We do not continue the crash recovery, because the table may become
InnoDB: corrupt if we cannot apply the log records in the InnoDB log to it.
InnoDB: To fix the problem and start mysqld:
InnoDB: 1) If there is a permission problem in the file and mysqld cannot
InnoDB: open the file, you should modify the permissions.
InnoDB: 2) If the table is not needed, or you can restore it from a backup,
InnoDB: then you can remove the .ibd file, and InnoDB will do a normal
InnoDB: crash recovery and ignore that table.
InnoDB: 3) If the file system or the disk is broken, and you cannot remove
InnoDB: the .ibd file, you can set innodb_force_recovery > 0 in my.cnf
InnoDB: and force InnoDB to continue crash recovery here.
170329 23:37:41 mysqld_safe mysqld from pid file /usr/local/mysql56/data/mysql.pid ended
170329 23:41:05 mysqld_safe Starting mysqld daemon with databases from /usr/local/mysql56/data
2017-03-29 23:41:06 0 [Note] /usr/local/mysql56/bin/mysqld (mysqld 5.6.32-log) starting as process 9155 ...
从这里可以看出t12.ibd被删除了,导致mysql起不来
2.设置innodb_force_recovery=1,启动
InnoDB: Last MySQL binlog file position 0 160166, file name mysql-bin.000095
2017-03-30 04:35:46 7f7351aaf840 InnoDB: Error: table 'test/t12'
InnoDB: in InnoDB data dictionary has tablespace id 1,
InnoDB: but the tablespace with that id has name test/playerdiamond.
InnoDB: Have you deleted or moved .ibd files?
InnoDB: Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting-datadict.html
InnoDB: for how to resolve the issue.
2017-03-30 04:35:46 15193 [Note] InnoDB: 128 rollback segment(s) are active.
2017-03-30 04:35:46 15193 [Note] InnoDB: Waiting for purge to start
2017-03-30 04:35:46 15193 [Note] InnoDB: 5.6.32 started; log sequence number 431731693
2017-03-30 04:35:46 15193 [Note] InnoDB: !!! innodb_force_recovery is set to 1 !!!
2017-03-30 04:35:46 15193 [Note] Recovering after a crash using /usr/local/logdir/mysql-bin
2017-03-30 04:35:46 15193 [Note] Starting crash recovery...
2017-03-30 04:35:46 15193 [Note] Crash recovery finished.
从日志可以看书mysql Crash recovery完成了,如果还是还是没启动你就可以将值设置为2,3,4依次递增
3.进入mysql,然后drop table t12;
mysql> show create table t12;
ERROR 1146 (42S02): Table 'test.t12' doesn't exist
mysql>
mysql>
mysql> drop table t12;
Query OK, 0 rows affected (0.03 sec)
mysql>
mysql>
由于这里我是模拟删除.ibd文件,所以就没法恢复数据了,所以也就没必要导出,导入这个这个步骤
4.设置innodb_force_recovery=0,重新启动
[root@localhost test]# vim /etc/my.cnf
[root@localhost test]# service mysqld restart
Shutting down MySQL... SUCCESS!
Starting MySQL............ SUCCESS!
[root@localhost test]#
由此看到MySQL重新启动了
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30221425/viewspace-2136469/,如需转载,请注明出处,否则将追究法律责任。