定时任务 crontab
- -e : 编辑定时任务
- -l : 显示定时任务
`sh
[root@slave01 ~]# crontab -l
* * * * * shell command parameter
- echo “hello world”
#分 时 日 月 周 命令
0 2 * * * /bin/ntpdate ntp.ntsc.ac.cn #定时做时间同步
*/15 2 1 * * echo “hello”
*/2 * * * * mysqladmin ping localhost
1-15,45-50 2 * * * echo “1” >/opt/cronta.log
30-50/10 * * * * echo 11
0 2 * * 1-6 /backup/bin/mysqlbackup_increment
0 2 * * 0 /backup/bin/mysqlbackup_whole
1 * * * * /backup/bin/rotatelog.sh >> /backup/log/rotate.log 2>&1
1 * * * * sleep 30; /backup/bin/rotatelog.sh >> /backup/log/rotate.log 2>&1
- echo “hello world”
# 数据不同步,在gtid模式下
在master机器上导出数据,记录当前的position
mysqldump -uroot -pRoot@1234 –single-transaction –lock-tables –all-databases –triggers –routines –events >all.dat
scp all.dat user@remote_ip:.
必须在slave机器先执行
`mysql -uroot -pRoot@1234 -e "RESET MASTER;"`
然后再导入 master机器上的数据库。
`mysql -uroot -pRoot@1234 < all.dat
# MySQL 备份工具详解与备份脚本
数据库一般都需要进行备份,备份的策略一般是
- 周一-周六 每天增量备份
- 周日 全量备份
- 备份保留最近的7份文件
- 备份的时间一般是凌晨 2-3点
## 一、mysqldump 详解
### 1.1 mysqldump 基本用法
数据量小50G,比较合适
另外一个公司 mysqldumper,适合50-200G大小的数据库
xtra-backup, 200G都适合。
```bash
# 基本语法
mysqldump [options] database [tables]
# 常用参数
-u, --user=username # 用户名
-p, --password[=password] # 密码
-h, --host=hostname # 主机名
-P, --port=port # 端口
--databases # 备份多个数据库
--all-databases # 备份所有数据库
--single-transaction # 对InnoDB使用事务保证一致性
--master-data[=value] # 记录二进制日志位置(1-注释,2-变更)
--flush-logs # 备份前刷新日志
--routines # 包含存储过程和函数
--events # 包含事件
--triggers # 包含触发器
--lock-tables # 对所有表加读锁
--skip-lock-tables # 不加锁
--compress # 压缩传输
--where='where_condition' # 条件备份1.2 mysqldump 全量备份示例
# 备份单个数据库
mysqldump -u root -p --single-transaction --routines --tri·ggers mydb > backup.sql
# 备份多个数据库
mysqldump -u root -p --databases db1 db2 db3 > backup.sql
# 备份所有数据库
mysqldump -u root -p --all-databases --single-transaction > alldb_backup.sql
# 备份文件带时间的数据库
mysqldump -uroot -pRoot@1234 --single-transaction --lock-tables db03 >/backup/db03.`date +%Y%m%d-%H%M%S`.sql
# 压缩备份
mysqldump -u root -p mydb | gzip > backup.sql.gz
# 分表备份
mysqldump -u root -p mydb table1 table2 > tables_backup.sql
二、Percona XtraBackup 详解
2.1 XtraBackup 特性
- 物理备份,速度快
- 支持热备份(备份期间不锁表)
- 支持增量备份
- 支持压缩备份
- 支持流式备份
2.2 常用命令
# 全量备份
xtrabackup --backup --target-dir=/path/to/backup --user=root --password=xxx
# 增量备份(基于前一个备份)
xtrabackup --backup --target-dir=/path/to/incremental \
--incremental-basedir=/path/to/full_backup \
--user=root --password=xxx
# 准备备份(应用事务日志)
xtrabackup --prepare --apply-log-only --target-dir=/path/to/full_backup
xtrabackup --prepare --target-dir=/path/to/full_backup
# 恢复备份
xtrabackup --copy-back --target-dir=/path/to/backup
三、备份脚本实现
3.1 mysqldump 备份脚本
全量备份脚本 (mysqldump_full.sh)
#!/bin/bash
# mysqldump_full.sh - 全量备份脚本
# 配置参数
BACKUP_DIR="/data/backup/mysql"
LOG_FILE="/var/log/mysql_backup.log"
MYSQL_USER="root"
MYSQL_PASSWORD="your_password"
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
RETENTION_DAYS=30
COMPRESS_LEVEL=9
# 创建备份目录
DATE=$(date +%Y%m%d_%H%M%S)
FULL_BACKUP_DIR="${BACKUP_DIR}/full_${DATE}"
mkdir -p ${FULL_BACKUP_DIR}
# 记录开始时间
echo "==========================================" >> ${LOG_FILE}
echo "全量备份开始: $(date)" >> ${LOG_FILE}
# 备份所有数据库
echo "备份所有数据库..." >> ${LOG_FILE}
mysqldump \
--user=${MYSQL_USER} \
--password=${MYSQL_PASSWORD} \
--host=${MYSQL_HOST} \
--port=${MYSQL_PORT} \
--all-databases \
--single-transaction \
--routines \
--events \
--triggers \
--master-data=2 \
--flush-logs \
--default-character-set=utf8mb4 > ${FULL_BACKUP_DIR}/full_backup_${DATE}.sql 2>> ${LOG_FILE}
# 检查备份结果
if [ $? -eq 0 ]; then
echo "数据库备份成功" >> ${LOG_FILE}
# 压缩备份文件
echo "压缩备份文件..." >> ${LOG_FILE}
gzip -${COMPRESS_LEVEL} ${FULL_BACKUP_DIR}/full_backup_${DATE}.sql
# 备份配置文件
echo "备份MySQL配置文件..." >> ${LOG_FILE}
cp /etc/my.cnf ${FULL_BACKUP_DIR}/ 2>> ${LOG_FILE} || cp /etc/mysql/my.cnf ${FULL_BACKUP_DIR}/ 2>> ${LOG_FILE}
# 生成备份信息
echo "备份时间: ${DATE}" > ${FULL_BACKUP_DIR}/backup.info
echo "备份类型: 全量备份" >> ${FULL_BACKUP_DIR}/backup.info
echo "备份大小: $(du -sh ${FULL_BACKUP_DIR} | awk '{print $1}')" >> ${FULL_BACKUP_DIR}/backup.info
else
echo "数据库备份失败" >> ${LOG_FILE}
rm -rf ${FULL_BACKUP_DIR}
exit 1
fi
# 清理旧备份
echo "清理超过${RETENTION_DAYS}天的旧备份..." >> ${LOG_FILE}
find ${BACKUP_DIR}/full_* -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} \; 2>> ${LOG_FILE}
echo "全量备份完成: $(date)" >> ${LOG_FILE}
echo "备份目录: ${FULL_BACKUP_DIR}" >> ${LOG_FILE}
echo "==========================================" >> ${LOG_FILE}
增量备份脚本 (mysqldump_incremental.sh)
#!/bin/bash
# mysqldump_incremental.sh - 增量备份脚本(基于二进制日志)
# 配置参数
BACKUP_DIR="/data/backup/mysql"
LOG_FILE="/var/log/mysql_backup.log"
MYSQL_USER="root"
MYSQL_PASSWORD="your_password"
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
RETENTION_DAYS=7
BINLOG_DIR="/var/lib/mysql"
# 获取当前二进制日志信息
DATE=$(date +%Y%m%d_%H%M%S)
INCR_BACKUP_DIR="${BACKUP_DIR}/incr_${DATE}"
mkdir -p ${INCR_BACKUP_DIR}
# 记录开始时间
echo "==========================================" >> ${LOG_FILE}
echo "增量备份开始: $(date)" >> ${LOG_FILE}
# 刷新日志,生成新的二进制日志文件
mysql -u${MYSQL_USER} -p${MYSQL_PASSWORD} -h${MYSQL_HOST} -P${MYSQL_PORT} \
-e "FLUSH BINARY LOGS;" 2>> ${LOG_FILE}
# 获取当前二进制日志文件
CURRENT_BINLOG=$(mysql -u${MYSQL_USER} -p${MYSQL_PASSWORD} -h${MYSQL_HOST} -P${MYSQL_PORT} \
-N -e "SHOW MASTER STATUS\G" 2>> ${LOG_FILE} | grep 'File:' | awk '{print $2}')
CURRENT_POSITION=$(mysql -u${MYSQL_USER} -p${MYSQL_PASSWORD} -h${MYSQL_HOST} -P${MYSQL_PORT} \
-N -e "SHOW MASTER STATUS\G" 2>> ${LOG_FILE} | grep 'Position:' | awk '{print $2}')
echo "当前二进制日志: ${CURRENT_BINLOG}" >> ${LOG_FILE}
echo "当前位置: ${CURRENT_POSITION}" >> ${LOG_FILE}
# 查找上次全量备份的信息
LAST_FULL_BACKUP=$(find ${BACKUP_DIR} -name "full_backup_*.sql.gz" -type f | sort | tail -n1)
if [ -z "${LAST_FULL_BACKUP}" ]; then
echo "未找到全量备份,请先执行全量备份" >> ${LOG_FILE}
exit 1
fi
# 获取上次备份的二进制日志位置
LAST_BINLOG_INFO=$(zgrep "CHANGE MASTER TO" ${LAST_FULL_BACKUP} | head -1)
if [ -z "${LAST_BINLOG_INFO}" ]; then
echo "无法从全量备份中获取二进制日志信息" >> ${LOG_FILE}
exit 1
fi
# 从上次全量备份后,复制所有二进制日志
echo "备份二进制日志..." >> ${LOG_FILE}
cp ${BINLOG_DIR}/mysql-bin.* ${INCR_BACKUP_DIR}/ 2>> ${LOG_FILE}
# 生成备份信息
echo "备份时间: ${DATE}" > ${INCR_BACKUP_DIR}/backup.info
echo "备份类型: 增量备份" >> ${INCR_BACKUP_DIR}/backup.info
echo "基于全量备份: ${LAST_FULL_BACKUP}" >> ${INCR_BACKUP_DIR}/backup.info
echo "二进制日志范围: 从上次全量备份后 到 ${CURRENT_BINLOG}" >> ${INCR_BACKUP_DIR}/backup.info
echo "当前位置: ${CURRENT_POSITION}" >> ${INCR_BACKUP_DIR}/backup.info
# 清理旧增量备份
echo "清理超过${RETENTION_DAYS}天的旧增量备份..." >> ${LOG_FILE}
find ${BACKUP_DIR}/incr_* -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} \; 2>> ${LOG_FILE}
echo "增量备份完成: $(date)" >> ${LOG_FILE}
echo "备份目录: ${INCR_BACKUP_DIR}" >> ${LOG_FILE}
echo "==========================================" >> ${LOG_FILE}
3.2 XtraBackup 备份脚本
全量备份脚本 (xtrabackup_full.sh)
#!/bin/bash
# xtrabackup_full.sh - XtraBackup全量备份脚本
# 配置参数
BACKUP_BASE="/data/backup/xtrabackup"
LOG_FILE="/var/log/xtrabackup.log"
MYSQL_USER="root"
MYSQL_PASSWORD="your_password"
MYSQL_DATA_DIR="/var/lib/mysql"
RETENTION_DAYS=30
THREADS=4 # 并行线程数
# 创建备份目录
DATE=$(date +%Y%m%d_%H%M%S)
FULL_BACKUP_DIR="${BACKUP_BASE}/full_${DATE}"
mkdir -p ${FULL_BACKUP_DIR}
# 记录开始时间
echo "==========================================" >> ${LOG_FILE}
echo "XtraBackup全量备份开始: $(date)" >> ${LOG_FILE}
echo "备份目录: ${FULL_BACKUP_DIR}" >> ${LOG_FILE}
# 执行全量备份
echo "执行全量备份..." >> ${LOG_FILE}
xtrabackup \
--backup \
--target-dir=${FULL_BACKUP_DIR} \
--user=${MYSQL_USER} \
--password=${MYSQL_PASSWORD} \
--parallel=${THREADS} \
--compress \
--compress-threads=${THREADS} \
--stream=xbstream \
--extra-lsndir=${FULL_BACKUP_DIR} \
2>> ${LOG_FILE} | gzip > ${FULL_BACKUP_DIR}/backup.xbstream.gz
# 检查备份结果
if [ $? -eq 0 ]; then
echo "全量备份成功" >> ${LOG_FILE}
# 生成备份信息
echo "备份时间: ${DATE}" > ${FULL_BACKUP_DIR}/backup.info
echo "备份类型: 全量备份" >> ${FULL_BACKUP_DIR}/backup.info
echo "LSN信息:" >> ${FULL_BACKUP_DIR}/backup.info
cat ${FULL_BACKUP_DIR}/xtrabackup_checkpoints >> ${FULL_BACKUP_DIR}/backup.info
# 准备备份(测试)
echo "准备备份(应用日志)..." >> ${LOG_FILE}
xtrabackup --prepare --target-dir=${FULL_BACKUP_DIR} 2>> ${LOG_FILE}
if [ $? -eq 0 ]; then
echo "备份准备成功" >> ${LOG_FILE}
else
echo "备份准备失败" >> ${LOG_FILE}
fi
else
echo "全量备份失败" >> ${LOG_FILE}
rm -rf ${FULL_BACKUP_DIR}
exit 1
fi
# 清理旧备份
echo "清理超过${RETENTION_DAYS}天的旧备份..." >> ${LOG_FILE}
find ${BACKUP_BASE}/full_* -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} \; 2>> ${LOG_FILE}
echo "全量备份完成: $(date)" >> ${LOG_FILE}
echo "备份大小: $(du -sh ${FULL_BACKUP_DIR} | awk '{print $1}')" >> ${LOG_FILE}
echo "==========================================" >> ${LOG_FILE}
增量备份脚本 (xtrabackup_incremental.sh)
#!/bin/bash
# xtrabackup_incremental.sh - XtraBackup增量备份脚本
# 配置参数
BACKUP_BASE="/data/backup/xtrabackup"
LOG_FILE="/var/log/xtrabackup.log"
MYSQL_USER="root"
MYSQL_PASSWORD="your_password"
RETENTION_DAYS=7
THREADS=4
# 查找最新的全量备份
DATE=$(date +%Y%m%d_%H%M%S)
LATEST_FULL=$(find ${BACKUP_BASE} -name "full_*" -type d | sort | tail -n1)
if [ -z "${LATEST_FULL}" ]; then
echo "未找到全量备份,请先执行全量备份" >> ${LOG_FILE}
exit 1
fi
# 查找最新的增量备份
LATEST_INCR=$(find ${BACKUP_BASE} -name "incr_*" -type d | sort | tail -n1)
# 确定增量基准目录
if [ -z "${LATEST_INCR}" ]; then
# 如果没有增量备份,基于最新的全量备份
INCREMENTAL_BASEDIR=${LATEST_FULL}
echo "基于全量备份: ${LATEST_FULL}" >> ${LOG_FILE}
else
# 如果有增量备份,基于最新的增量备份
INCREMENTAL_BASEDIR=${LATEST_INCR}
echo "基于增量备份: ${LATEST_INCR}" >> ${LOG_FILE}
fi
# 创建增量备份目录
INCR_BACKUP_DIR="${BACKUP_BASE}/incr_${DATE}"
mkdir -p ${INCR_BACKUP_DIR}
# 记录开始时间
echo "==========================================" >> ${LOG_FILE}
echo "XtraBackup增量备份开始: $(date)" >> ${LOG_FILE}
echo "基准目录: ${INCREMENTAL_BASEDIR}" >> ${LOG_FILE}
echo "增量目录: ${INCR_BACKUP_DIR}" >> ${LOG_FILE}
# 执行增量备份
echo "执行增量备份..." >> ${LOG_FILE}
xtrabackup \
--backup \
--target-dir=${INCR_BACKUP_DIR} \
--incremental-basedir=${INCREMENTAL_BASEDIR} \
--user=${MYSQL_USER} \
--password=${MYSQL_PASSWORD} \
--parallel=${THREADS} \
--compress \
--compress-threads=${THREADS} \
--stream=xbstream \
--extra-lsndir=${INCR_BACKUP_DIR} \
2>> ${LOG_FILE} | gzip > ${INCR_BACKUP_DIR}/incremental.xbstream.gz
# 检查备份结果
if [ $? -eq 0 ]; then
echo "增量备份成功" >> ${LOG_FILE}
# 生成备份信息
echo "备份时间: ${DATE}" > ${INCR_BACKUP_DIR}/backup.info
echo "备份类型: 增量备份" >> ${INCR_BACKUP_DIR}/backup.info
echo "基准目录: ${INCREMENTAL_BASEDIR}" >> ${INCR_BACKUP_DIR}/backup.info
echo "LSN信息:" >> ${INCR_BACKUP_DIR}/backup.info
cat ${INCR_BACKUP_DIR}/xtrabackup_checkpoints >> ${INCR_BACKUP_DIR}/backup.info
else
echo "增量备份失败" >> ${LOG_FILE}
rm -rf ${INCR_BACKUP_DIR}
exit 1
fi
# 清理旧增量备份
echo "清理超过${RETENTION_DAYS}天的旧增量备份..." >> ${LOG_FILE}
find ${BACKUP_BASE}/incr_* -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} \; 2>> ${LOG_FILE}
echo "增量备份完成: $(date)" >> ${LOG_FILE}
echo "备份大小: $(du -sh ${INCR_BACKUP_DIR} | awk '{print $1}')" >> ${LOG_FILE}
echo "==========================================" >> ${LOG_FILE}
恢复脚本 (xtrabackup_restore.sh)
#!/bin/bash
# xtrabackup_restore.sh - XtraBackup恢复脚本
# 配置参数
BACKUP_BASE="/data/backup/xtrabackup"
MYSQL_DATA_DIR="/var/lib/mysql"
MYSQL_USER="root"
MYSQL_PASSWORD="your_password"
RESTORE_DATE="$1" # 从命令行参数获取恢复日期
# 检查参数
if [ -z "${RESTORE_DATE}" ]; then
echo "用法: $0 <备份日期>"
echo "示例: $0 20231201_120000"
exit 1
fi
# 查找全量备份
FULL_BACKUP_DIR="${BACKUP_BASE}/full_${RESTORE_DATE}"
if [ ! -d "${FULL_BACKUP_DIR}" ]; then
echo "未找到指定日期的全量备份: ${FULL_BACKUP_DIR}"
exit 1
fi
echo "开始恢复数据库..."
echo "全量备份目录: ${FULL_BACKUP_DIR}"
# 停止MySQL服务
systemctl stop mysql
# 备份当前数据目录
if [ -d "${MYSQL_DATA_DIR}" ]; then
mv ${MYSQL_DATA_DIR} ${MYSQL_DATA_DIR}_backup_$(date +%Y%m%d_%H%M%S)
fi
# 准备全量备份
echo "准备全量备份..."
xtrabackup --prepare --apply-log-only --target-dir=${FULL_BACKUP_DIR}
# 查找并应用增量备份
INCREMENTAL_BACKUPS=$(find ${BACKUP_BASE} -name "incr_*" -type d | grep -E "incr_.*${RESTORE_DATE:0:8}" | sort)
for INCR_DIR in ${INCREMENTAL_BACKUPS}; do
if [ $(basename ${INCR_DIR}) \> "full_${RESTORE_DATE}" ]; then
echo "应用增量备份: ${INCR_DIR}"
xtrabackup --prepare --apply-log-only --target-dir=${FULL_BACKUP_DIR} \
--incremental-dir=${INCR_DIR}
fi
done
# 最终准备
echo "最终准备..."
xtrabackup --prepare --target-dir=${FULL_BACKUP_DIR}
# 恢复数据
echo "恢复数据到 ${MYSQL_DATA_DIR}..."
xtrabackup --copy-back --target-dir=${FULL_BACKUP_DIR}
# 设置权限
chown -R mysql:mysql ${MYSQL_DATA_DIR}
# 启动MySQL服务
systemctl start mysql
echo "数据库恢复完成!"
四、自动化备份配置
4.1 Crontab 配置示例
# 编辑crontab
crontab -e
# 添加以下内容:
# 每天凌晨2点全量备份
0 2 * * 0 /path/to/mysqldump_full.sh
# 每天凌晨1点增量备份(周日除外)
0 1 * * 1-6 /path/to/mysqldump_incremental.sh
# 每周日凌晨3点XtraBackup全量备份
0 3 * * 0 /path/to/xtrabackup_full.sh
# 每天凌晨4点XtraBackup增量备份
0 4 * * 1-6 /path/to/xtrabackup_incremental.sh
4.2 备份策略建议
# 推荐备份策略:
# 1. 每周日:全量备份
# 2. 周一至周六:增量备份
# 3. 保留4周的全量备份
# 4. 保留2周的增量备份
# 5. 定期测试恢复
# 6. 备份到远程存储
五、注意事项
- 测试备份恢复:定期测试备份文件是否可恢复
- 监控备份任务:监控备份日志和磁盘空间
- 加密敏感数据:备份文件包含敏感数据,建议加密存储
- 远程备份:将备份传输到远程服务器
- 版本兼容性:确保备份和恢复的MySQL版本一致
- 性能影响:备份期间可能影响数据库性能,建议在低峰期进行
六、常用检查命令
# 检查备份文件
ls -lh /data/backup/mysql/
# 查看备份日志
tail -f /var/log/mysql_backup.log
# 检查MySQL状态
mysql -u root -p -e "SHOW MASTER STATUS;"
# 检查二进制日志
ls -lh /var/lib/mysql/mysql-bin.*
# 验证备份文件完整性
gzip -t backup.sql.gz
这些脚本提供了完整的备份解决方案,可以根据实际需求进行调整和优化。
基于gitid的备份
GTID模式下的MySQL备份脚本
1. 全量备份脚本 (mysql_full_backup.sh)
#!/bin/bash
# mysql_full_backup.sh - GTID模式下的全量备份脚本
# 使用方法: ./mysql_full_backup.sh [备份路径]
# 配置参数
MYSQL_USER="root"
MYSQL_PASS="Root@1234"
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
BACKUP_DIR="${1:-/data/backup/mysql}"
LOG_FILE="/var/log/mysql_backup.log"
DATE=$(date +%Y%m%d_%H%M%S)
FULL_BACKUP_DIR="${BACKUP_DIR}/full_${DATE}"
# 创建备份目录
mkdir -p "${FULL_BACKUP_DIR}"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
# 检查MySQL连接
check_mysql() {
if ! mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -e "SELECT 1" >/dev/null 2>&1; then
log "ERROR: 无法连接到MySQL服务器"
exit 1
fi
}
# 获取GTID信息
get_gtid_info() {
GTID_EXECUTED=$(mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -sN -e "SELECT @@GLOBAL.GTID_EXECUTED")
echo "${GTID_EXECUTED}" > "${FULL_BACKUP_DIR}/gtid_executed.txt"
log "GTID_EXECUTED: ${GTID_EXECUTED}"
}
# 执行全量备份
full_backup() {
log "开始全量备份..."
# 使用mysqldump进行全量备份(包含GTID信息)
mysqldump -u"${MYSQL_USER}" -p"${MYSQL_PASS}" \
-h"${MYSQL_HOST}" -P"${MYSQL_PORT}" \
--single-transaction \
--master-data=2 \
--routines \
--triggers \
--events \
--all-databases \
--set-gtid-purged=ON \
--flush-logs \
> "${FULL_BACKUP_DIR}/full_backup.sql" 2>>"${LOG_FILE}"
if [ $? -eq 0 ]; then
log "全量备份完成: ${FULL_BACKUP_DIR}/full_backup.sql"
# 压缩备份文件
gzip "${FULL_BACKUP_DIR}/full_backup.sql"
log "备份文件已压缩: ${FULL_BACKUP_DIR}/full_backup.sql.gz"
# 生成恢复脚本
create_restore_script
else
log "ERROR: 全量备份失败"
exit 1
fi
}
# 创建恢复脚本
create_restore_script() {
cat > "${FULL_BACKUP_DIR}/restore.sh" << 'EOF'
#!/bin/bash
# MySQL全量备份恢复脚本
# 使用方法: ./restore.sh [备份文件]
BACKUP_FILE="${1}"
MYSQL_USER="root"
MYSQL_PASS="Root@1234"
if [ -z "${BACKUP_FILE}" ]; then
echo "请指定备份文件: ./restore.sh /path/to/backup.sql.gz"
exit 1
fi
if [ ! -f "${BACKUP_FILE}" ]; then
echo "备份文件不存在: ${BACKUP_FILE}"
exit 1
fi
echo "开始恢复MySQL数据库..."
# 解压备份文件
gunzip -c "${BACKUP_FILE}" > restore_temp.sql
# 重置GTID并导入
mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}" -e "RESET MASTER;"
mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}" < restore_temp.sql
# 清理临时文件
rm -f restore_temp.sql
echo "数据库恢复完成!"
EOF
chmod +x "${FULL_BACKUP_DIR}/restore.sh"
log "恢复脚本已生成: ${FULL_BACKUP_DIR}/restore.sh"
}
# 清理旧备份(保留最近7天)
clean_old_backups() {
log "清理7天前的备份..."
find "${BACKUP_DIR}" -name "full_*" -type d -mtime +7 | xargs rm -rf
find "${BACKUP_DIR}" -name "incr_*" -type d -mtime +7 | xargs rm -rf
}
# 主函数
main() {
log "===== 开始MySQL全量备份 ====="
check_mysql
get_gtid_info
full_backup
clean_old_backups
log "===== 全量备份完成 ====="
}
main
2. 增量备份脚本 (mysql_incr_backup.sh)
#!/bin/bash
# mysql_incr_backup.sh - GTID模式下的增量备份脚本
# 使用方法: ./mysql_incr_backup.sh [全量备份路径] [增量备份路径]
# 配置参数
MYSQL_USER="root"
MYSQL_PASS="Root@1234"
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
BASE_BACKUP_DIR="${1:-/data/backup/mysql}"
INCR_BACKUP_DIR="${BASE_BACKUP_DIR}/incremental"
LOG_FILE="/var/log/mysql_backup.log"
DATE=$(date +%Y%m%d_%H%M%S)
INCR_BACKUP_SUBDIR="${INCR_BACKUP_DIR}/incr_${DATE}"
# 创建备份目录
mkdir -p "${INCR_BACKUP_SUBDIR}"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
# 检查上次备份的GTID位置
get_last_backup_gtid() {
# 查找最新的全量备份目录
LATEST_FULL_BACKUP=$(find "${BASE_BACKUP_DIR}" -name "full_*" -type d | sort -r | head -1)
if [ -z "${LATEST_FULL_BACKUP}" ]; then
log "ERROR: 未找到全量备份,请先执行全量备份"
exit 1
fi
# 获取全量备份时的GTID
GTID_FILE="${LATEST_FULL_BACKUP}/gtid_executed.txt"
if [ -f "${GTID_FILE}" ]; then
LAST_GTID=$(cat "${GTID_FILE}")
log "上次备份的GTID: ${LAST_GTID}"
echo "${LAST_GTID}"
else
log "ERROR: 在全量备份中未找到GTID信息"
exit 1
fi
}
# 获取当前GTID信息
get_current_gtid() {
GTID_EXECUTED=$(mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -sN -e "SELECT @@GLOBAL.GTID_EXECUTED")
log "当前GTID_EXECUTED: ${GTID_EXECUTED}"
echo "${GTID_EXECUTED}"
}
# 执行增量备份
incremental_backup() {
log "开始增量备份..."
# 获取binlog文件列表
BINLOG_INDEX=$(mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -sN -e "SHOW VARIABLES LIKE 'log_bin_basename'" | awk '{print $2}')
BINLOG_DIR=$(dirname "${BINLOG_INDEX}")
if [ -z "${BINLOG_INDEX}" ]; then
log "ERROR: 未启用binlog,无法进行增量备份"
exit 1
fi
# 刷新日志,生成新的binlog文件
mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -e "FLUSH BINARY LOGS;"
# 获取当前的binlog文件
CURRENT_BINLOG=$(mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -sN -e "SHOW MASTER STATUS" | awk '{print $1}')
# 复制从上个GTID之后的所有binlog文件
log "开始复制binlog文件..."
for binlog in $(ls "${BINLOG_DIR}"/*.0* 2>/dev/null | sort); do
if [[ "${binlog}" > "${BINLOG_DIR}/${CURRENT_BINLOG}" ]] || [[ "${binlog}" == "${BINLOG_DIR}/${CURRENT_BINLOG}" ]]; then
continue
fi
cp "${binlog}" "${INCR_BACKUP_SUBDIR}/"
log "已复制: $(basename ${binlog})"
done
# 使用mysqlbinlog导出指定GTID之后的SQL
LAST_GTID="$1"
CURRENT_GTID="$2"
if [ -n "${LAST_GTID}" ] && [ -n "${CURRENT_GTID}" ] && [ "${LAST_GTID}" != "${CURRENT_GTID}" ]; then
log "导出从GTID ${LAST_GTID} 到 ${CURRENT_GTID} 的增量SQL..."
# 导出增量SQL
mysqlbinlog --read-from-remote-server \
--host="${MYSQL_HOST}" \
--port="${MYSQL_PORT}" \
--user="${MYSQL_USER}" \
--password="${MYSQL_PASS}" \
--include-gtids="${LAST_GTID}-${CURRENT_GTID}" \
--result-file="${INCR_BACKUP_SUBDIR}/incremental.sql" \
--verbose
if [ $? -eq 0 ]; then
log "增量SQL导出完成: ${INCR_BACKUP_SUBDIR}/incremental.sql"
# 压缩文件
gzip "${INCR_BACKUP_SUBDIR}/incremental.sql"
else
log "WARNING: 增量SQL导出失败,继续使用binlog文件备份"
fi
fi
# 备份GTID信息
echo "${CURRENT_GTID}" > "${INCR_BACKUP_SUBDIR}/current_gtid.txt"
log "增量备份完成: ${INCR_BACKUP_SUBDIR}"
}
# 创建增量恢复脚本
create_incremental_restore_script() {
cat > "${INCR_BACKUP_SUBDIR}/restore_incremental.sh" << 'EOF'
#!/bin/bash
# MySQL增量备份恢复脚本
# 使用方法:
# 1. 先恢复全量备份: ./restore.sh /path/to/full_backup.sql.gz
# 2. 再恢复增量: ./restore_incremental.sh [增量备份目录]
INCR_BACKUP_DIR="$1"
MYSQL_USER="root"
MYSQL_PASS="Root@1234"
if [ -z "${INCR_BACKUP_DIR}" ] || [ ! -d "${INCR_BACKUP_DIR}" ]; then
echo "请指定增量备份目录"
exit 1
fi
echo "开始恢复增量备份..."
# 恢复binlog文件
if ls "${INCR_BACKUP_DIR}"/*.0* 1> /dev/null 2>&1; then
echo "恢复binlog文件..."
for binlog in "${INCR_BACKUP_DIR}"/*.0*; do
echo "恢复: $(basename ${binlog})"
mysqlbinlog "${binlog}" | mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}"
done
fi
# 恢复增量SQL文件
if [ -f "${INCR_BACKUP_DIR}/incremental.sql.gz" ]; then
echo "恢复增量SQL..."
gunzip -c "${INCR_BACKUP_DIR}/incremental.sql.gz" | mysql -u"${MYSQL_USER}" -p"${MYSQL_PASS}"
fi
echo "增量恢复完成!"
EOF
chmod +x "${INCR_BACKUP_SUBDIR}/restore_incremental.sh"
}
# 主函数
main() {
log "===== 开始MySQL增量备份 ====="
LAST_GTID=$(get_last_backup_gtid)
CURRENT_GTID=$(get_current_gtid)
if [ "${LAST_GTID}" = "${CURRENT_GTID}" ]; then
log "INFO: 自上次备份后没有新数据,跳过增量备份"
rm -rf "${INCR_BACKUP_SUBDIR}"
exit 0
fi
incremental_backup "${LAST_GTID}" "${CURRENT_GTID}"
create_incremental_restore_script
log "===== 增量备份完成 ====="
}
main
3. 自动化备份管理脚本 (mysql_backup_manager.sh)
#!/bin/bash
# mysql_backup_manager.sh - 备份管理脚本
# 使用方法:
# 1. 全量备份: ./mysql_backup_manager.sh full
# 2. 增量备份: ./mysql_backup_manager.sh incr
# 3. 自动模式: ./mysql_backup_manager.sh auto
# 配置参数
BACKUP_DIR="/data/backup/mysql"
LOG_FILE="/var/log/mysql_backup.log"
FULL_SCRIPT="/opt/scripts/mysql_full_backup.sh"
INCR_SCRIPT="/opt/scripts/mysql_incr_backup.sh"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
# 检查备份目录
check_backup_dir() {
if [ ! -d "${BACKUP_DIR}" ]; then
mkdir -p "${BACKUP_DIR}"
log "创建备份目录: ${BACKUP_DIR}"
fi
}
# 全量备份
do_full_backup() {
log "执行全量备份..."
if [ -x "${FULL_SCRIPT}" ]; then
"${FULL_SCRIPT}" "${BACKUP_DIR}"
else
log "ERROR: 全量备份脚本不存在: ${FULL_SCRIPT}"
exit 1
fi
}
# 增量备份
do_incremental_backup() {
log "执行增量备份..."
if [ -x "${INCR_SCRIPT}" ]; then
"${INCR_SCRIPT}" "${BACKUP_DIR}"
else
log "ERROR: 增量备份脚本不存在: ${INCR_SCRIPT}"
exit 1
fi
}
# 自动模式(每周日全量,其他天增量)
do_auto_backup() {
DAY_OF_WEEK=$(date +%u) # 1-7, 1=Monday, 7=Sunday
if [ "${DAY_OF_WEEK}" -eq 7 ]; then
log "周日,执行全量备份"
do_full_backup
else
log "周${DAY_OF_WEEK},执行增量备份"
do_incremental_backup
fi
}
# 备份状态检查
check_backup_status() {
log "=== 备份状态检查 ==="
# 检查最新全量备份
LATEST_FULL=$(find "${BACKUP_DIR}" -name "full_*" -type d | sort -r | head -1)
if [ -n "${LATEST_FULL}" ]; then
log "最新全量备份: $(basename ${LATEST_FULL})"
log "备份时间: $(stat -c %y ${LATEST_FULL})"
else
log "WARNING: 未找到全量备份"
fi
# 检查最新增量备份
LATEST_INCR=$(find "${BACKUP_DIR}" -name "incr_*" -type d | sort -r | head -1)
if [ -n "${LATEST_INCR}" ]; then
log "最新增量备份: $(basename ${LATEST_INCR})"
log "备份时间: $(stat -c %y ${LATEST_INCR})"
fi
# 检查磁盘空间
DISK_USAGE=$(df -h "${BACKUP_DIR}" | tail -1 | awk '{print $5}')
log "备份目录磁盘使用率: ${DISK_USAGE}"
}
# 主函数
main() {
ACTION="${1:-auto}"
case "${ACTION}" in
"full")
check_backup_dir
do_full_backup
;;
"incr")
check_backup_dir
do_incremental_backup
;;
"auto")
check_backup_dir
do_auto_backup
;;
"status")
check_backup_status
;;
*)
echo "用法: $0 {full|incr|auto|status}"
echo " full - 执行全量备份"
echo " incr - 执行增量备份"
echo " auto - 自动模式(默认)"
echo " status - 检查备份状态"
exit 1
;;
esac
}
main "$@"
4. 安装和配置脚本
#!/bin/bash
# setup_mysql_backup.sh - 安装配置备份脚本
# 创建目录
mkdir -p /opt/scripts
mkdir -p /data/backup/mysql
mkdir -p /var/log/mysql_backup
# 复制脚本
cp mysql_full_backup.sh /opt/scripts/
cp mysql_incr_backup.sh /opt/scripts/
cp mysql_backup_manager.sh /opt/scripts/
# 设置权限
chmod +x /opt/scripts/*.sh
chown -R root:root /opt/scripts/
chown -R mysql:mysql /data/backup/mysql/
# 创建日志文件
touch /var/log/mysql_backup.log
chown mysql:mysql /var/log/mysql_backup.log
# 配置cron定时任务
cat > /etc/cron.d/mysql-backup << 'EOF'
# MySQL自动备份计划
# 每天凌晨2点执行自动备份
0 2 * * * root /opt/scripts/mysql_backup_manager.sh auto >> /var/log/mysql_backup/cron.log 2>&1
# 每周日凌晨1点执行全量备份
0 1 * * 0 root /opt/scripts/mysql_backup_manager.sh full >> /var/log/mysql_backup/cron.log 2>&1
# 每天凌晨3点清理旧备份
0 3 * * * root find /data/backup/mysql -type d -name "full_*" -mtime +30 -exec rm -rf {} \;
0 3 * * * root find /data/backup/mysql -type d -name "incr_*" -mtime +7 -exec rm -rf {} \;
EOF
echo "安装完成!"
echo "手动执行测试:"
echo "1. 全量备份: /opt/scripts/mysql_backup_manager.sh full"
echo "2. 增量备份: /opt/scripts/mysql_backup_manager.sh incr"
echo "3. 查看状态: /opt/scripts/mysql_backup_manager.sh status"
5. 恢复指南
# 恢复流程:
# 1. 找到最新的全量备份
LATEST_FULL=$(find /data/backup/mysql -name "full_*" -type d | sort -r | head -1)
# 2. 恢复全量备份
cd "${LATEST_FULL}"
./restore.sh full_backup.sql.gz
# 3. 按顺序恢复增量备份
for incr_dir in $(find /data/backup/mysql -name "incr_*" -type d | sort); do
cd "${incr_dir}"
./restore_incremental.sh .
done
使用说明
首次使用:
chmod +x setup_mysql_backup.sh ./setup_mysql_backup.sh修改配置:编辑脚本中的数据库连接信息
手动备份测试:
# 全量备份 /opt/scripts/mysql_backup_manager.sh full # 增量备份 /opt/scripts/mysql_backup_manager.sh incr # 查看备份状态 /opt/scripts/mysql_backup_manager.sh status查看备份文件:
ls -la /data/backup/mysql/
注意事项
- GTID模式必须启用:确保MySQL配置中启用了GTID
- binlog必须开启:增量备份依赖binlog
- 定期清理:脚本会自动清理7天前的增量备份和30天前的全量备份
- 备份验证:定期测试恢复流程
- 监控磁盘空间:确保备份目录有足够空间
- 主从复制:在主库执行备份,从库可用于恢复测试
这些脚本已针对GTID模式优化,确保备份和恢复时GTID一致性。
不一样!XtraBackup在GTID和非GTID模式下的备份脚本有明显差异。
主要差异对比表
| 特性 | GTID模式 | 非GTID模式 |
|---|---|---|
| 备份命令参数 | 需要特殊GTID处理 | 常规参数即可 |
| 恢复流程 | 必须重置GTID | 无需GTID处理 |
| 主从复制设置 | 基于GTID设置 | 基于binlog位置 |
| 一致性要求 | GTID一致性 | 位置一致性 |
GTID模式下的XtraBackup脚本
1. GTID全量备份脚本 (xtrabackup_gtid_full.sh)
#!/bin/bash
# GTID模式全量备份脚本
# 配置
MYSQL_USER="backup"
MYSQL_PASS="Backup@123"
BACKUP_DIR="/data/backup/xtrabackup"
LOG_FILE="/var/log/xtrabackup.log"
DATE=$(date +%Y%m%d_%H%M%S)
FULL_DIR="${BACKUP_DIR}/full_gtid_${DATE}"
# 创建目录
mkdir -p "${FULL_DIR}"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
# 1. GTID模式专用备份
log "开始GTID模式全量备份..."
# 关键参数:--set-gtid-purged=ON
xtrabackup \
--backup \
--user="${MYSQL_USER}" \
--password="${MYSQL_PASS}" \
--target-dir="${FULL_DIR}" \
--datadir=/var/lib/mysql \
--set-gtid-purged=ON \
--extra-lsndir="${FULL_DIR}/lsn" \
--stream=xbstream \
--compress \
2>> "${LOG_FILE}" | gzip > "${FULL_DIR}/backup.xbstream.gz"
# 或者使用压缩格式
# xtrabackup \
# --backup \
# --user="${MYSQL_USER}" \
# --password="${MYSQL_PASS}" \
# --target-dir="${FULL_DIR}" \
# --set-gtid-purged=ON \
# --compress \
# --compress-threads=4
if [ $? -eq 0 ]; then
# 2. 准备备份
xtrabackup \
--prepare \
--target-dir="${FULL_DIR}" \
--apply-log-only
# 3. 保存GTID信息
cat > "${FULL_DIR}/gtid_info.txt" << EOF
# GTID备份信息
备份时间: $(date)
备份类型: GTID全量备份
GTID模式: ON
恢复前需执行: RESET MASTER;
EOF
# 获取当前GTID
GTID_EXECUTED=$(mysql -u${MYSQL_USER} -p${MYSQL_PASS} -sN -e "SELECT @@GLOBAL.GTID_EXECUTED")
echo "GTID_EXECUTED=${GTID_EXECUTED}" >> "${FULL_DIR}/gtid_info.txt"
# 4. 创建恢复脚本
cat > "${FULL_DIR}/restore_gtid.sh" << 'EOF'
#!/bin/bash
# GTID模式恢复脚本
BACKUP_DIR="$(cd "$(dirname "$0")" && pwd)"
MYSQL_USER="backup"
MYSQL_PASS="Backup@123"
DATA_DIR="/var/lib/mysql"
echo "正在停止MySQL服务..."
systemctl stop mysqld
echo "清空数据目录..."
rm -rf ${DATA_DIR}/*
echo "准备恢复备份..."
# 解压(如果备份是压缩的)
if [ -f "${BACKUP_DIR}/backup.xbstream.gz" ]; then
echo "解压备份文件..."
gzip -d -c "${BACKUP_DIR}/backup.xbstream.gz" | xbstream -x -C ${DATA_DIR}
fi
echo "应用日志..."
xtrabackup --prepare --target-dir=${DATA_DIR}
echo "修改文件权限..."
chown -R mysql:mysql ${DATA_DIR}
echo "重置GTID(重要!)..."
# 必须重置GTID,否则会冲突
cat > /tmp/reset_gtid.sql << SQL
RESET MASTER;
SET @@GLOBAL.GTID_PURGED='';
SQL
echo "启动MySQL服务..."
systemctl start mysqld
echo "等待MySQL启动..."
sleep 10
echo "恢复完成!"
echo "请检查GTID状态:SHOW GLOBAL VARIABLES LIKE 'gtid%';"
EOF
chmod +x "${FULL_DIR}/restore_gtid.sh"
log "GTID全量备份完成: ${FULL_DIR}"
else
log "备份失败!"
exit 1
fi
2. GTID增量备份脚本 (xtrabackup_gtid_incremental.sh)
#!/bin/bash
# GTID模式增量备份脚本
# 配置
MYSQL_USER="backup"
MYSQL_PASS="Backup@123"
BACKUP_DIR="/data/backup/xtrabackup"
LOG_FILE="/var/log/xtrabackup.log"
DATE=$(date +%Y%m%d_%H%M%S)
# 查找最新的全量备份
LATEST_FULL=$(find "${BACKUP_DIR}" -name "full_gtid_*" -type d | sort -r | head -1)
if [ -z "${LATEST_FULL}" ]; then
echo "未找到全量备份,请先执行全量备份"
exit 1
fi
# 增量备份目录
INCR_DIR="${BACKUP_DIR}/incr_gtid_${DATE}"
# 获取增量备份的LSN
BASE_LSN=$(cat "${LATEST_FULL}/xtrabackup_checkpoints" | grep "to_lsn" | awk '{print $3}')
log "开始GTID增量备份,基于LSN: ${BASE_LSN}"
# 执行增量备份
xtrabackup \
--backup \
--user="${MYSQL_USER}" \
--password="${MYSQL_PASS}" \
--target-dir="${INCR_DIR}" \
--incremental-basedir="${LATEST_FULL}" \
--set-gtid-purged=ON \
--extra-lsndir="${INCR_DIR}/lsn"
# 保存增量备份信息
cat > "${INCR_DIR}/incremental_info.txt" << EOF
增量备份信息
------------
备份时间: $(date)
基础备份: $(basename ${LATEST_FULL})
基础LSN: ${BASE_LSN}
当前GTID: $(mysql -u${MYSQL_USER} -p${MYSQL_PASS} -sN -e "SELECT @@GLOBAL.GTID_EXECUTED")
EOF
非GTID模式下的XtraBackup脚本
1. 非GTID全量备份脚本 (xtrabackup_normal_full.sh)
#!/bin/bash
# 非GTID模式全量备份脚本
# 配置
MYSQL_USER="backup"
MYSQL_PASS="Backup@123"
BACKUP_DIR="/data/backup/xtrabackup"
LOG_FILE="/var/log/xtrabackup.log"
DATE=$(date +%Y%m%d_%H%M%S)
FULL_DIR="${BACKUP_DIR}/full_normal_${DATE}"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
# 1. 非GTID备份(不需要--set-gtid-purged参数)
log "开始非GTID模式全量备份..."
xtrabackup \
--backup \
--user="${MYSQL_USER}" \
--password="${MYSQL_PASS}" \
--target-dir="${FULL_DIR}" \
--datadir=/var/lib/mysql \
--stream=xbstream \
2>> "${LOG_FILE}" | gzip > "${FULL_DIR}/backup.xbstream.gz"
if [ $? -eq 0 ]; then
# 2. 准备备份
xtrabackup \
--prepare \
--target-dir="${FULL_DIR}"
# 3. 保存binlog位置信息
echo "=== binlog位置信息 ===" > "${FULL_DIR}/binlog_info.txt"
cat "${FULL_DIR}/xtrabackup_binlog_info" >> "${FULL_DIR}/binlog_info.txt"
# 4. 创建非GTID恢复脚本
cat > "${FULL_DIR}/restore_normal.sh" << 'EOF'
#!/bin/bash
# 非GTID模式恢复脚本
BACKUP_DIR="$(cd "$(dirname "$0")" && pwd)"
MYSQL_USER="backup"
MYSQL_PASS="Backup@123"
DATA_DIR="/var/lib/mysql"
echo "正在停止MySQL服务..."
systemctl stop mysqld
echo "清空数据目录..."
rm -rf ${DATA_DIR}/*
echo "恢复备份..."
if [ -f "${BACKUP_DIR}/backup.xbstream.gz" ]; then
gzip -d -c "${BACKUP_DIR}/backup.xbstream.gz" | xbstream -x -C ${DATA_DIR}
fi
echo "应用日志..."
xtrabackup --prepare --target-dir=${DATA_DIR}
echo "修改文件权限..."
chown -R mysql:mysql ${DATA_DIR}
echo "启动MySQL服务..."
systemctl start mysqld
echo "恢复完成!"
echo "binlog位置信息:"
cat ${BACKUP_DIR}/binlog_info.txt
EOF
chmod +x "${FULL_DIR}/restore_normal.sh"
log "非GTID全量备份完成: ${FULL_DIR}"
else
log "备份失败!"
exit 1
fi
2. 非GTID增量备份脚本 (xtrabackup_normal_incremental.sh)
#!/bin/bash
# 非GTID模式增量备份脚本
# 配置
MYSQL_USER="backup"
MYSQL_PASS="Backup@123"
BACKUP_DIR="/data/backup/xtrabackup"
LOG_FILE="/var/log/xtrabackup.log"
DATE=$(date +%Y%m%d_%H%M%S)
# 查找最新的全量备份
LATEST_FULL=$(find "${BACKUP_DIR}" -name "full_normal_*" -type d | sort -r | head -1)
if [ -z "${LATEST_FULL}" ]; then
echo "未找到全量备份,请先执行全量备份"
exit 1
fi
# 增量备份目录
INCR_DIR="${BACKUP_DIR}/incr_normal_${DATE}"
log "开始非GTID增量备份..."
# 执行增量备份
xtrabackup \
--backup \
--user="${MYSQL_USER}" \
--password="${MYSQL_PASS}" \
--target-dir="${INCR_DIR}" \
--incremental-basedir="${LATEST_FULL}"
# 保存增量备份信息
echo "=== 增量备份信息 ===" > "${INCR_DIR}/incremental_info.txt"
echo "基础备份: $(basename ${LATEST_FULL})" >> "${INCR_DIR}/incremental_info.txt"
echo "binlog位置: $(cat ${LATEST_FULL}/xtrabackup_binlog_info)" >> "${INCR_DIR}/incremental_info.txt"
关键差异详解
1. 备份时的关键参数差异
# GTID模式必须添加
--set-gtid-purged=ON
# 或
--set-gtid-purged=OFF
# 或
--set-gtid-purged=AUTO
# 非GTID模式不需要此参数
2. 恢复时的关键差异
GTID恢复脚本必须包含:
# 重置GTID
mysql -e "RESET MASTER;"
# 或者导入备份的GTID
mysql -e "SET GLOBAL gtid_purged='备份的GTID值';"
非GTID恢复只需要常规步骤:
# 直接恢复数据文件即可
xtrabackup --copy-back --target-dir=/backup
3. 主从复制设置差异
GTID模式设置从库:
-- 不需要指定binlog位置
CHANGE MASTER TO
MASTER_HOST='master_host',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_AUTO_POSITION=1; -- 关键参数!
非GTID模式设置从库:
-- 需要指定binlog文件和位置
CHANGE MASTER TO
MASTER_HOST='master_host',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=123456;
统一备份脚本(自动检测模式)
#!/bin/bash
# xtrabackup_unified.sh - 自动检测GTID模式的统一备份脚本
# 检测MySQL GTID模式
check_gtid_mode() {
GTID_MODE=$(mysql -u${MYSQL_USER} -p${MYSQL_PASS} -sN -e "SELECT @@GLOBAL.GTID_MODE")
if [ "${GTID_MODE}" = "ON" ]; then
echo "gtid"
else
echo "normal"
fi
}
# 主备份函数
backup_mysql() {
MODE=$(check_gtid_mode)
DATE=$(date +%Y%m%d_%H%M%S)
if [ "${MODE}" = "gtid" ]; then
log "检测到GTID模式,执行GTID备份"
BACKUP_DIR="${BASE_DIR}/full_gtid_${DATE}"
XTRA_OPTIONS="--set-gtid-purged=ON"
else
log "检测到非GTID模式,执行常规备份"
BACKUP_DIR="${BASE_DIR}/full_normal_${DATE}"
XTRA_OPTIONS=""
fi
# 执行备份
xtrabackup \
--backup \
--user="${MYSQL_USER}" \
--password="${MYSQL_PASS}" \
--target-dir="${BACKUP_DIR}" \
${XTRA_OPTIONS}
# 保存模式信息
echo "BACKUP_MODE=${MODE}" > "${BACKUP_DIR}/backup_mode.txt"
echo "GTID_EXECUTED=$(mysql -u${MYSQL_USER} -p${MYSQL_PASS} -sN -e "SELECT @@GLOBAL.GTID_EXECUTED")" >> "${BACKUP_DIR}/gtid_info.txt"
}
# 主恢复函数
restore_mysql() {
BACKUP_PATH="$1"
MODE=$(cat "${BACKUP_PATH}/backup_mode.txt" | grep "BACKUP_MODE" | cut -d'=' -f2)
if [ "${MODE}" = "gtid" ]; then
log "GTID模式恢复,需要重置GTID"
systemctl stop mysqld
rm -rf /var/lib/mysql/*
xtrabackup --copy-back --target-dir=${BACKUP_PATH}
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld
# GTID特殊处理
mysql -e "RESET MASTER;"
else
log "非GTID模式恢复"
systemctl stop mysqld
rm -rf /var/lib/mysql/*
xtrabackup --copy-back --target-dir=${BACKUP_PATH}
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld
fi
}
建议
- 生产环境:为GTID和非GTID模式分别准备不同的备份脚本
- 备份策略:无论哪种模式,都应该:
- 定期执行全量备份
- 定期测试恢复流程
- 监控备份完整性
- 文档记录:明确记录数据库运行模式
- 备份验证:恢复时特别注意GTID处理
核心原则:GTID模式下必须处理GTID一致性,非GTID模式下不需要关心GTID。
作者:严锋 创建时间:2025-12-25 10:39
最后编辑:严锋 更新时间:2025-12-25 10:40
最后编辑:严锋 更新时间:2025-12-25 10:40