故障分析 | MySQL 備份檔案靜默損壞一例分析

愛可生雲資料庫發表於2023-03-14

作者:付祥

現居珠海,主要負責 Oracle、MySQL、mongoDB 和 Redis 維護工作。

本文來源:原創投稿

*愛可生開源社群出品,原創內容未經授權不得隨意使用,轉載請聯絡小編並註明來源。


背景

線上一套 MySQL 計劃升級到 8.0 ,透過備份還原搭建一個測試環境,用於升級測試。資料庫採用 xtrabackup 每天進行全備,壓縮備份檔案約 300G ,解壓到一半就報錯了:

gzip: stdin: invalid compressed data--format violated
tar: Unexpected EOF in archive
tar: Unexpected EOF in archive
tar: Error is not recoverable: exiting now

剛開始以為只是這個備份檔案不完整,又找了前一天備份檔案,解壓過程中也報了同樣的錯誤,備份檔案比較大,無疑增加了排障時間。

故障分析

備份指令碼透過 crontab 每天凌晨執行,線上都是同一套備份指令碼,不同專案時常做備份資料還原,還是頭一次遇到備份檔案解壓失敗現象,檢視了指令碼,每個關鍵階段都做了狀態碼判斷是否成功,若失敗就告警,同時對 xtrabackup 備份日誌最後一行是否包含 completed OK 關鍵詞也做了判斷,關鍵備份指令碼如下:

xtrabackup xxx --stream=tar  --no-timestamp $bkdir 2> xxx.log | gzip - > xxx.tar.gz

近期也沒收到失敗告警,說明備份指令碼是執行成功了的,感覺太奇怪了,檢視定時任務日誌,發現同一任務同一時間點竟然啟了2次:

[root@localhost backup]# grep backup /var/log/cron
Mar  6 00:00:01 localhost CROND[6212]: (root) CMD (sh xxx/mysql_ftp_backup.sh || echo 1 > xxx/err.log)
Mar  6 00:00:01 localhost CROND[6229]: (root) CMD (sh xxx/mysql_ftp_backup.sh || echo 1 > xxx/err.log)
Mar  7 00:00:01 localhost CROND[5387]: (root) CMD (sh xxx/mysql_ftp_backup.sh || echo 1 > xxx/err.log)
Mar  7 00:00:01 localhost CROND[5420]: (root) CMD (sh xxx/mysql_ftp_backup.sh || echo 1 > xxx/err.log)

crond 服務每次同時拉起2個程式執行備份,併發地往同一個壓縮檔案 xxx.tar.gz 寫資料,備份資料相互覆蓋,導致備份檔案損壞,每天看似備份成功的任務,其實備份都是無效的,這也說明瞭定期備份恢復演練的重要性。為何定時任務同一時間點會啟動2次?檢視 crond 程式:

[root@localhost backup]# ps -ef|grep crond |grep -v grep
root 2883 1 0 2018 ? 01:42:46 crond 
root 17293 1 0 2022 ? 00:43:22 crond

原來是因為系統啟動了2個 crond 程式,kill crond 程式後重啟,再次檢視只有一個 crond 程式:

[root@localhost backup]# service crond stop
Stopping crond:                                            [  OK  ]

[root@localhost backup]# ps -ef|grep crond
root      2883     1  0  2018 ?        01:42:46 crond
root     31486 31856  0 10:59 pts/2    00:00:00 grep crond

[root@localhost backup]# kill 2883
[root@localhost backup]# ps -ef|grep crond
root     31572 31856  0 10:59 pts/2    00:00:00 grep crond

[root@localhost backup]# service crond start
Starting crond:                                            [  OK  ]
[root@localhost backup]# ps -ef|grep crond
root     31632     1  0 10:59 ?        00:00:00 crond
root     31639 31856  0 11:00 pts/2    00:00:00 grep crond

總結

為了確保備份有效,需要做如下改進:

1、flock給指令碼執行加互斥鎖,確保一個時間點只有1個程式執行。

2、定期做備份恢復演練。

3、增加crond程式監控,不等於1告警。

相關文章