在生產環境中,資料庫的備份與還原是 DBA 核心職責之一。Percona XtraBackup 的 innobackupex 工具支援熱備份、增量備份且不阻塞寫入,是 MySQL 物理備份的主流選擇。本文提供一個生產級的自動還原 Shell 腳本,支援全量備份與增量備份的鏈式還原,並包含錯誤檢測、權限修復、服務自動啟動驗證等完整流程。
completed OK! 關鍵字,失敗即時輸出日誌並保存my.cnf 中的 datadir 並執行 chown -R mysql:mysqlinnobackupex 位於 /usr/bin//backup/full/ 存放全量備份,/backup/incre/ 存放增量備份/usr/local/mysql/my.cnf#!/bin/sh
# 使用方法:./restore.sh /備份文件的全路徑
# 作者:ocpyang@126.com
INNOBACKUPEX=innobackupex
INNOBACKUPEX_PATH=/usr/bin/$INNOBACKUPEX
TMP_LOG="/var/log/restore.$$.log"
MY_CNF=/usr/local/mysql/my.cnf
BACKUP_DIR=/backup
FULLBACKUP_DIR=$BACKUP_DIR/full
INCRBACKUP_DIR=$BACKUP_DIR/incre
MEMORY=4096M
#############################################################################
# 錯誤處理函數
#############################################################################
error() {
echo "$1" 1>&2
exit 1
}
#############################################################################
# 檢查 innobackupex 執行結果
#############################################################################
check_innobackupex_fail() {
if [ -z "`tail -2 $TMP_LOG | grep 'completed OK!'`" ]; then
echo "$INNOBACKUPEX 命令執行失敗:"
echo "---------- $INNOBACKUPEX 錯誤輸出 ----------"
cat $TMP_LOG
logfiledate=restore.`date +%Y%m%d%H%M`.txt
cat $TMP_LOG > /backup/$logfiledate
rm -f $TMP_LOG
exit 1
fi
}
# 參數檢查
if [ ! -x $INNOBACKUPEX_PATH ]; then
error "$INNOBACKUPEX_PATH 不存在,請確認安裝路徑或軟連結。"
fi
if [ ! -d $BACKUP_DIR ]; then
error "備份目錄 $BACKUP_DIR 不存在。"
fi
if [ $# != 1 ]; then
error "用法: $0 還原目錄的絕對路徑"
fi
if [ ! -d $1 ]; then
error "還原路徑 $1 不存在。"
fi
echo "----------------------------"
echo "$0: MySQL 還原腳本"
START_RESTORE_TIME=`date +'%F %T %w'`
echo "資料庫還原開始於: $START_RESTORE_TIME"
echo
PARENT_DIR=`dirname $1`
# 判斷備份類型:全量備份或增量備份
if [ $PARENT_DIR = $FULLBACKUP_DIR ]; then
FULLBACKUP=$1
echo "還原全量備份: `basename $FULLBACKUP`"
echo
else
if [ `dirname $PARENT_DIR` = $INCRBACKUP_DIR ]; then
INCR=`basename $1`
FULL=`basename $PARENT_DIR`
FULLBACKUP=$FULLBACKUP_DIR/$FULL
if [ ! -d $FULLBACKUP ]; then
error "全量備份 $FULLBACKUP 不存在。"
fi
echo "還原全量備份 $FULL 至增量備份 $INCR"
echo
# 1. 準備全量備份 (--redo-only)
echo "Prepare 全量備份集..........."
echo "*****************************"
$INNOBACKUPEX_PATH --defaults-file=$MY_CNF --apply-log --redo-only --use-memory=$MEMORY $FULLBACKUP > $TMP_LOG 2>&1
check_innobackupex_fail
# 2. 依序準備增量備份
for i in `find $PARENT_DIR -mindepth 1 -maxdepth 1 -type d -printf "%P\n" | sort -n`; do
echo "Prepare 增量備份集 $i........"
echo "*****************************"
$INNOBACKUPEX_PATH --defaults-file=$MY_CNF --apply-log --redo-only --use-memory=$MEMORY $FULLBACKUP --incremental-dir=$PARENT_DIR/$i > $TMP_LOG 2>&1
check_innobackupex_fail
if [ $INCR = $i ]; then
break
fi
done
else
error "未知的備份類型"
fi
fi
# 3. 最後一次 apply-log 回滾未提交事務
echo "準備全量備份集,回滾未提交事務..........."
$INNOBACKUPEX_PATH --defaults-file=$MY_CNF --apply-log --use-memory=$MEMORY $FULLBACKUP > $TMP_LOG 2>&1
check_innobackupex_fail
echo "*****************************"
echo "1. 資料庫還原中 ... 請稍等"
echo "*****************************"
# 4. 複製回原數據目錄
$INNOBACKUPEX_PATH --defaults-file=$MY_CNF --copy-back $FULLBACKUP > $TMP_LOG 2>&1
check_innobackupex_fail
rm -f $TMP_LOG
echo "2. 恭喜,還原成功!"
echo "*****************************"
# 5. 修改目錄權限
echo "修改 MySQL 目錄權限。"
mysqlcnf="/usr/local/mysql/my.cnf"
mysqldatadir=`grep -i "^basedir=" $mysqlcnf`
`echo 'chown -R mysql:mysql' ${mysqldatadir:8}`
echo "3. 權限修改成功!"
echo "*****************************"
# 6. 互動式啟動 MySQL
echo -n "請輸入 1 確認啟動 MySQL: "
read var
echo "您輸入的是 $var"
errorlog=`grep -i "^log-error" $MY_CNF`
if [ $var = 1 ]; then
echo "MySQL 啟動中............"
`/usr/local/mysql/bin/mysqld_safe > /dev/null &`
sleep 10
PortNum=`netstat -lnt | grep 3306 | wc -l`
if [ $PortNum = 1 ]; then
echo "4. MySQL 啟動成功"
echo "*****************************"
else
echo "4. MySQL 啟動失敗,請檢查錯誤日誌 $errorlog"
echo "*****************************************"
fi
exit 0
else
echo "輸入不正確!"
fi
END_RESTORE_TIME=`date +'%F %T %w'`
echo "資料庫還原完成於: $END_RESTORE_TIME"
exit 0
增量備份必須按生成順序依次應用到全量備份上:
--apply-log --redo-only--apply-log --redo-only --incremental-dir=...--redo-only 的 --apply-log 回滾未提交事務sort -n 確保按目錄名(通常為時間戳)升序處理,break 在達到目標增量備份時停止。
每次檢查失敗時,會將完整臨時日誌複製到 /backup/restore.YYYYMMDDHHMM.txt,方便事後排查,同時清理臨時文件。
從 my.cnf 解析 basedir,去除前綴 basedir= 後執行 chown,避免硬編碼路徑。
read var,改為參數控制或配合編排系統--decompress 參數支援 xbstream 格式--use-memory 搭配 --parallel 加速/var/log/restore.*.log 建議接入 logrotate 管理| 現象 | 可能原因 | 解決方案 |
|---|---|---|
| completed OK! 未出現 | 磁盤空間不足、權限問題、備份文件損壞 | 檢查 df -h、確認 mysql 用戶權限、驗證備份完整性 |
| copy-back 後 MySQL 無法啟動 | datadir 路徑錯誤、selinux、配置文件不匹配 | 核對 my.cnf datadir、臨時關閉 selinux、對比配置參數 |
| 增量備份 apply 失敗 | 增量備份序列缺失、LSN 不連續 | 確認增量備份目錄完整、檢查 xtrabackup_checkpoints |
本腳本實現了 MySQL 5.6 環境下基於 innobackupex 的全自動還原流程,涵蓋全量與增量備份的完整生命週期。實際部署時建議根據業務 RTO/RPO 要求,結合備份驗證、自動化編排(Ansible/Jenkins)、監控告警構建完整的災備體系。