環境準備
- OS: CentOS 7.x
- MySQL: 5.7+ (已安裝並運行,datadir=/var/lib/mysql)
- 目標: 安裝 XtraBackup 2.4/8.0 並實現壓縮備份/自動恢復
快速安裝 (二進制包解壓即用)
# 1. 下載對應版本 (Percona 官網)
cd /opt
wget https://downloads.percona.com/downloads/Percona-XtraBackup-2.4/Percona-XtraBackup-2.4.28/binary/redhat/7/x86_64/percona-xtrabackup-2.4.28-1.el7.x86_64.rpm
# 2. 解壓 RPM (不安裝,直接提取二進制)
rpm2cpio percona-xtrabackup-2.4.28-1.el7.x86_64.rpm | cpio -idmv
# 3. 複製核心工具到 PATH
cp usr/bin/innobackupex /usr/local/bin/
cp usr/bin/xtrabackup /usr/local/bin/
cp usr/bin/xtrabackup_55 /usr/local/bin/ # MySQL 5.5
cp usr/bin/xtrabackup_56 /usr/local/bin/ # MySQL 5.6
cp usr/bin/xtrabackup_57 /usr/local/bin/ # MySQL 5.7
# 4. 驗證
innobackupex --version
xtrabackup --version
核心參數速查表
| 參數 | 說明 | 典型值 |
| --user | 資料庫用戶 | backup_user |
| --password | 密碼 (建議用 --defaults-file) | xxx |
| --defaults-file | my.cnf 路徑 | /etc/my.cnf |
| --database | 指定庫 (不加 = 全庫) | mydb |
| --stream=tar | 串流輸出 tar 格式 | 配合管道壓縮 |
| --compress | 快速壓縮 (需 qpress) | 節省空間 |
| --parallel=N | 並行複製線程數 | 4-8 |
| --no-timestamp | 不生成時間戳目錄 | 固定路徑便於腳本 |
| --slave-info | 記錄主庫 binlog 位置 | 從庫備份必加 |
| --apply-log | 準備階段 (redo log 重放) | 恢復前必執行 |
| --copy-back | 複製回 datadir | 恢復最後步驟 |
實戰:壓縮備份腳本 (生產就緒)
#!/bin/bash
# /usr/local/bin/xtrabackup_full.sh
# 功能:每日全量壓縮備份,保留 7 天
set -euo pipefail
# ===== 配置區 =====
MY_CNF="/etc/my.cnf"
DB_USER="backup_user"
DB_PASS="your_strong_password"
BACKUP_ROOT="/data/backup/mysql"
RETENTION_DAYS=7
PARALLEL=4
COMPRESS_THREADS=4
LOG_FILE="/var/log/xtrabackup_full.log"
# ==================
DATE=$(date +%F_%H-%M)
BACKUP_DIR="$BACKUP_ROOT/full_$DATE"
LOG_DIR="$BACKUP_ROOT/logs"
mkdir -p "$BACKUP_DIR" "$LOG_DIR"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "[$(date)] ===== 開始全量備份 ====="
echo "目標目錄: $BACKUP_DIR"
# 執行備份
innobackupex \
--defaults-file="$MY_CNF" \
--user="$DB_USER" \
--password="$DB_PASS" \
--no-timestamp \
--parallel=$PARALLEL \
--compress \
--compress-threads=$COMPRESS_THREADS \
--slave-info \
"$BACKUP_DIR" 2>&1 | tee -a "$LOG_DIR/full_$DATE.log"
EXIT_CODE=${PIPESTATUS[0]}
if [ $EXIT_CODE -eq 0 ]; then
echo "[$(date)] ✅ 備份成功: $BACKUP_DIR"
# 記錄備份元信息
echo "$DATE|full|$BACKUP_DIR|$(du -sh $BACKUP_DIR | cut -f1)" >> "$BACKUP_ROOT/backup_index.log"
else
echo "[$(date)] ❌ 備份失敗,退出碼: $EXIT_CODE"
rm -rf "$BACKUP_DIR"
exit 1
fi
# 清理舊備份
echo "[$(date)] 清理 $RETENTION_DAYS 天前備份..."
find "$BACKUP_ROOT" -maxdepth 1 -type d -name 'full_*' -mtime +$RETENTION_DAYS -exec rm -rf {} \;
find "$LOG_DIR" -type f -mtime +$RETENTION_DAYS -delete
echo "[$(date)] ===== 備份任務結束 ====="
實戰:恢復操作標準流程
#!/bin/bash
# /usr/local/bin/xtrabackup_restore.sh
# 用法: ./xtrabackup_restore.sh /data/backup/mysql/full_2024-01-15_02-00
set -euo pipefail
BACKUP_DIR="${1:-}"
if [ -z "$BACKUP_DIR" ] || [ ! -d "$BACKUP_DIR" ]; then
echo "用法: $0 <備份目錄路徑>"
exit 1
fi
MY_CNF="/etc/my.cnf"
DB_USER="root"
DB_PASS="your_password"
DATADIR="/var/lib/mysql"
echo "[$(date)] 開始恢復: $BACKUP_DIR"
# 1. 停止 MySQL
systemctl stop mysqld
echo "MySQL 已停止"
# 2. 備份當前數據 (安全網)
mv "$DATADIR" "${DATADIR}_bak_$(date +%s)"
mkdir -p "$DATADIR"
echo "原數據目錄已備份"
# 3. 解壓 (若為壓縮備份)
if ls "$BACKUP_DIR"/*.qp 2>/dev/null; then
echo "檢測到壓縮備份,正在解壓..."
xtrabackup --decompress --target-dir="$BACKUP_DIR" --parallel=4
find "$BACKUP_DIR" -name "*.qp" -delete
fi
# 4. 準備備份 (核心步驟)
echo "執行 --apply-log..."
innobackupex --defaults-file="$MY_CNF" --apply-log "$BACKUP_DIR"
# 5. 複製回數據目錄
echo "執行 --copy-back..."
innobackupex --defaults-file="$MY_CNF" --copy-back "$BACKUP_DIR"
# 6. 修正權限
chown -R mysql:mysql "$DATADIR"
# 7. 清理殘留 xtrabackup 文件
rm -f "$DATADIR"/xtrabackup_*
# 8. 啟動 MySQL
systemctl start mysqld
sleep 3
# 9. 驗證
if mysql -u"$DB_USER" -p"$DB_PASS" -e "SELECT 1;" >/dev/null 2>&1; then
echo "[$(date)] ✅ 恢復成功並驗證通過"
else
echo "[$(date)] ❌ 恢復後連線失敗,請檢查日誌"
exit 1
fi
增量備份策略 (配合全量)
#!/bin/bash
# /usr/local/bin/xtrabackup_inc.sh
# 每 4 小時執行一次增量
MY_CNF="/etc/my.cnf"
DB_USER="backup_user"
DB_PASS="xxx"
BACKUP_ROOT="/data/backup/mysql"
# 找到最新的基準目錄 (優先增量,其次全量)
LATEST_BASE=$(ls -1dt "$BACKUP_ROOT"/inc_* "$BACKUP_ROOT"/full_* 2>/dev/null | head -1)
if [ -z "$LATEST_BASE" ]; then
echo "無基準備份,請先執行全量備份"
exit 1
fi
DATE=$(date +%F_%H-%M)
INC_DIR="$BACKUP_ROOT/inc_$DATE"
innobackupex \
--defaults-file="$MY_CNF" \
--user="$DB_USER" \
--password="$DB_PASS" \
--no-timestamp \
--incremental "$INC_DIR" \
--incremental-basedir="$LATEST_BASE"
echo "增量備份完成: $INC_DIR (基於 $LATEST_BASE)"
定時任務配置
# crontab -e (root 用戶)
# 每日 02:00 全量備份
0 2 * * * /usr/local/bin/xtrabackup_full.sh
# 每 4 小時增量備份
0 */4 * * * /usr/local/bin/xtrabackup_inc.sh
# 每週日 04:00 執行恢復演練 (測試環境)
0 4 * * 0 /usr/local/bin/xtrabackup_restore.sh /data/backup/mysql/full_$(date -d 'yesterday' +%F)_02-00
常見問題排查
| 問題 | 原因 | 解決 |
| innobackupex: command not found | 未加入 PATH | cp 到 /usr/local/bin 或 export PATH |
| Error: unknown option --compress | 版本不支援 | 升級 XtraBackup 或用管道 gzip |
| 備份卡住無響應 | MyISAM 表加鎖 | 評估業務窗口或遷移至 InnoDB |
| 恢復後表不存在 | .frm 文件缺失 | xtrabackup 不備份 .frm,確認使用 innobackupex |
| 權限拒絕 | datadir 權限錯誤 | chown -R mysql:mysql /var/lib/mysql |
生產環境核心建議
- 專用備份賬號:最小權限原則,禁止使用 root
- 異地備份:備份完成後同步至異地存儲 (S3/OSS/NFS)
- 加密傳輸:rsync over SSH 或加密壓縮包
- 監控告警:備份耗時、大小、成功率納入監控體系
- 文檔化恢復流程:壓力測試環境每月演練,記錄 RTO