只靠 cron MAILTO 会静默失败,因其仅转发 stdout/stderr,而 mysqldump 关键错误走 stderr;若脚本中重定向为 > backup.sql 2>/dev/null,则失败彻底消失;且 cron 环境 PATH 极简,mail 命令常不可用,须在脚本内显式调用 /bin/mailx 并校验其存在,同时禁用 --force、用 $? 和 head -c1 验证真实失败,告警内容须含主机名、时间、版本、磁盘空间、最近5行脱敏 stderr 等可定位信息。
cron 的 MAILTO 只转发 stdout/stderr,但 mysqldump 关键错误默认走 stderr —— 一旦你在脚本里写了 > backup.sql 2>/dev/null,整个失败过程就彻底消失。更糟的是,cron 环境 PATH 极简,mail 命令常根本找不到。
必须在脚本内显式调用:/bin/mailx -s "MySQL Backup FAIL on $(hostname)" [email protected]
mailx,它不依赖交互配置,在 cron 下更稳定;避免 mutt,容易卡住which mailx >/dev/null || { echo "mailx not found"; exit 1; }
/dev/null,至少保留到临时文件供后续分析$?,不能看文件大小mysqldump 成功返回 0,失败返回非 0 码(常见:2=连接失败、3=权限不足、4=找不到表、11=临时 I/O 错误)。if [ $? -ne 0 ] 是唯一可靠依据。
用 ls -l 或 stat -c%s 判断文件大小 >0 完全不可靠 —— gzip 头信息会让空文件也有 20+ 字节;--force 参数会让 mysqldump 忽略错误继续执行,生成空 SQL 却返回 0。
--force 参数mysqldump | gzip),退出码是 gzip 的,需用 ${PIPESTATUS[0]} 捕获 mysqldump 真实状态head -c 1 backup.sql | wc -c,结果为 0 才说明首字节不可读“备份失败”四个字毫无价值。运维凌晨三点爬起来,需要的是“在哪台机器、哪个库、因何失败、现在磁盘还剩多少、上一次成功是什么时候”。
钉钉/邮件正文固定包含:
$(hostname) 和 $(date)
mysqldump --versiondf -h /backup(尤其关注 /backup 分区)ls -lh /backup/*.sql | tail -3sed '/-p|password|@/d')错误日志截取要精准:从最后一次 mysqldump 开始,到下一个时间戳前为止,避免混入旧日志。
直接把 mysqldump -u root -p123456 或完整报错日志发到钉钉,等于把数据库凭据贴在群里。第一责任在告警脚本本身。
--defaults-file=/root/.my.cnf,并确保该文件权限为 chmod 600
sed '/-p|password|@/d'
@10.0.2.5)、绝对路径(如 /root/.my.cnf)真正容易被忽略的不是怎么发告警,而是告警里有没有暴露不该暴露的东西 —— 很多团队的告警流程,恰恰是第一个泄露面。