# 准备工作: MySQL 必须开启 binlog
#!/bin/bash
# MySQL 周一全量、周二至周日差异备份脚本
# 差异逻辑:每次备份本周一全量之后全部binlog,恢复只需要全量+当天一份差异包
########################### 【配置区,请自行修改】###########################
# MySQL 连接信息
DB_HOST="127.0.0.1"
DB_PORT="3306"
DB_USER="root"
DB_PASS="root123456"
# --all-databases 全部库;指定单库填数据库名
DB_TARGET="--all-databases"
# 备份根目录
BACKUP_ROOT="/data/mysql_backup"
# MySQL binlog 存放路径(my.cnf log_bin 对应目录)
BINLOG_PATH="/var/lib/mysql"
# 备份保留天数
RETENTION=30
# 告警邮箱,不需要填空
MAIL_ADMIN=""
#############################################################################
# 自动创建目录
FULL_DIR="${BACKUP_ROOT}/full"
DIFF_DIR="${BACKUP_ROOT}/diff"
LOG_FILE="${BACKUP_ROOT}/backup_log.log"
mkdir -p "${FULL_DIR}" "${DIFF_DIR}"
# 日期、星期变量
TODAY=$(date +%Y%m%d)
WEEK_NUM=$(date +%w) # 0周日 1周一 2周二 ...6周六
# 日志输出函数
log() {
echo "[$(date +%Y-%m-%d\ %H:%M:%S)] $1" | tee -a "${LOG_FILE}"
}
# 异常退出+邮件告警
err_exit() {
log "ERROR: $1"
if [ -n "${MAIL_ADMIN}" ]; then
echo "MySQL备份失败:$1" | mail -s "【MySQL备份告警】${TODAY}" "${MAIL_ADMIN}"
fi
exit 1
}
# 清理过期备份
clean_old_backup() {
log "开始清理${RETENTION}天前过期备份"
find "${FULL_DIR}" -name "mysql_full_*.sql.gz" -mtime +${RETENTION} -delete
find "${DIFF_DIR}" -name "mysql_diff_*.binlog.tar.gz" -mtime +${RETENTION} -delete
}
# 周一全量备份函数
full_backup() {
log "========== 执行周一全量备份 ${TODAY} =========="
FULL_FILE="${FULL_DIR}/mysql_full_${TODAY}.sql.gz"
# InnoDB专用一致性备份,刷新binlog并记录位点
mysqldump -h"${DB_HOST}" -P"${DB_PORT}" -u"${DB_USER}" -p"${DB_PASS}" \
--single-transaction --flush-logs --master-data=2 --quick ${DB_TARGET} \
| gzip > "${FULL_FILE}"
[ $? -ne 0 ] && err_exit "全量mysqldump导出失败"
log "全量备份文件:${FULL_FILE}"
# 提取本次全量对应的起始binlog文件名,保存给本周差异使用
grep "^CHANGE MASTER TO" "${FULL_FILE}" | awk -F\' '{print $2}' > "${FULL_DIR}/this_week_start_binlog.txt"
log "记录本周差异起始binlog位点完成"
}
# 周二至周日 差异备份函数
diff_backup() {
log "========== 执行差异备份 ${TODAY} =========="
START_BINLOG_FILE="${FULL_DIR}/this_week_start_binlog.txt"
# 判断本周是否存在周一全量位点文件
[ ! -f "${START_BINLOG_FILE}" ] && err_exit "缺少本周一全量备份位点文件,请先手动执行一次周一全量备份"
START_BIN=$(cat "${START_BINLOG_FILE}")
DIFF_PACK="${DIFF_DIR}/mysql_diff_${TODAY}.binlog.tar.gz"
# 找出从周一起始binlog到当前所有binlog文件打包(差异:本周一至今所有变更)
cd "${BINLOG_PATH}" || err_exit "无法进入binlog目录${BINLOG_PATH}"
bin_list=$(ls ${START_BIN}* 2>/dev/null)
[ -z "${bin_list}" ] && err_exit "未找到从${START_BIN}开始的binlog文件"
tar -zcf "${DIFF_PACK}" ${bin_list}
[ $? -ne 0 ] && err_exit "差异binlog打包失败"
log "差异备份包:${DIFF_PACK}"
}
########################### 主执行流程 ###########################
log "===== 备份任务启动,星期${WEEK_NUM} ====="
clean_old_backup
# 判断星期:1=周一全量,其余差异
if [ "${WEEK_NUM}" -eq 1 ]; then
full_backup
else
diff_backup
fi
log "===== ${TODAY} 备份任务执行完成 ===="
echo -e "\n" >> "${LOG_FILE}"
exit 0
crontab -e
# 添加一行
# 每日凌晨 2 点执行
0 2 * * * /data/script/mysql_backup_diff.sh