天天看點

一個mysqldump導出失敗的案例分析

 背景

MySQL全量邏輯備份恢複最基礎的方法,就是mysqldump生成文本,再通過source 指令直接導入。一般用于執行個體遷移或者版本更新。

這裡說明最近碰到的一個失敗例子。

描述

這個例子可以簡要複現如下,在源庫上執行如下操作:

use mydb;

create table t1 (id int);

create view v1 as select * from t1;

drop table t1;

之後執行 mysqldump mydb,發現mysqldump中途退出。簡化後出錯原因很明顯,就是視圖v1對應的表t1已經不存在,這個視圖本身非法。

這個錯誤很危險,因為如果沒有捕獲這個錯誤,直接認為mysqldump執行完成,并将生成的結果應用于目标庫,則會導緻資料丢失!

其實這個問題并不像看起來那麼簡單。

一個問題

mysqldump隻需要生成show create view v1的結果即可----這會導緻在目标庫source的時候報錯----為什麼會在dump的時候就報錯?

MySQL Tips: mysqldump導出整庫,預設情況下,會在導出前對整庫裡面的每個表加讀鎖,即Lock tables tb1 read, tb2 read,..., tbn read.

​本例中由于視圖v1需要的實體表t1已經不存在,lock table v1 read 傳回失敗。是以整個庫所有表都沒有正常導出。如果以此輸出結果導入到目标庫,則整庫資料丢失。

MySQL Tips: mysqldump若正常結束,生成的檔案結果最後一行是“-- Dump completed on + 時間”。

​使用dump的結果檔案必須先檢查結果檔案的完整性,判斷末行的文本是一個推薦操作。

導整庫的時候為什麼需要對所有表都加讀鎖呢?目的是為了得到一緻性讀視圖。也就是說,在導出整庫期間,不會有更新,這樣才保證導出資料的一緻性。

而實際上這個是曆史遺留問題,InnoDB本身支援一緻性讀,也就是說隻要啟動一個事務(begin/start transaction),則在此事務存續期間,對于本執行個體内InnoDB表的更新,此導出事務均不可見。也就是說InnoDB事務可以保證事務期間看到的視圖與事務啟動瞬間看到的一緻。

而鎖表會堵住更新,導庫又往往是長時間的操作,是以備份期間能允許讀寫對OLTP應用來說至關重要。

MySQL Tips: 若確定mysqldump導出的資料中隻有InnoDB表,可以用 --single-transaction 避免鎖表。

問題繼續

加了--single-transaction後不需要鎖表,是否還會導緻mysqldump失敗?答案依然是會。這次我們發現輸出的錯誤是 "SHOW FIELDS FROM v1" 失敗。由于show fields v1需要解析視圖并列出執行結果的列資訊,而表t1已經不存在是以報錯。

問題是,為什麼需要執行一個 SHOW FIELDS?

這就說到restore的依賴問題。

MySQL Tips: mysqldump生成導出檔案時。同一個庫内實體表先生成,之後是視圖。多個實體表是按照字母升序生成,多個視圖也是按字母升序生成。

這樣就可能存在這樣的情況,某個視圖v1依賴視圖v2,而v1的字母排序前于v2。比如視圖名為x,而依賴的另一個視圖名為y。這樣在按順序輸出的時候,如果不做任何處理,在輸出檔案中就會先出現create view x ...而由于x依賴于y但y還沒有生成,就會導緻restore階段執行失敗。

MySQL Tips: mysqldump解決視圖依賴問題的方法,就是在生成實體表階段,如果碰到視圖,則建立一個同名的臨時實體表,該表的結果與視圖完全相同。

配合的政策是在生成真正的視圖前,先将臨時實體表删除。這樣在restore階段,建立任何視圖V1前,它所依賴的視圖V2有兩種情況:

1) 字母排序V2 > V1,則目前庫中有一個名為V2的臨時實體表,這樣視圖V1能夠正常建立;

2) 字母排序V2 < V1,則此時視圖V2已經存在,這樣視圖V1能夠正常建立;

以上政策解決了視圖循環依賴的問題,這個機制需要早生成實體表階段得到視圖執行結果的列名,是以需要執行一個 SHOW FIELDS。

實踐建議

上面的分析說明了"為什麼”,以下操作型的讀者希望的實踐建議:

1) 為避免無效視圖影響導出,可以在調用mysqldump時增加--force參數,強行忽略此錯誤。這個忽略不會對資料造成影響;

2) 使用--result-file參數儲存mysqldump結果,同時将所有控制台收到的傳回都作為報警傳回給調用端;

3) 檢查 result-file的最後一行,若無“Dump completed on"字樣,則傳回嚴重錯誤,終止備份恢複流程。

繼續閱讀