從刪庫到跑路or恢復,記一次MySQL數據庫文件損壞恢復經歷

1、 前言

2018年5月28日,北京晴有輕度沙塵暴。 坐上公交車走在上班的路上,想起老羅常常提及的一句話:想成盛田昭夫時代的索尼,想成喬布斯時代的蘋果,因而繼續研讀着 《日本製造:盛田昭夫的日式經營學》php

到了人大西門在西區食堂吃了個早餐,穿過人民大學很快就來到了公司。坐在工位上打開電腦登上QQ,不一會運營的CC的頭像就開始閃動,「mooc平臺登陸不了」,「你看看」。又一會領導的頭像開始閃動,「xxx說慕課平臺不能登陸了」。 額… 這事都驚動領導了?mysql

2、 排查問題

打開chrome瀏覽器開始預覽,等了很久代理服務器才反饋linux

Time out!nginx

使用 SecureCRT 鏈接了一下服務器,首先從新啓動了一下Nginx代理服務器sql

service nignx stop // 關閉Nginx服務chrome

service nginx start // 開啓Nginx服務數據庫

去前臺刷新了幾下沒有恢復。 那就在重啓一下php吧,因而就centos

service php-fpm stop // 關閉PHP服務瀏覽器

service php-fpm start // 開啓PHP服務安全

又去前臺試了試仍是沒有恢復。(有人會問爲何不直接用 service xxx restart 來重啓各服務呢? 我也不知道爲何,我的愛好吧!)那只有一種可能數據庫出問題了。

打開 Navicat 鏈接了一下數據庫,發現能夠正常鏈接並且能夠看到全部的表,隨便打開了一張表能看到裏面的數據,可是彈出了一個錯誤的提示。

Got error 28 from storage engine

大概是這個錯誤提示,當時也沒在乎,心想反正提示錯誤了那就重啓一下物理服務器吧,這裏是物理服務器!!!隨後執行了這個命令(爲何不直接重啓MySQL服務呢? 過後想了想我也不知道爲何。 並且若是當時注意看看這個錯誤,是由於磁盤空間問題引發的,也許後面就不會有那麼多驚心動魄了!)

reboot // 重啓物理服務器

執行完之後全部的服務都正常關閉了,只有Mysql數據庫服務

Shutdown MySQL ……………………………………………….

引號已經5排了,實在是等不下去了。 斷電!!!(MySQL沒有安全關閉,直接斷電會出問題的!!!)。

3、 恢復進程

等了一會,物理服務器啓動起來了。一切的應用服務都正常啓動了,只看到在啓動MySQL數據庫的時候出現了

The server quit without updating pid file (/var/lib/mysql/localhost.localdomain.pid)

等到所有服務加載完成之後手動又進行了一次MySQL數據庫啓動

service mysql start

依然報前面那樣的錯誤,此時內心開始緊張了起來。 Google了一下這個錯誤,網上提供了幾種解決的方案:

一、 Mysql權限問題

