兩次使用InnoDB的慘痛經驗

URL Link //n.sfs.tw/10264

2016-11-21 12:58:19 By 張○○

Mysql 的Innodb引擎雖然好用,但是我得說說我兩次的慘痛經驗,這讓我考慮以後可能不會再使用innodb了。

先要從這近的大災難說起。這近我的伺服器不明原因發生磁碟異常,兩顆硬碟亮紅燈,我是有做raid5的,兩顆同時亮紅燈時我緊張到快要脫肛。眼下的伺服器os當了,所以給他硬重開機,重開機後出現一個錯誤說找不到磁碟

◢▆▅▄▃-崩╰(〒皿〒)╯潰-▃▄▅▆◣

出現兩個選項:

1 不論如何開機
2 放棄變更從磁碟啟動

我當然先選1但無用後選2,開是能開機,但是只能進到救援模式,他要我去檢查磁碟,說真的我根本不知道是啥事?做了四次的fsck才把檔案系統救回,花了三個多小時。

本來急到快有心臟病,搞了三個小時突然好了,取而代之是疲勞,可是我又不能放著跑去睡覺,繼續努力...

救回系統後發現mysql啟動不,心想到是不是資料庫檔案壞掉了?利用mysql提供的強制救援模式(這玩意也是第一次用到),mysql在安全模式下啟動中一直失敗,看來問題很大,事實上,就是那個存放資料庫的innodb的檔案壞掉了,序號不對、key不對就是一直起不來:

ib_logfile0
ib_logfile1
ibdata1

130507 10:38:46  mysqld started
130507 10:38:48  InnoDB: Started; log sequence number 1 3612530484
130507 10:38:49 [Note] /usr/local/libexec/mysqld: ready for connections.
Version: '5.0.92-log'  socket: '/tmp/mysql.sock'  port: 3306  FreeBSD port: mysql-server-5.0.92
130508 07:40:11  mysqld started

InnoDB: The log sequence number in ibdata files does not match <==流水號不對
InnoDB: the log sequence number in the ib_logfiles!
130508  7:40:12  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Restoring possible half-written data pages from the doublewrite
InnoDB: buffer...
InnoDB: Last MySQL binlog file position 0 14325444, file name ./mysql-bin.000063
130508  7:40:13  InnoDB: Started; log sequence number 1 3629485601
130508  7:40:13 [Note] Recovering after a crash using mysql-bin
130508  7:40:14 [Note] Starting crash recovery...
130508  7:40:14 [Note] Crash recovery finished.
130508  7:40:14 [Note] /usr/local/libexec/mysqld: ready for connections.
Version: '5.0.92-log'  socket: '/tmp/mysql.sock'  port: 3306  FreeBSD port: mysql-server-5.0.92
130515  3:00:07  InnoDB: ERROR: the age of the last checkpoint is 9433731,
InnoDB: which exceeds the log group capacity 9433498.
InnoDB: If you are using big BLOB or TEXT rows, you must set the
InnoDB: combined size of log files at least 10 times bigger than the
InnoDB: largest such row.

.... 一大堆錯誤checkpoint 的列表,我根本不知道要怎麼救 .....

我從晚上七點努力到半夜三點,想了非常多招 要救援「遺失的環節」,但是因為磁碟損傷太嚴重,完全沒招,只好採用最後一招也是我最不想打的招術:「備份還原」。

因為備份還原只能還原到特定的時間點,大概會遺失4天的資料,這4天的資料我利用救援的過程中幸運的撿回了二天的資料,怎麼說幸運呢?因為強制mysql安全模式啟動失敗前,會有短暫的幾秒鐘處於「成功」的狀態,這成功的狀況發生很短,我猜測可能是mysql本身還沒有檢查到序號不match的錯誤。我利用這個短暫的時間救回了大概二天的資料,足足搞了二三個小時:

151106 01:00:01  mysqld restarted
InnoDB: The user has set SRV_FORCE_NO_LOG_REDO on
InnoDB: Skipping log redo
151106  1:00:01  InnoDB: Started; log sequence number 0 0

InnoDB: !!! innodb_force_recovery is set to 6 !!! <== 安全模式最暴力啟動法第6級
151106  1:00:01 [Note] Recovering after a crash using mysql-bin
151106  1:00:01 [Note] Starting crash recovery...
151106  1:00:01 [Note] Crash recovery finished.

