外观
TDSQL 备份脚本
全量备份脚本
基本全量备份脚本
脚本功能
- 执行TDSQL全量备份
- 备份文件命名规范
- 备份日志记录
- 基本错误处理
脚本示例
bash
#!/bin/bash
# 配置参数
DB_HOST="tdsql-instance.example.com"
DB_PORT="3306"
DB_USER="backup_user"
DB_PASSWORD="backup_password"
BACKUP_DIR="/backup/tdsql/full"
LOG_FILE="/var/log/tdsql_backup.log"
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_FILE="${BACKUP_DIR}/tdsql_full_backup_${DATE}.sql.gz"
# 创建备份目录
mkdir -p ${BACKUP_DIR}
# 记录备份开始时间
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL全量备份开始" >> ${LOG_FILE}
# 执行全量备份
mysqldump -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -p${DB_PASSWORD} \
--single-transaction \
--master-data=2 \
--flush-logs \
--all-databases \
| gzip > ${BACKUP_FILE}
# 检查备份结果
if [ $? -eq 0 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL全量备份成功: ${BACKUP_FILE}" >> ${LOG_FILE}
# 获取备份文件大小
BACKUP_SIZE=$(du -h ${BACKUP_FILE} | awk '{print $1}')
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件大小: ${BACKUP_SIZE}" >> ${LOG_FILE}
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL全量备份失败" >> ${LOG_FILE}
# 发送告警通知(示例:邮件通知)
echo "TDSQL全量备份失败,请检查" | mail -s "TDSQL备份告警" admin@example.com
exit 1
fi
# 记录备份结束时间
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL全量备份结束" >> ${LOG_FILE}
echo "-----------------------------------------------------------------" >> ${LOG_FILE}
exit 0高级全量备份脚本
脚本功能
- 支持多实例备份
- 备份压缩和加密
- 备份验证
- 备份文件管理(清理过期备份)
- 详细的日志记录
- 备份状态监控
脚本示例
bash
#!/bin/bash
# 配置文件加载
if [ -f "/etc/tdsql_backup.conf" ]; then
source /etc/tdsql_backup.conf
else
echo "配置文件 /etc/tdsql_backup.conf 不存在" >&2
exit 1
fi
# 实例配置(可在配置文件中定义)
INSTANCES=("instance1" "instance2" "instance3")
INSTANCE1_HOST="tdsql-instance1.example.com"
INSTANCE1_PORT="3306"
INSTANCE2_HOST="tdsql-instance2.example.com"
INSTANCE2_PORT="3306"
INSTANCE3_HOST="tdsql-instance3.example.com"
INSTANCE3_PORT="3306"
# 全局配置
BACKUP_BASE_DIR="/backup/tdsql"
LOG_DIR="/var/log/tdsql_backup"
DB_USER="backup_user"
DB_PASSWORD="backup_password"
RETENTION_DAYS=7
DATE=$(date +"%Y%m%d_%H%M%S")
# 创建目录
mkdir -p ${BACKUP_BASE_DIR}
mkdir -p ${LOG_DIR}
# 日志文件
LOG_FILE="${LOG_DIR}/tdsql_full_backup_${DATE}.log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL全量备份任务开始" > ${LOG_FILE}
# 遍历所有实例进行备份
for INSTANCE in "${INSTANCES[@]}"; do
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始备份实例: ${INSTANCE}" >> ${LOG_FILE}
# 获取实例配置
INSTANCE_HOST=$(eval echo \$${INSTANCE^^}_HOST)
INSTANCE_PORT=$(eval echo \$${INSTANCE^^}_PORT)
# 实例备份目录
INSTANCE_BACKUP_DIR="${BACKUP_BASE_DIR}/${INSTANCE}/full"
mkdir -p ${INSTANCE_BACKUP_DIR}
# 备份文件名
BACKUP_FILE="${INSTANCE_BACKUP_DIR}/${INSTANCE}_full_backup_${DATE}.sql.gz"
# 执行全量备份
mysqldump -h ${INSTANCE_HOST} -P ${INSTANCE_PORT} -u ${DB_USER} -p${DB_PASSWORD} \
--single-transaction \
--master-data=2 \
--flush-logs \
--all-databases \
| gzip > ${BACKUP_FILE}
if [ $? -eq 0 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 实例 ${INSTANCE} 备份成功: ${BACKUP_FILE}" >> ${LOG_FILE}
# 备份文件大小
BACKUP_SIZE=$(du -h ${BACKUP_FILE} | awk '{print $1}')
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件大小: ${BACKUP_SIZE}" >> ${LOG_FILE}
# 验证备份文件
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 验证备份文件: ${BACKUP_FILE}" >> ${LOG_FILE}
gunzip -t ${BACKUP_FILE}
if [ $? -eq 0 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件验证成功" >> ${LOG_FILE}
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件验证失败" >> ${LOG_FILE}
# 发送告警
echo "TDSQL实例 ${INSTANCE} 备份文件验证失败" | mail -s "TDSQL备份告警" admin@example.com
fi
# 清理过期备份
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 清理 ${INSTANCE} ${RETENTION_DAYS} 天前的过期备份" >> ${LOG_FILE}
find ${INSTANCE_BACKUP_DIR} -name "${INSTANCE}_full_backup_*.sql.gz" -mtime +${RETENTION_DAYS} -delete
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 实例 ${INSTANCE} 备份失败" >> ${LOG_FILE}
# 发送告警
echo "TDSQL实例 ${INSTANCE} 备份失败" | mail -s "TDSQL备份告警" admin@example.com
fi
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 实例 ${INSTANCE} 备份完成" >> ${LOG_FILE}
done
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL全量备份任务结束" >> ${LOG_FILE}
exit 0增量备份脚本
基于二进制日志的增量备份
脚本功能
- 利用TDSQL二进制日志进行增量备份
- 支持断点续传
- 备份日志记录
- 错误处理
脚本示例
bash
#!/bin/bash
# 配置参数
DB_HOST="tdsql-instance.example.com"
DB_PORT="3306"
DB_USER="backup_user"
DB_PASSWORD="backup_password"
BACKUP_DIR="/backup/tdsql/incremental"
LOG_FILE="/var/log/tdsql_incremental_backup.log"
DATE=$(date +"%Y%m%d_%H%M%S")
BINLOG_DIR="/var/lib/mysql"
LAST_BINLOG_FILE="$(mysql -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -p${DB_PASSWORD} -e "SHOW MASTER STATUS\G" | grep "File:" | awk '{print $2}')"
LAST_BINLOG_POS="$(mysql -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -p${DB_PASSWORD} -e "SHOW MASTER STATUS\G" | grep "Position:" | awk '{print $2}')"
# 创建备份目录
mkdir -p ${BACKUP_DIR}
# 记录备份开始时间
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL增量备份开始" >> ${LOG_FILE}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 当前二进制日志: ${LAST_BINLOG_FILE}, 位置: ${LAST_BINLOG_POS}" >> ${LOG_FILE}
# 读取上一次备份的二进制日志位置
if [ -f "${BACKUP_DIR}/last_binlog_position.txt" ]; then
source ${BACKUP_DIR}/last_binlog_position.txt
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 上次备份二进制日志: ${PREV_BINLOG_FILE}, 位置: ${PREV_BINLOG_POS}" >> ${LOG_FILE}
else
# 第一次增量备份,从当前位置开始
PREV_BINLOG_FILE=${LAST_BINLOG_FILE}
PREV_BINLOG_POS=${LAST_BINLOG_POS}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 首次增量备份,从当前位置开始" >> ${LOG_FILE}
fi
# 执行增量备份(复制二进制日志文件)
if [ "${PREV_BINLOG_FILE}" = "${LAST_BINLOG_FILE}" ]; then
# 同一二进制日志文件,备份从上次位置到当前位置的内容
BACKUP_FILE="${BACKUP_DIR}/tdsql_incremental_backup_${DATE}.binlog"
mysqlbinlog -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -p${DB_PASSWORD} \
--start-position=${PREV_BINLOG_POS} \
--stop-position=${LAST_BINLOG_POS} \
${PREV_BINLOG_FILE} > ${BACKUP_FILE}
else
# 跨二进制日志文件,备份多个文件
BACKUP_FILE="${BACKUP_DIR}/tdsql_incremental_backup_${DATE}.binlog"
# 备份第一个文件从上次位置到文件末尾
mysqlbinlog -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -p${DB_PASSWORD} \
--start-position=${PREV_BINLOG_POS} \
${PREV_BINLOG_FILE} > ${BACKUP_FILE}
# 获取中间的二进制日志文件列表
BINLOG_LIST=$(mysql -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -p${DB_PASSWORD} -e "SHOW BINARY LOGS" | grep -v "Log_name" | awk '{print $1}')
# 备份中间的二进制日志文件
for BINLOG in ${BINLOG_LIST}; do
if [[ "${BINLOG}" > "${PREV_BINLOG_FILE}" && "${BINLOG}" < "${LAST_BINLOG_FILE}" ]]; then
mysqlbinlog -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -p${DB_PASSWORD} ${BINLOG} >> ${BACKUP_FILE}
fi
done
# 备份最后一个文件从开头到当前位置
mysqlbinlog -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -p${DB_PASSWORD} \
--stop-position=${LAST_BINLOG_POS} \
${LAST_BINLOG_FILE} >> ${BACKUP_FILE}
fi
# 检查备份结果
if [ $? -eq 0 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL增量备份成功: ${BACKUP_FILE}" >> ${LOG_FILE}
# 保存当前二进制日志位置
echo "PREV_BINLOG_FILE=${LAST_BINLOG_FILE}" > ${BACKUP_DIR}/last_binlog_position.txt
echo "PREV_BINLOG_POS=${LAST_BINLOG_POS}" >> ${BACKUP_DIR}/last_binlog_position.txt
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL增量备份失败" >> ${LOG_FILE}
# 发送告警
echo "TDSQL增量备份失败,请检查" | mail -s "TDSQL备份告警" admin@example.com
exit 1
fi
# 记录备份结束时间
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL增量备份结束" >> ${LOG_FILE}
echo "-----------------------------------------------------------------" >> ${LOG_FILE}
exit 0备份验证脚本
备份文件完整性验证
脚本功能
- 验证备份文件的完整性
- 检查备份文件大小
- 验证备份文件格式
- 生成验证报告
脚本示例
bash
#!/bin/bash
# 配置参数
BACKUP_DIR="/backup/tdsql"
LOG_FILE="/var/log/tdsql_backup_verify.log"
DATE=$(date +"%Y%m%d_%H%M%S")
VERIFY_REPORT="/var/report/tdsql_backup_verify_${DATE}.txt"
# 创建报告目录
mkdir -p $(dirname ${VERIFY_REPORT})
# 记录验证开始时间
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL备份验证开始" > ${LOG_FILE}
echo "TDSQL备份验证报告 - ${DATE}" > ${VERIFY_REPORT}
echo "="*50 >> ${VERIFY_REPORT}
# 遍历所有备份文件
find ${BACKUP_DIR} -name "*.sql.gz" -o -name "*.binlog" | while read BACKUP_FILE; do
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 验证备份文件: ${BACKUP_FILE}" >> ${LOG_FILE}
# 检查文件是否存在且大小大于0
if [ -s ${BACKUP_FILE} ]; then
FILE_SIZE=$(du -h ${BACKUP_FILE} | awk '{print $1}')
FILE_DATE=$(stat -c %y ${BACKUP_FILE} | cut -d' ' -f1)
# 根据文件类型进行验证
if [[ ${BACKUP_FILE} == *.sql.gz ]]; then
# 验证gzip文件完整性
gzip -t ${BACKUP_FILE}
if [ $? -eq 0 ]; then
echo "✓ ${BACKUP_FILE} - 完整 - 大小: ${FILE_SIZE} - 创建日期: ${FILE_DATE}" >> ${VERIFY_REPORT}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件验证成功: ${BACKUP_FILE}" >> ${LOG_FILE}
else
echo "✗ ${BACKUP_FILE} - 损坏 - 大小: ${FILE_SIZE} - 创建日期: ${FILE_DATE}" >> ${VERIFY_REPORT}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件验证失败: ${BACKUP_FILE}" >> ${LOG_FILE}
fi
elif [[ ${BACKUP_FILE} == *.binlog ]]; then
# 验证二进制日志文件
# 简单检查文件是否可读取
if [ -r ${BACKUP_FILE} ]; then
echo "✓ ${BACKUP_FILE} - 完整 - 大小: ${FILE_SIZE} - 创建日期: ${FILE_DATE}" >> ${VERIFY_REPORT}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件验证成功: ${BACKUP_FILE}" >> ${LOG_FILE}
else
echo "✗ ${BACKUP_FILE} - 不可读 - 大小: ${FILE_SIZE} - 创建日期: ${FILE_DATE}" >> ${VERIFY_REPORT}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件验证失败: ${BACKUP_FILE}" >> ${LOG_FILE}
fi
fi
else
echo "✗ ${BACKUP_FILE} - 文件不存在或为空" >> ${VERIFY_REPORT}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件不存在或为空: ${BACKUP_FILE}" >> ${LOG_FILE}
fi
done
# 统计验证结果
TOTAL_FILES=$(grep -c "-" ${VERIFY_REPORT} | tail -n1)
SUCCESS_FILES=$(grep -c "✓" ${VERIFY_REPORT})
FAILED_FILES=$(grep -c "✗" ${VERIFY_REPORT})
echo "="*50 >> ${VERIFY_REPORT}
echo "验证统计:" >> ${VERIFY_REPORT}
echo "总备份文件数: ${TOTAL_FILES}" >> ${VERIFY_REPORT}
echo "验证成功: ${SUCCESS_FILES}" >> ${VERIFY_REPORT}
echo "验证失败: ${FAILED_FILES}" >> ${VERIFY_REPORT}
# 记录验证结束时间
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL备份验证结束" >> ${LOG_FILE}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 验证报告: ${VERIFY_REPORT}" >> ${LOG_FILE}
# 发送验证报告
if [ ${FAILED_FILES} -gt 0 ]; then
cat ${VERIFY_REPORT} | mail -s "TDSQL备份验证报告(有失败项)" admin@example.com
else
cat ${VERIFY_REPORT} | mail -s "TDSQL备份验证报告(全部成功)" admin@example.com
fi
exit 0备份管理脚本
备份清理脚本
脚本功能
- 清理过期备份文件
- 支持基于时间的清理策略
- 支持基于数量的清理策略
- 日志记录
脚本示例
bash
#!/bin/bash
# 配置参数
BACKUP_DIR="/backup/tdsql"
LOG_FILE="/var/log/tdsql_backup_cleanup.log"
RETENTION_DAYS=7
MAX_BACKUPS=10
# 记录清理开始时间
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL备份清理开始" >> ${LOG_FILE}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 清理策略: 保留最近${RETENTION_DAYS}天或最多${MAX_BACKUPS}个备份" >> ${LOG_FILE}
# 遍历所有实例的备份目录
find ${BACKUP_DIR} -type d -name "full" -o -name "incremental" -o -name "differential" | while read BACKUP_TYPE_DIR; do
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 清理备份目录: ${BACKUP_TYPE_DIR}" >> ${LOG_FILE}
# 基于时间清理:删除超过RETENTION_DAYS天的备份
OLD_BACKUPS=$(find ${BACKUP_TYPE_DIR} -name "*.sql.gz" -o -name "*.binlog" -mtime +${RETENTION_DAYS})
if [ -n "${OLD_BACKUPS}" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 删除过期备份文件:" >> ${LOG_FILE}
echo "${OLD_BACKUPS}" >> ${LOG_FILE}
find ${BACKUP_TYPE_DIR} -name "*.sql.gz" -o -name "*.binlog" -mtime +${RETENTION_DAYS} -delete
fi
# 基于数量清理:保留最多MAX_BACKUPS个备份
BACKUP_COUNT=$(ls -1 ${BACKUP_TYPE_DIR}/*.sql.gz ${BACKUP_TYPE_DIR}/*.binlog 2>/dev/null | wc -l)
if [ ${BACKUP_COUNT} -gt ${MAX_BACKUPS} ]; then
EXCESS_COUNT=$((BACKUP_COUNT - MAX_BACKUPS))
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份数量超过限制(${BACKUP_COUNT}/${MAX_BACKUPS}),删除${EXCESS_COUNT}个最旧的备份" >> ${LOG_FILE}
# 删除最旧的备份
ls -1t ${BACKUP_TYPE_DIR}/*.sql.gz ${BACKUP_TYPE_DIR}/*.binlog 2>/dev/null | tail -n ${EXCESS_COUNT} | while read OLD_BACKUP; do
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 删除备份文件: ${OLD_BACKUP}" >> ${LOG_FILE}
rm -f ${OLD_BACKUP}
done
fi
done
# 清理空目录
find ${BACKUP_DIR} -type d -empty -delete
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDSQL备份清理结束" >> ${LOG_FILE}
echo "-----------------------------------------------------------------" >> ${LOG_FILE}
exit 0备份脚本的最佳实践
脚本安全性
密码安全
- 避免在脚本中硬编码密码
- 使用配置文件存储密码,并设置权限为600
- 考虑使用MySQL配置文件(~/.my.cnf)存储认证信息
- 定期更换备份用户密码
文件权限
- 设置脚本权限为700,只允许所有者执行
- 设置备份文件权限为600,只允许所有者读写
- 设置配置文件权限为600,保护敏感信息
访问控制
- 限制备份脚本的执行权限
- 限制备份目录的访问权限
- 考虑使用专用的备份用户,只授予备份所需的最小权限
脚本可靠性
错误处理
- 添加充分的错误检查和处理
- 记录详细的日志信息
- 实现告警机制,在备份失败时及时通知
日志管理
- 记录备份开始、结束时间
- 记录备份文件路径、大小
- 记录备份结果和错误信息
- 定期清理旧日志文件
备份验证
- 定期验证备份文件的完整性
- 测试备份恢复,确保备份可用于恢复
- 生成备份验证报告
脚本性能
备份性能优化
- 选择合适的备份时间,避开业务高峰期
- 考虑使用并行备份,提高备份效率
- 优化备份参数,如调整缓冲区大小
存储优化
- 压缩备份文件,减少存储空间占用
- 采用增量或差异备份,减少备份时间和存储空间
- 考虑使用高性能存储设备,提高备份和恢复速度
脚本维护
版本控制
- 使用版本控制系统管理备份脚本
- 记录脚本的变更历史
- 便于回滚和追踪问题
定期更新
- 定期检查和更新备份脚本
- 适应TDSQL版本变化
- 优化脚本性能和可靠性
文档化
- 编写脚本文档,说明脚本功能、使用方法和配置参数
- 记录脚本的依赖关系
- 说明备份策略和恢复流程
备份脚本的调度
使用crontab调度
全量备份调度(每天凌晨2点)
bash
0 2 * * * /path/to/tdsql_full_backup.sh增量备份调度(每4小时)
bash
0 */4 * * * /path/to/tdsql_incremental_backup.sh备份验证调度(每天凌晨1点)
bash
0 1 * * * /path/to/tdsql_backup_verify.sh备份清理调度(每天凌晨3点)
bash
0 3 * * * /path/to/tdsql_backup_cleanup.sh调度注意事项
- 避免调度冲突,确保备份脚本按顺序执行
- 考虑脚本执行时间,避免影响业务运行
- 监控调度任务的执行状态
- 配置调度任务的日志输出
常见问题(FAQ)
Q1: 如何确保备份脚本的安全性?
A1: 确保备份脚本安全性的措施包括:
- 避免硬编码密码,使用配置文件存储敏感信息
- 设置合适的文件权限(脚本700,配置文件600)
- 使用专用的备份用户,授予最小权限
- 定期更换备份用户密码
- 限制备份脚本的执行权限
Q2: 如何选择合适的备份策略?
A2: 选择备份策略应考虑:
- 业务需求:RTO(恢复时间目标)和RPO(恢复点目标)
- 数据量大小:数据量越大,全量备份时间越长
- 业务高峰期:避免在业务高峰期执行备份
- 存储空间:增量和差异备份占用存储空间较小
- 恢复复杂度:全量备份恢复简单,增量备份恢复复杂
Q3: 如何验证备份的可恢复性?
A3: 验证备份可恢复性的方法包括:
- 定期执行恢复测试,将备份恢复到测试环境
- 验证恢复后的数据完整性和一致性
- 检查业务功能是否正常
- 记录恢复时间,评估RTO是否符合要求
Q4: 如何优化备份性能?
A4: 优化备份性能的方法包括:
- 选择合适的备份时间,避开业务高峰期
- 使用压缩技术,减少备份数据量
- 采用增量或差异备份,减少备份时间
- 优化备份参数,如调整缓冲区大小
- 使用高性能存储设备
- 考虑使用并行备份
Q5: 如何管理大量备份文件?
A5: 管理大量备份文件的方法包括:
- 制定合理的备份保留策略
- 定期清理过期备份文件
- 使用分层存储,将旧备份迁移到低成本存储
- 建立备份文件索引,便于查找和管理
- 监控备份存储空间使用情况
Q6: 备份脚本执行失败怎么办?
A6: 备份脚本执行失败的处理方法包括:
- 查看脚本日志,定位失败原因
- 检查数据库连接是否正常
- 检查备份目录权限和存储空间
- 检查备份用户权限
- 修复脚本中的错误
- 手动执行备份,验证备份命令是否正常
- 考虑调整备份策略或参数
