利用 Forcing InnoDB Recovery 特性解決 MySQL 重啓失敗的問題

背景

小明同窗在本機上安裝了 MySQL 5.7.17 配合項目進行開發,而且已經有了一部分重要數據。某天小明在開發的時候,須要出去一趟就直接把電腦關掉了,沒有讓 MySQL 正常關閉,重啓 MySQL 的時候,報錯以下:html

...
[ERROR] InnoDB: Space id and page no stored in the page, read in are [page id: space=3611051955, page number=1571966525], should be [page id: space=86, page number=4]
...
[ERROR] InnoDB: Database page corruption on disk or a failed file read of page [page id: space=86, page number=4]. You may have to recover from a backup.
...
[ERROR] [FATAL] InnoDB: Aborting because of a corrupt database page in the system tablespace. Or,  there was a failure in tagging the tablespace  as corrupt.
...

分析

從日誌內容來看,MySQL 在機器關機的時候有數據沒有落地,表空間損壞,致使重啓以後沒法正常恢復,線程在數據頁中讀取不到須要的 page 和數據。mysql

須要作特殊操做,讓 MySQL 跳過恢復,啓動 MySQL,而後把數據導出來,再重建數據庫導入。sql

MySQL 有個一個特性:Forcing InnoDB Recovery,啓用這個特性須要設置 innodb_force_recovery 大於 0。數據庫

innodb_force_recovery 能夠設置爲 1-6,大的值包含前面全部小於它的值的影響。安全

1 (SRV_FORCE_IGNORE_CORRUPT): 忽略檢查到的 corrupt 頁。儘管檢測到了損壞的 page 仍強制服務運行。通常設置爲該值便可,而後 dump 出庫表進行重建。

2 (SRV_FORCE_NO_BACKGROUND): 阻止主線程的運行,如主線程須要執行 full purge 操做,會致使 crash。 阻止 master thread 和任何 purge thread 運行。若 crash 發生在 purge 環節則使用該值。

3 (SRV_FORCE_NO_TRX_UNDO): 不執行事務回滾操做。

4 (SRV_FORCE_NO_IBUF_MERGE): 不執行插入緩衝的合併操做。若是可能致使崩潰則不要作這些操做。不要進行統計操做。該值可能永久損壞數據文件。若使用了該值,則未來要刪除和重建輔助索引。

5 (SRV_FORCE_NO_UNDO_LOG_SCAN): 不查看重作日誌,InnoDB 存儲引擎會將未提交的事務視爲已提交。此時 InnoDB 甚至把未完成的事務按照提交處理。該值可能永久性的損壞數據文件。

6 (SRV_FORCE_NO_LOG_REDO): 不執行前滾的操做。恢復時不作 redo log roll-forward。使數據庫頁處於廢止狀態,繼而可能引發 B 樹或者其餘數據庫結構更多的損壞。

注意:服務器

爲了安全,當設置參數值大於 0 後,能夠對錶進行 select, create, drop 操做,但 insert, update 或者 delete 這類操做是不容許的。MySQL 5.6.15 之後,當 innodb_force_recovery 的值大於等於 4 的時候,InnoDB 表處於只讀模式。

在值小於等於 3 時能夠經過 select 來 dump 表,能夠 drop 或者 create 表。MySQL 5.6.27 後大於 3 的值也支持 DROP TABLE;

若是事先知道哪一個表致使了崩潰則可 drop 掉這個表。若是碰到了由失敗的大規模導入或大量 ALTER TABLE 操做引發的 runaway rollback,則可 kill 掉 mysqld 線程而後設置 innodb_force_recovery = 3 使數據庫重啓後不進行 rollback。而後刪除致使 runaway rollback 的表;

若是表內的數據損壞致使不能 dump 整個表內容。那麼附帶 order by primary_key desc 從句的查詢或許可以 dump 出損壞部分以後的部分數據;

若使用更高的 innodb_force_recovery 值,那麼一些損壞的數據結構可能引發複雜的查詢沒法運行。此時可能只能運行最基本的 select * from table 語句。

解決

前面說了,表空間損壞,重啓時前滾恢復失敗,所以在重啓的時候不要執行前滾的操做,在 /etc/mysql/my.cnf 中添加:數據結構

[mysqld]
innodb_force_recovery = 6

而後重啓 MySQL,當即對數據庫用 mysqldump 把數據導出。完成後,去掉 innodb_force_recovery 或者設置爲 0,而後從新建立數據庫,把數據導入。測試

最後

這個方法僅僅是緊急狀況下的一種補救,不能依賴於這個辦法,最好是作好數據備份工做,包括全備份和日誌備份。肯定要使用該方案是要確保有原始損壞數據的副本。4 以上的值可能永久致使數據文件損壞。務必在測試環境測試經過後再在生產環境使用。spa

MySQL crash 或者 MySQL 服務器 crash 會致使各類各類的問題 ,對於主從複製關係,MySQL 5.6 版本開始新增了 crash-safe 的特性,能夠在最大程度上避免 error 1594 的問題,保證數據的安全,如何開啓這個功能能夠參考上一篇博文:MySQL 5.6 從庫開啓 crash-safe 功能線程

做爲一個 DBA,遇到問題,要淡定,細心閱讀日誌,從中找的相關錯誤提示,而後依據錯誤找到相關的解決方法來解決問題。

相關文章
相關標籤/搜索