邏輯備份 (mysqldump) 在 500GB 以上數據量面前力不從心:導出慢、導入更慢、佔用大量 CPU。Percona XtraBackup 基於 InnoDB Redo Log 拷貝數據文件,實現熱備份(不鎖表、不阻塞讀寫)、並行壓縮、增量備份、流式傳輸,是生產環境物理備份的事實標準。本文提供生產就緒的自動化腳本、關鍵參數解析、恢復流程與避坑指南。
# 1. 下載對應版本包 (Percona 官網)
wget https://www.percona.com/downloads/Percona-XtraBackup-2.4/Percona-XtraBackup-2.4.28/binary/tarball/percona-xtrabackup-2.4.28-Linux-x86_64.tar.gz
# 2. 解壓安裝
tar zxf percona-xtrabackup-2.4.28-Linux-x86_64.tar.gz
mkdir -p /usr/local/xtrabackup
cp -r percona-xtrabackup-2.4.28-Linux-x86_64/* /usr/local/xtrabackup/
# 3. 環境變量
echo 'export PATH=$PATH:/usr/local/xtrabackup/bin' >> /etc/profile
source /etc/profile
# 4. 依賴包
yum -y install perl-Time-HiRes perl-DBD-MySQL libev numactl-libs
CREATE USER 'xbkp'@'localhost' IDENTIFIED BY 'Xbkp@StrongPass2024';
GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT, SUPER, CREATE TABLESPACE ON *.* TO 'xbkp'@'localhost';
FLUSH PRIVILEGES;
mkdir -p /data/backup/xtrabackup/{full,incr}
mkdir -p /data/backup/xtrabackup_log
/usr/local/sbin/xtrabackup_full_incr.sh#!/bin/bash
# xtrabackup_full_incr.sh
# 全量備份間隔 23h (82800s),保留 3 份全備及其增量鏈
# 每小時執行一次:0 * * * * /usr/local/sbin/xtrabackup_full_incr.sh >> /data/backup/xtrabackup_log/cron.log 2>&1
set -euo pipefail
INNOBACKUPEX=/usr/local/xtrabackup/bin/innobackupex
MY_CNF=/etc/my.cnf
MYSQL_USER=xbkp
MYSQL_PASS='Xbkp@StrongPass2024'
MYSQL_HOST=localhost
MYSQL_PORT=3306
BACKUP_ROOT=/data/backup/xtrabackup
FULL_DIR=$BACKUP_ROOT/full
INCR_DIR=$BACKUP_ROOT/incr
LOG_DIR=/data/backup/xtrabackup_log
FULL_INTERVAL=82800
KEEP_FULL=3
THREADS=4
COMPRESS_THREADS=2
USE_MEMORY=4G
LOG_FILE=$LOG_DIR/backup_$(date +%Y%m%d_%H%M%S).log
exec >> $LOG_FILE 2>&1
echo "========== $(date '+%F %T') Backup Start =========="
# 1. 檢查環境
[ -x $INNOBACKUPEX ] || { echo "ERROR: innobackupex not found"; exit 1; }
[ -d $BACKUP_ROOT ] || { echo "ERROR: backup root missing"; exit 1; }
mysqladmin -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PASS -P$MYSQL_PORT ping >/dev/null 2>&1 || { echo "ERROR: MySQL unreachable"; exit 1; }
mkdir -p $FULL_DIR $INCR_DIR
# 2. 尋找最新有效全備
LATEST_FULL=$(find $FULL_DIR -mindepth 1 -maxdepth 1 -type d -printf '%P\n' | sort -r | head -1)
if [ -n "$LATEST_FULL" ]; then
LATEST_FULL_TS=$(stat -c %Y "$FULL_DIR/$LATEST_FULL")
NOW_TS=$(date +%s)
if [ $((LATEST_FULL_TS + FULL_INTERVAL + 300)) -ge $NOW_TS ]; then
# 全備未過期 → 增量備份
echo "Incremental backup based on $LATEST_FULL"
INCR_BASE=$FULL_DIR/$LATEST_FULL
# 尋找最新增量
LATEST_INCR=$(find $INCR_DIR/$LATEST_FULL -mindepth 1 -maxdepth 1 -type d -printf '%P\n' 2>/dev/null | sort -r | head -1)
[ -n "$LATEST_INCR" ] && INCR_BASE=$INCR_DIR/$LATEST_FULL/$LATEST_INCR
INCR_TARGET=$INCR_DIR/$LATEST_FULL/incr_$(date +%Y%m%d_%H%M%S)
mkdir -p $INCR_TARGET
$INNOBACKUPEX --defaults-file=$MY_CNF --user=$MYSQL_USER --password=$MYSQL_PASS --host=$MYSQL_HOST --port=$MYSQL_PORT \
--parallel=$THREADS --compress --compress-threads=$COMPRESS_THREADS --use-memory=$USE_MEMORY \
--incremental $INCR_TARGET --incremental-basedir=$INCR_BASE \
--no-timestamp 2>&1 | tee -a $LOG_FILE
if [ ${PIPESTATUS[0]} -eq 0 ]; then
echo "SUCCESS: Incremental backup to $INCR_TARGET"
else
echo "FAILED: Incremental backup"
exit 1
fi
else
# 全備過期 → 新全備
goto_full
fi
else
# 無全備 → 新全備
goto_full
fi
# 3. 清理過期備份 (保留 KEEP_FULL 份全備鏈)
echo "Cleaning expired backups..."
find $FULL_DIR -mindepth 1 -maxdepth 1 -type d -mtime +$((KEEP_FULL*1)) -exec rm -rf {} \;
find $INCR_DIR -mindepth 1 -maxdepth 1 -type d -mtime +$((KEEP_FULL*1)) -exec rm -rf {} \;
echo "========== $(date '+%F %T') Backup End =========="
exit 0
: <<'FULL_BACKUP_LABEL'
goto_full:
echo "Full backup starting..."
FULL_TARGET=$FULL_DIR/full_$(date +%Y%m%d_%H%M%S)
mkdir -p $FULL_TARGET
$INNOBACKUPEX --defaults-file=$MY_CNF --user=$MYSQL_USER --password=$MYSQL_PASS --host=$MYSQL_HOST --port=$MYSQL_PORT \
--parallel=$THREADS --compress --compress-threads=$COMPRESS_THREADS --use-memory=$USE_MEMORY \
$FULL_TARGET --no-timestamp 2>&1 | tee -a $LOG_FILE
if [ ${PIPESTATUS[0]} -eq 0 ]; then
echo "SUCCESS: Full backup to $FULL_TARGET"
else
echo "FAILED: Full backup"
exit 1
fi
FULL_BACKUP_LABEL
| 參數 | 含義 | 建議值 |
|---|---|---|
--parallel | 並行拷貝線程數 | CPU 核心數 50-75% |
--compress | 啟用 qpress 壓縮 (.qp 後綴) | 生產必開,節省 60-70% 空間 |
--compress-threads | 壓縮線程數 | 2-4 |
--use-memory | 崩潰恢復階段內存上限 | 物理內存 20-30% |
--incremental-basedir | 增量基準目錄 | 上一輪全備或增備目錄 |
--no-timestamp | 不在目標目錄下再創建時間戳子目錄 | 腳本自控目錄結構必加 |
--slave-info | 備份從庫時記錄主庫位點 | 從庫備份必加 |
--safe-slave-backup | 暫停 SQL 線程確保一致性 | 從庫備份建議加 |
cd /data/backup/xtrabackup/full/full_20240115_020000
for f in *.qp; do qpress -d $f $(dirname $f) && rm -f $f; done
innobackupex --apply-log --use-memory=4G /data/backup/xtrabackup/full/full_20240115_020000
# 若有增量鏈,依序應用
innobackupex --apply-log --redo-only --use-memory=4G /data/backup/xtrabackup/full/full_20240115_020000 \
--incremental-dir=/data/backup/xtrabackup/incr/full_20240115_020000/incr_20240115_030000
innobackupex --apply-log --redo-only --use-memory=4G /data/backup/xtrabackup/full/full_20240115_020000 \
--incremental-dir=/data/backup/xtrabackup/incr/full_20240115_020000/incr_20240115_040000
# 最後一輪不加 --redo-only
innobackupex --apply-log --use-memory=4G /data/backup/xtrabackup/full/full_20240115_020000
systemctl stop mysqld
mv /var/lib/mysql /var/lib/mysql.bak.$(date +%s)
innobackupex --copy-back --use-memory=4G /data/backup/xtrabackup/full/full_20240115_020000
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld
mysql -e "CHECKSUM TABLE db1.t1, db2.t2;"
# 對比備份前後 checksum
innodb_log_file_size 變更後首次備份會報錯,需先 --apply-log 一次全備CREATE TABLESPACE 導致 8.0 備份失敗--slave-info --safe-slave-backup,恢復後 gtid_purged 自動修正--copy-back --parallel 加速還原XtraBackup 以物理拷貝 + Redo Log 重放實現熱備份,配合並行壓縮、增量鏈、自動清理腳本,可支撐 TB 級生產庫 RPO < 1h、RTO < 30min 目標。核心在於:定期演練恢復、監控備份耗時/大小/成功率、版本升級同步升級工具。將備份納入 CI/CD 流水線,才是真正的生產就緒。