Linux 文件系統引發的雲盤文件系統異常致使 MySQL 數據頁損壞事故恢復覆盤

事故的原由是由於當我訪問某個數據庫的某個表的時候,MySQL 當即出現崩潰而且去查看 MySQL 的錯誤日誌出現相似信息html

2019-05-09T05:52:19.232564Z 1027 [ERROR] InnoDB: Space id and page no stored in the page, read in are [page id: space=1668620387, page number=16777216], should be [page id: space=1321, page number=2560]
2019-05-09T05:52:19.232613Z 1027 [ERROR] InnoDB: Database page corruption on disk or a failed file read of page [page id: space=1321, page number=2560]. You may have to recover from a backup.
2019-05-09T05:52:19.232620Z 1027 [Note] InnoDB: Page dump in ascii and hex (16384 bytes):

2019-05-09T05:52:19.301493Z 1027 [Note] InnoDB: Uncompressed page, stored checksum in field1 0, calculated checksums for field1: crc32 509574685/727399785, innodb 723696011, none 3735928559, stored checksum in field2 2940110097, calculated checksums for field2: crc32 509574685/727399785, innodb 2408125488, none 3735928559,  page LSN 2131755008 16, low 4 bytes of LSN at page end 0, page number (if stored to page already) 16777216, space id (if created with >= MySQL-4.1.1 and stored already) 1668620387
InnoDB: Page may be a freshly allocated page
2019-05-09T05:52:19.301532Z 1027 [Note] InnoDB: It is also possible that your operating system has corrupted its own file cache and rebooting your computer removes the error. If the corrupt page is an index page. You can also try to fix the corruption by dumping, dropping, and reimporting the corrupt table. You can use CHECK TABLE to scan your table for corruption. Please refer to http://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html for information about forcing recovery.
2019-05-09T05:52:19.301558Z 1027 [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.
2019-05-09 13:52:19 0x7fe307678700  InnoDB: Assertion failure in thread 140613058529024 in file ut0ut.cc line 942

Trying to get some variables.
Some pointers may be invalid and cause the dump to abort.
Query (7fe2dc03c240): select * from desktop_document2
Connection ID (thread ID): 1027
Status: NOT_KILLED

 

能夠注意到這裏就是 MySQL innodb 的數據發生了損壞。能夠看到日誌的最下面其實這裏就是給出的是可能形成崩潰的 query mysql

這裏咱們能夠看到是要由於對 desktop_document2 進行讀取形成的。一旦咱們對該表嘗試讀寫或者 check table 都會形成 MySQL 崩潰重啓。web

這裏有兩種解決思路:sql

1. 有備份的話將備份找個地方恢復出來,而後從新生成該表。數據庫

2. 若是對應到壞的表 check 了以後發現是無關緊要能夠從新生成的表,能夠直接將該表 drop 掉重建。這樣能夠省出一些恢復的成本和複雜性。bash

3. 若是壞的數據不可修復,也沒有備份。那麼須要避開壞數據用 id 偏移的方式儘可能掃描更多的數據出來。網絡

而後這裏還有個腳本 能夠批量掃描壞表。當遇到第一個壞表的時候檢查打印出來的 table_name 並作確認。而後排出掉他再繼續掃下面的表。spa

#!/bin/bash
host_name=127.0.0.1
user_name=
user_pwd=
database=
tables=$(/usr/local/webserver/mysql/bin/mysql -h$host_name -u$user_name -p$user_pwd $database -A -Bse "show tables")
for table_name in $tables
do
 echo $table_name
 check_result=$(/usr/local/webserver/mysql/bin/mysql -h$host_name -u$user_name -p$user_pwd $database -A -Bse "check table $table_name" | awk '{ print $4 }')
 if [ "$check_result" = "OK" ]
 then
  echo "OK TABLE $table_name"
 fi
done

須要注意的是使用該腳本在掃描到壞表的時候一樣會觸發 MySQL 異常重啓。日誌

 

到目前爲止來看彷佛狀況可控,可是遺憾的是形成此次事故繼續擴大的是。當時我發現異常損壞發生在系統盤,而後該盤有天級快照。在和各方確認該數據庫影響以後我打算直接使用 aliyun 的天級快照來恢復目前糟糕的狀況。而後再從新計算當天的相關數據便可,恢復的週期也比較短。code

因而關機開始恢復快照 然而等待個人倒是

exoo me????

看上去是引導區損壞了,到這裏爲止就感受狀況變得很是麻煩了。由於快照恢復以後出現這個問題就意味着以前很長一段時間一直都存在引導區由於文件系統損壞而損壞的狀況。也就是說可能以前的快照也都壞了,系統盤沒法做爲引導啓動系統。

後來聯繫 aliyun 工程師經過 liveCD 重啓系統,將以前系統掛載到數據盤開始搶救數據。

這裏有個值得反思的地方,當時沒有作這個機器的數據庫備份是由於想到有快照能夠依賴,用快照來當備份使用。可是沒有考慮打的是,MySQL 的默認數據目錄是 /var/lib ,而這個目錄存在於數據庫上而並不是數據盤上。一旦出現相似的文件系統或者引導區損壞重啓以後可能就沒法進入系統,最嚴重的狀況可能沒法使用快照恢復任何數據。

因此說任什麼時候候即便有快照,都應該對你的數據庫進行最少天級備份。

 

在和 aliyun 確認一些信息以後,我列了一個恢復方案最終使用了方案2恢復了數據。下面貼一個 check list

方案1:

1. data02 上用 data-11 5.8日凌晨3點的快照恢復一塊 500g 的數據盤。
2. data02 上配置和 data-11 上版本相同的 MySQL(5.7.23)。
3. 使用 data-11 上 MySQL 的數據目錄恢復出當時 MySQL 的狀況而且啓動 MySQL
4. 使用 innobackupex 將機器上的數據庫全量備份出來,同時查看數據完整性狀況,使用腳本 check table 檢查完整性。
5. 將 data-11 機器還原成初始配置,安裝一樣版本的數據庫,而且使用備份恢復數據庫數據。
 

方案2:

1. 直接在 data-11 上重置系統。☑️
2. 而後使用鏡像掛一個 500g 的盤。☑️
3. 通知 aliyun 工程師使得新掛載的盤變得可讀。☑️
4. 安裝 MySQL 5.7.23 數據庫。☑️
5. 將數據庫文件找個地方拷貝出來。☑️
6. 將數據文件恢復至 新安裝的 5.7.23 數據庫,而且不保證相關帳號密碼都和之前一致。☑️

這裏要提一下方案2的todo 6,若是全量恢復整個數據庫的數據,能夠直接將整個數據目錄進行覆蓋,而後重啓數據庫就能夠簡單的直接經過文件恢復數據庫。

若是是單純的要恢復某個表或者某個庫,最好仍是找機器全量恢復以後,使用 mysqldump 或者 pxb 備份對應的庫表進行恢復比較簡單。直接經過恢復文件的形式恢復單個表庫實在太過於複雜了,感受不必。

截止到目前數據庫就已經恢復了,剩下的仍是要 drop 掉壞掉的表進行重建,或者參照上面的方法進行數據搶救。

 

其實在以前一個月就發現該機器有一些奇怪的報錯日誌 相似於

Aborted connection 134328328 to db: 'test' user: 'root' host: '127.0.0.1' (Got timeout reading communication packets)

後來看了一些資料,這些都是一些網絡超時錯誤,與這次事故無關,能夠根據 http://mysql.taobao.org/monthly/2017/05/04/ | https://www.percona.com/blog/2016/05/16/mysql-got-an-error-reading-communication-packet-errors/ 來仔細排查網絡問題。

 

小結:

無論有沒有快照或者別的保護措施都應該對數據庫進行天級備份,有備無患。

當能恢復接觸到數據的時候應該第一時間對數據進行再備份,保證至少當前狀態能夠保證再也不惡化。

要第一時間通知相關小夥伴事故處理的進度,以及通知到受影響的小夥伴得到他們的支持,恢復以後第一時間恢復相關服務。

 

Reference:

https://zhuanlan.zhihu.com/p/60327406  MySQL經過frm、ibd文件恢復innodb數據

http://www.yunweipai.com/archives/19844.html  MySQL 如何利用 ibd 文件恢復數據

http://mysql.taobao.org/monthly/2017/05/04/  MySQL · 答疑解惑 · MySQL 的那些網絡超時錯誤

https://www.percona.com/blog/2016/05/16/mysql-got-an-error-reading-communication-packet-errors/  mysql-got-an-error-reading-communication-packet-errors

https://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html  Forcing InnoDB Recovery

相關文章
相關標籤/搜索