centos/windows服務器,Mysql數據庫表結構損壞-已解決

【問題原因】服務器突然斷電
【故障報告】數據庫表結構損壞
【解決思路】進入強制恢復模式,備份庫表及數據重建

故障發現

周末公司斷電,周一啟動數據庫就直接報錯了

image.png
查看日誌

image.png

image.png

image.png

上面標記的log,明確表示是非正常關機(InnoDB: Database was not shutdown normally!)導致表結構損壞了,並且在最後給出了三種修復建議:
1)權限問題。我的文件無此類問題,略過該方案
2)跳過當前表恢復。我出錯的表比較重要,全額無法通過備份恢復,所以該方案也不合適
3)調整強制恢復級別,強制修復表結構。我後續的處理,使用了選擇了該方案。

備註:斷電時往往數據結構都還是好的,只是mysql事務未完成,有壞的數據在這裡,所以有錯誤。 理論上只要修復表結構、去除壞的數據,mysql就可以正常恢復了。

處理故障

如上所述,權衡之後,我採用了強制啟動+導出數據重建的方式。

調整強制恢復級別

找到配置進入編輯模式:# vim /etc/my.cnf

在[mysqld]配置項下面配置(配置前需要檢查,如果配置文件中已有該配置,將值改為6;如果沒有則新增這項配置。)

image.png

配置文件中調整級別:(配置前需要檢查,如果配置文件中已有該配置,將值改為6;如果沒有則新增這項配置。)

因為之前也遇到過類似問題,低級別恢復失敗了。所以我這裡直接使用級別6:跳過啟動檢測直接進行庫表重建。
如果是其他情況的啟動異常,具體問題分析後再確定採用哪個級別。

innodb_force_recovery參數說明:

影響整個InnoDB存儲引擎的恢復狀況,默認值為0,表示當需要恢復時執行所有的恢復操作。 當不能進行有效的恢復操作時,MySQL有可能無法啟動,並記錄下錯誤日誌。

innodb_force_recovery可以設置為1-6,大的數字包含前面所有數字的影響。 當設置參數值大於0後,可以對錶進行select/create/drop操作,但insert/update/delete這類操作是不允許的。

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):不執行前滾的操作。
啟動MySQL

配置改好後,就可以啟動了。

啟動方式選擇常用的即可,但不能重複執行,否則提示進程已存在。

/etc/init.d/mysql start(在centos7.0以上版本已被systemctl start mysqld.service替代)
或者
service mysql start

正常啟動後,注意此時我們只是跳過了啟動檢查,表數據仍然是壞的。新的數據讀寫操作進來,仍然可能會出錯,甚至導致臟數據滾雪球般放大。因此需要修複數據
修複數據文件

修複數據採用的是導出後重建。

導出數據方式一
使用mysqldump命令導出:

image.png

如果數據順利導出了,可以直接查看下一節重建。

導出數據方式二

使用navicat數據庫連接工具遠程連接數據庫。

image.png

常見問題

提示密碼過期

操作時出現了密碼過期的提示:

嘗試直接登錄數據庫後,沒問題,但任何操作都會提示重設密碼:

原因暫時不清楚,畢竟只是斷電,沒有數據庫升級或其他動作。我直接按提示重設密碼

能正常讀了,接着執行備份:

執行命令:mysqldump -uroot -p –default-character-set=utf8 acc > ./acc.sql

輸入密碼,備份成功。

如果損壞的是MySQL系統表,無法dump

重建

此時數據已備份好,最大的風險已經沒有了。

為了保險起見,接下來的操作前,可以把數據文件備份。

zip -r mysql_bak.zip /var/lib/mysql 或者直接將MySQL家目錄改名(因為目前數據庫已停止,不需要關閉數據庫) mv /var/lib/mysql /var/lib/mysql_bak-user-date

有的人建議直接直接物理刪除目錄和裏面的frm與ibd文件,找到mysql的data目錄,找到目標庫,刪除整個目錄,但是我沒有成功。

我建議直接完全卸載mysql,直接重裝數據庫,因為我們現在最重要的數據已經備份出來了。這種方法百試不爽,從來沒有失敗過。

卸載數據庫(注意使用腳本前修改相應的目錄路徑)

#!/bin/bash

#SelfDir
SelfDir=$(cd "$(dirname "$0")";pwd) 
echo "cerrent path is :${SelfDir}"

mysql='mysql'


if [ `rpm -qa | grep -i $mysql | wc -l` -ne 0 ]
then 
echo " installed  mysql "
service mysql stop
EXISTS_RPMS=`rpm -qa | grep -i mysql`
echo ${EXISTS_RPMS}
for RPM in ${EXISTS_RPMS}

do
 rpm -e --nodeps ${RPM}

done
## 刪除殘留文件
rm -fr /usr/lib/mysql
rm -fr /usr/include/mysql
rm -f /etc/my.cnf
rm -fr /var/lib/mysql
rm -f /root/.mysql_secret
else 

echo "start install mysql ...." 

fi


echo 'finished!'

重裝MYSQL(這裡就不演示了,需要安裝之前部署的mysql版本,可以在網上查mysql安裝部署)

導入備份數據

將my.cnf中的innodb_force_recovery配置改為0或直接刪掉(無該配置項時MySQL默認為0)

然後重建數據庫

image.png

成功完成還原。

啟動應用服務正常,數據庫訪問正常。

整個恢復過程基本完成。

windwos服務器的恢複流程與上述一樣,只是服務的啟停方式,文件後綴名,卸載安裝操作不一樣而已

windwos啟停mysql net start/stop mysql或者到「服務」中啟動,停止
windwos配置文件 my.ini

Tags: