备份时间需根据实际流量曲线动态确定,避开业务高峰期;mysqldump必须使用--single-transaction、--routines、--events、--triggers、--set-gtid-purged=off等参数;脚本须校验服务状态、退出码、压缩包完整性并记录日志;crontab需注意时区与系统负载。

备份时间必须避开业务高峰期
凌晨2点到5点是大多数业务的低谷期,但不能直接写死。你得先确认自己系统的实际流量曲线——比如用 top、mysqladmin processlist 或应用监控看过去24小时的QPS峰值分布。如果你们是跨境电商,可能凌晨4点反而有海外批量下单;如果是国内SaaS系统,0点到1点就可能有大量定时任务堆积。
实操建议:
- 用
crontab -e设置任务时,别只写0 2 * * *,至少加个轻量校验:比如在脚本开头加pgrep -f "mysqld" > /dev/null || exit 1,防止MySQL没起来就开跑 - 在
mysqldump命令里强制加--single-transaction(InnoDB必备),否则备份期间遇到长事务或DDL操作,会卡住甚至失败 - 避免在备份窗口内执行
ALTER TABLE、DROP DATABASE等DDL,这类操作会阻塞mysqldump的元数据锁
mysqldump 必须带这几个关键参数
只用 mysqldump -u root -p db_name > backup.sql 是生产环境大忌。它不导存储过程、事件、触发器,也不保证事务一致性,恢复时大概率丢功能逻辑。
正确组合是:
-
--single-transaction:对InnoDB生效,避免锁表,保证备份期间业务可写 -
--routines:导出所有存储过程和函数 -
--events:导出事件调度器定义 -
--triggers:导出触发器 -
--set-gtid-purged=OFF:如果用了GTID复制,不加这个会导致恢复时报错
示例命令:mysqldump -h127.0.0.1 -P3306 -ubackup -p'xxx' --single-transaction --routines --events --triggers --all-databases | gzip > /backup/full_$(date +\%Y%m%d_%H%M%S).sql.gz
备份脚本里必须做状态检查和日志记录
很多脚本跑完不报错,但生成的 .sql.gz 文件只有几KB——其实是认证失败或权限不足,mysqldump 静默退出了。没人看日志,就以为备份成功了。
关键动作:
- 每次执行后立刻检查
mysqldump的退出码:if [[ $? -ne 0 ]]; then echo "dump failed" >&2; exit 1; fi - 用
gzip -t验证压缩包完整性,再用zcat xxx.sql.gz | head -n 10确认开头是CREATE DATABASE而不是一堆错误提示 - 把标准输出和错误都重定向进带时间戳的日志文件,路径固定如
/var/log/mysql_backup/backup_$(date +\%Y%m%d).log,方便排查
crontab 时间表达式容易忽略时区和系统负载
CentOS默认用系统本地时区,但如果你服务器时区设成UTC,而业务方要求“每天北京时间2:00备份”,那 0 2 * * * 实际在UTC时间2:00(即北京时间10:00)运行——直接撞上早高峰。
解决办法:
- 查清系统时区:
timedatectl | grep "Time zone",必要时用timedatectl set-timezone Asia/Shanghai统一 - 加负载保护:在crontab里用
load average判断,比如test $(uptime | awk -F'average:' '{print $2}' | awk '{print $1}' | sed 's/,//') -lt 2.0,超载就跳过本次 - 避免秒级并发:如果同一台机器跑多个备份任务,别全设成
0 2 * * *,错开5分钟,比如一个设0 2 * * *,另一个设5 2 * * *
真正麻烦的从来不是脚本能跑通,而是某天凌晨磁盘突然写满、备份进程被OOM killer干掉、或者MySQL临时密码轮换后脚本继续用旧密码连——这些细节不埋点监控,等出事就晚了。











