真正成功需三重验证:退出码为0、文件非空(test -s)、末尾含sql终止标记;同时捕获stderr关键词分级告警,并加锁、测磁盘、设超时防脚本单点故障。

如何判断 mysqldump 备份是否真正成功
只看 mysqldump 命令退出码($?)不够——它可能返回 0,但实际只导出了一张空表或被中断的半截文件。真正可靠的判断依据是:备份文件存在 + 文件大小显著大于 0 + 文件末尾包含 /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 这类终止标记(表明 SQL 流完整结束)。
实操建议:
- 用
test -s /path/to/backup.sql检查文件非空(比单纯-f更严格) - 用
tail -n 5 backup.sql | grep -q "SET CHARACTER_SET_CLIENT="验证 SQL 结束标记存在 - 避免依赖
mysqldump --single-transaction的“无锁”特性来推断成功——它不保证写入完成
Shell 脚本中捕获 mysqldump 的 stderr 并区分错误类型
mysqldump 的错误信息全走 stderr,且不同错误对应不同关键词:连接拒绝是 Can't connect to MySQL server,权限不足是 Access denied,表不存在是 Unknown table。把这些关键词抓出来,才能做分级告警。
实操建议:
- 重定向 stderr 到变量:
dump_err=$(mysqldump ... 2>&1 >/dev/null) - 用
case匹配错误关键词,而不是简单判断$?是否非 0 - 对
Can't connect类错误立即触发高优先级告警(DB 可能宕机),而Unknown table可记录日志后跳过
如何避免备份脚本自身成为单点故障
脚本跑在 crond 里,但 crond 不保证进程不被 kill、磁盘满时写入失败也不报错、甚至脚本被重复调度导致并发冲突。这些都会让“看似运行了”等于“实际没备份”。
实操建议:
- 加锁:用
if mkdir /tmp/mysql_backup.lock 2>/dev/null; then ...; rmdir /tmp/mysql_backup.lock; fi防重入 - 检查磁盘空间:
df -B1 /backup | awk 'NR==2 {print $4}'获取剩余字节数,低于 2GB 就 abort - 设置超时:
timeout 3600 mysqldump ...防止大库卡死整个调度队列
用 mail 或 curl 发送告警时的关键细节
很多脚本用 mail -s "Backup FAIL" admin@example.com,但生产环境邮件常被过滤或延迟;用 curl 推送到企业微信/钉钉更可靠,但要注意 JSON 格式和 token 权限。
实操建议:
- 邮件告警必须带时间戳和错误上下文:
echo "$(date): $dump_err" | mail -s "[MySQL Backup] FAILED on $(hostname)" admin@example.com - 钉钉告警需构造合法 JSON:
curl -H 'Content-Type: application/json' -d '{"msgtype":"text","text":{"content":"Backup failed: '$dump_err'"}}' https://oapi.dingtalk.com/robot/send?access_token=xxx - 所有网络告警必须加
timeout 10和|| true,防止 curl 失败导致脚本中断











