【MySQL】崩潰恢復問題解決:Forcing InnoDB Recovery

風塵_NULL發表於2017-04-01
背景:
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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章