151106  1:00:02 [Note] /usr/local/libexec/mysqld: ready for connections.
Version: '5.0.92-log'  socket: '/tmp/mysql.sock'  port: 3306  FreeBSD port: mysql-server-5.0.92
151106  1:00:08 [ERROR] /usr/local/libexec/mysqld: Table './herald/news' is marked as crashed and should be repaired
151106  1:00:08 [ERROR] /usr/local/libexec/mysqld: Table './herald/news' is marked as crashed and should be repaired
151106  1:00:08 [ERROR] /usr/local/libexec/mysqld: Table './herald/news' is marked as crashed and should be repaired
151106  1:00:08 [ERROR] /usr/local/libexec/mysqld: Table './herald/news' is marked as crashed and should be repaired
151106  1:00:12 -
mysqld got signal 11 ;  <==被強制中止mysql
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
We will try our best to scrape up some info that will hopefully help diagnose
the problem, but since we have already crashed, something is definitely wrong
and this may fail.


上面的例子可以看到1:00:02正確啟動,大約有六秒鐘的時間mysql是處於能運作的狀態,不一定是6秒,有時是1秒有時是10秒不一定,但是都不長,我這時就想,如果我能夠在這麼短的時間把資料dump出來就能重建這四天的資料。

想是想,但是只有短短的幾秒,要怎麼連線又下指令又dump?這真的是一個非常困難的挑戰,我把指令全部打好,接下來就是把苦練打電動三十年的功力拿出來用的時候:在極短的時間飛快的動手指{貼指令-->祁禱有抓到資料-->失敗}一直循環操作。失敗是正常,成功是偶然。我一開始想貪心抓一堆,後來發現根本不可能,最後縮短到十筆十筆,最後變成一筆一筆的抓,只要是筆數少,在短時間程式還有少許的機會執行完的。

對我而言每一筆資料都不能再製,所以都很重要,所以我一定得把他們能救多少算多少,,就這樣我救了一百多筆的「失落環節」。到最後就再也不能成功,因為可能一抓到受損的資料就會被立刻終止,所以救也只能救到二天。

最後我只能心一橫,把innodb的資料全砍掉重建。因為只要是存在innodb引擎的欄位就失敗,重建是唯一解。

---


來~哥餵你

第二次的經驗完全是因為我自己.白.痴.所造成的:有一天我在改程式的時候,去資料庫看到一些資料,那時腦袋不清楚。

就想說:咦?這些資料都是舊資料啊,我留下來幹什麼,應該要更新...

就想說:咦?這些資料都是舊資料啊,我留下來幹什麼,應該要更新...

就想說:咦?這些資料都是舊資料啊,我留下來幹什麼,應該要更新...

所以咧,我就把他刪了,然後把整理好的新資料餵進去,說穿了也才21筆而已,心裡非常滿足

心裡非常滿足

心裡非常滿足

心裡非常滿足

接下來....臉就綠了

我的網站資料怎麼全部都不見了?是不是被駭客入侵?天啊~~~為什麼我會被駭客入侵,刪光我的資料

等我回過神後,我才想到完完全全是我自己白痴造成的。

因為我設了關聯式資料庫建立了關聯,在刪除那個部分也設定了CASCADE,所以一關聯後,全部刪光光,天啊,6萬多筆資料耶~~~~

我白痴去設什麼cascade?(不設cascade那我是在關聯個屁啊?)

為了這個白痴的舉動,我又白花了好多小時重建資料,就像老師會說的…

  當你在嬉戲的時候,別人很認真的在唸書

而我是…

  當你在睡覺看電視的時候,我在為我的白痴行為付出代價

討論

我並不是說innodb不好,以免費的關連式資料庫來說,innodb相當的不錯。但是它有幾個不好的,至少是我覺得比較困擾的缺點:

1. 全部的更新記錄都會寫到 ib_logfile0、ib_logfile1這兩個檔中,ibdata1則存放所有的資料。有非常大的可能這個ibdata1檔案會大到好幾G,這檔案很大本身並不是問題,只是麻煩而已,但越大的檔案損壞的風險就越高。舉例而言,1個2g的檔案和2個1g的檔案,假如磁區每一個區域壞掉的機率都相同,那麼2g的檔案壞掉的機率會是任一個1g檔的兩倍。雖然有做硬體的備援,軟體的備援,但是難道就完全萬無一失嗎?我想未必。

2. 關聯式資料庫方便的地方在於不必去處理關聯的事情(廢話),所以很方便,但是一關聯後操作就得要很小心,一失手就屎很久。有時寫程式多花一點程式碼檢查重覆也未必不好,不要為了關聯而去關聯。

結論

1. 沒事別用innodb
2. 腦袋不清楚不要去動資料庫。
3. 備份很重要,救命就靠它。
4. 意外總是會在你覺得萬無一失的時候出現。(放假時機器總是會出問題?!)
5. 當災難發生時,連最基本的指令都會忘記,所以平常要做筆記。