chown -R mysql:mysql /var/lib/mysql/*

chmod -R 660 /var/lib/mysql/*

二、 Mysql 服務已開啓

ps -ef|grep mysqld // 查看是否有mysqld進程

kill -9 進程號 // 強制殺死進程

三、 殘餘數據影響了Mysql服務的啓動

刪除數據庫目錄(個人數據庫目錄爲rpm安裝默認目錄:/var/lib/mysql)下的 mysql-bin.index 文件

四、 Mysql配置文件(默認爲:/etc/my.cnf)

配置文件裏面沒有配置數據庫目錄,這個問題通常在剛安裝MySQL時候會出現

五、 skip-federated字段問題

MySQL配置文件註釋掉skip-federated字段

六、 selinux的問題

centos6.8以上默認會開啓selinux服務,增強版軍用級防火牆。爲了查問題能夠直接關掉

/usr/sbin/setenforce 0

以上解決方案所有都已經使用過了,都沒有解決問題,依然開啓服務會報錯。 此時的心開始涼了。

回頭看了看往期的備份,xxxx_20171208.sql。 都快2018年6月份了,個人上次備份居然是17年12月份的,半年了!都半年沒備份過了! (我視乎隱約的感受前段時間是有備份的,備份的服務器硬盤好像被我清理了)。

進入到數據庫目錄下,看到了除了上述說的 mysql-bin.index 文件之外還有其餘的幾個文件:mysql-bin.~rec~ 、 ib_logfile一、 ib_logfile0、 ibdata1 想了想是否是這幾個也是一些殘餘文件,所有刪了試試。 嘗試把這幾個文件轉移到了其餘的目錄(使用的mv命令)模擬刪除效果,同時還至關於備份。

service mysql start

居然MySQL數據庫服務正常啓動了! 內心的喜悅涌了上來,趕忙使用Navicat鏈接一下看看,可以正常鏈接,看到了數據庫。 打開數據庫之後全部的表都沒有了! 此時心又酸了起來。 一轉眼11:30了,時間過的可真快啊,同事叫着一塊兒吃飯,此時的我已經全無吃飯的心情了。

恢復表結構

把剛纔移走的幾個文件又恢復到了原目錄裏,既然恢復MySQL進程如今沒什麼但願了,那就想辦法恢復數據吧。 進入到數據庫目錄(/var/lib/mysql)下找到了個人數據庫名字以目錄的形式存放。 進去該目錄之後發現裏面都是以擴展名爲:xxxx表.frm文件,這些不都是個人數據庫表嗎? 裏面是否是就存放了全部的數據? 是否是直接拿這些文件就能夠恢復數據呢?Google了一下,果真有這方面的文章,大體說: 「frm能夠恢復表結構,同時InnoDB數據庫引擎和MyISAM數據庫引擎恢復的方式不同」。

一、 InnoDB數據庫引擎

  1. 在一個正常的MySQL數據庫服務器(new_server)下創建數據庫(new_db),該數據庫的名稱和異常服務器(old_server)數據庫(old_db)保持一致。
  2. 在new_db數據庫中創建一張表與old_db的表名稱(t_user)一致。
  3. 將new_server服務器的MySQL數據庫服務關閉。
  4. 從old_server服務器下old_db的數據庫目錄下複製t_user.frm文件到new_server服務器下new_db的數據庫目錄下替換t_user.frm文件。
  5. 開啓new_server服務器的MySQL數據庫服務。
  6. 使用鏈接工具鏈接new_server就能夠看到new_db下的表及表結構。

二、 MyISAM數據庫引擎

其餘和InnoDB數據庫引擎操做基本一致,只是在new_server服務器下new_db的數據庫目錄下建立兩個空的文件:t_user.MYD 和 t_user.MYI。

我使用的數據庫爲InnoDB引擎,無奈的我以上兩種方法都使用了,沒有恢復任何表結構更沒有數據,也許多是我操做有問題吧。 此時看到了目錄下有一個文件: ibdata1 Google了一下,能夠和xxx.frm配合使用,又一次將new_server服務器的MySQL數據庫服務關閉。 直接把old_server服務器下old_db的數據庫目錄下複製ibdata1文件到new_server服務器下new_db的數據庫目錄下替換ibdata1文件。

service mysql start

新的服務器也出現了這樣的錯誤,致使錯誤的很大緣由多是ibdata1文件損壞引發的。

今天北京的天氣已經達到了35攝氏度,但此時個人心已經涼了一半了,雖然沒有按時備份數據及服務器異常崩潰形成數據丟失比直接刪庫的責任小了點,可是也辦法向公司交代,真的須要開始準備 「離職申請」 了嗎?

binlog日誌

打開微信

:大家公司用的是什麼數據庫,是MySQL嗎

好友LZ:是的

:公司的MySQL壞了,啓動不了了; 數據沒有備份; 有什麼好辦法把數據拿回來嗎

好友LZ:大家以前數據的binlog還有嗎;經過這個應該能夠恢復

:都有

好友LZ:我也沒弄過數據恢復,都是DBA搞,感受應該能夠的;你先查查看網上有沒有解決方案,我這會在上線。

:嗯

原本想說:「你能不能問問好友LZ大家DBA遇到過這種狀況嗎,幫忙給個方案」;最後仍是沒有好意思開出口。 不過binlog這個名字讓我忽然想起了數據庫目錄(/var/lib/mysql)下面幾個較大的文件。

這十幾個文件就是binlog日誌文件,每臺服務器上面的個數應該不同,這個文件只有每次重啓MySQL服務或者刷新日誌(MySQL命令:show master logs)的時候纔會新增一個。看了一下我最近的幾個文件,2018年1月1六、 2018年3月1八、 2018年4月1八、 2018年5月28這幾個時間點產生了新的文件,說明MySQL服務器這幾個日期都進行過關閉又開啓的操做。

binlog使用

binlog文件簡介(網上摘抄)

MySQL的二進制日誌能夠說是MySQL最重要的日誌了,它記錄了全部的DDL和DML(除了數據查詢語句)語句,以事件形式記錄,還包含語句所執行的消耗的時間,MySQL的二進制日誌是事務安全型的。

binlog做用(網上摘抄)

MySQL Replication在Master端開啓binlog,Mster把它的二進制日誌傳遞給slaves來達到master-slave數據一致的目的。

數據恢復,經過使用mysqlbinlog工具來使恢復數據。

使用binlog恢復數據以前須要肯定MySQL是否開啓binlog日誌

show variables like 'log_%';

狀態 OFF 爲未開啓,狀態 ON 表示已開啓

能夠經過MySQL配置文件(默認路徑:/etc/my.cnf)開啓或關閉binlog日誌

vi /etc/my.cnf

使用加上#能夠關閉,去掉開啓。 修改後須要重啓MySQL服務(service mysql restart)才能夠生效。

恢復數據(binlog日誌方式)

初試mysqlbinlog工具

看到上面的那麼多mysql-bin文件,很顯然使用centos6.5下rpm方式安裝的MySQL默認是打開binlog日誌的。 這時咱們就須要用到MySQL的 mysqlbinlog 工具,想使用它首先須要確保已經安裝MySQL服務,而後咱們須要找到它的位置

find / -name mysql

2 表示爲MySQL可執行文件的目錄

3 表示爲MySQL的數據庫目錄

那咱們先簡單的使用一下

cd /var/lib/mysql

mysqlbinlog mysql-bin.000001 > mysql-bin.000001.sql

很顯然我在使用mysqlbinlog的時候是,直接執行的mysqlbinlog命令,前面並無增長任何路徑。 由於默認centos系統會將/usr/bin這個目錄配置到環境標量中,若咱們使用的是rpm方式安裝的MySQL,默認是安裝到/usr/bin目錄下的。 能夠直接在任何路徑下使用/usr/bin目錄裏的文件。 執行完上面的語句後會發如今當前目錄生成一個mysql-bin.000001.sql的文件, 打開文件能夠看到不少sql語句。

對於我當前的狀況來看並不須要把全部的binlog都處理一遍,上面提到我上次的備份是在2017年12月8日的時候(xxxx_20171208.sql)所以我只須要從 mysql-bin.000009 這個binlog文件開始就能夠了。

首先我在另一臺服務器上面從新搭建了一個MySQL服務,把mysql-bin.000009之後的幾個binlog都拷貝到了這臺新的服務器上面去。(服務器出現任何問題,建議不要對該服務器作任何操做,換一臺新的電腦或服務來處理,爲了保護數據的完整性!)

使用備份文件恢復數據

在新的MySQL上面建了一個和之前同樣名稱的數據庫

mysql -u數據庫用戶名 -p數據庫密碼 數據庫名稱 --default-character-set=utf8 < xxxx_20171208.sql

例:mysql -uroot -proot xxxx --default-character-set=utf8 < xxxx_20171208.sql

使用binlog恢復數據

這時數據庫有了,數據表及表結構也有了,那就開始恢復數據吧。

mysqlbinlog mysql-bin.000009 | mysql -uroot -proot

回車立刻就出錯了,遇到了兩種錯誤,一種是PRIMARY的錯誤,一種是找不到記錄的錯誤。 mysqlbinlog在執行mysql-bin.000009文件裏的插入語句時出錯了。 看了一下mysql-bin.000009文件的建立時間是2017年11月12日,個人備份文件是2017年12月8日,他們兩個時間差了二十幾天,執行上面恢復語句確定會出現重複插入的問題,數據庫裏的某些表是由PRIMARY KEY的約束的,因此會致使PRIMARY錯誤。 這時咱們須要用到mysqlbinlog的參數: start-datetimeend-datetime,顧名思義一個是開始時間一個是結束時間。

mysqlbinlog --start-datetime="2017-12-08 10:00:00" mysql-bin.000009 | mysql -uroot -proot

看了一下我備份的xxxx_20171208.sql大體是2017年12月8日的10左右,沒有添加 end-datetime 參數的話默認爲該binglog文件下的最後一個時間點。 執行了之後報了一個找不到記錄的異常。 應該是執行刪除或更新語句的時候沒有找到某條記錄,時間仍是不對。 因而我就查看了數據庫的日誌表,最後的時間是2017年12月8日9點32分41秒,有執行了一次

mysqlbinlog --start-datetime="2017-12-08 09:32:41" mysql-bin.000009 | mysql -uroot -proot

依然報錯,那怎麼辦呢,難道這個方法不行?

mysqlbinlog mysql-bin.000009 > mysql-bin.000009.sql

此時打開mysql-bin.000009.sql裏面擁有大量的sql語句,發現好多條sql語句在這個時間點下。 看來使用參數來控制行不通。 還好mysqlbinlog工具給咱們提供了另外兩個參數start-positionend-position

修改了一下命令

mysqlbinlog --start-position="123456" mysql-bin.000009 | mysql -uroot -proot

果真一切都正常了,執行這個命令須要好久,它要把你這段時間全部的增長、刪除、更新都執行一遍。 這裏可能還會遇到一個問題,個人這個MySQL服務器裏面這有一個數據庫,MySQL的binlog文件記錄的是全部數據庫的增長、刪除、更新記錄,那怎樣只針對某個數據庫來操做呢? 這時咱們須要用到mysqlbinlog的database參數

mysqlbinlog --database=xxxx --start-position="123456" mysql-bin.000009 | mysql -uroot -proot

半年的數據,就這麼一個一個的binlog文件進行處理的,從晚上6點到夜裏的12點完成全部文件的恢復,數據量不是很大,服務器的性能也不是過高,中間出了點問題,不過都是服務器中斷的問題。 最後把全部的數據所有恢復了回來,這心驚肉跳的一天!

這是工做7年來出的最大一次事故,去年給本身定的一個目標今年寫12篇有質量的文章反饋給互聯網,都快過半年了一篇尚未寫,沒想到第一篇居然是以這種方式書寫的。 不知道這篇算不算是有質量,但願能幫到更多的人。

總結

遇到問題不要盲目,保持清醒的頭腦,找清問題,整理好思路才能更有效的解決問題。 對於數據平時不要怕麻煩,注意備份

備註

個人服務器及各軟件的版本

  • 操做系統:** centos6.5
  • MySQL:** 5.5.49
  • 安裝MySQL方式:** rpm
相關文章
相關標籤/搜索