在运维日常中,mysql数据库备份通常通过crontab定时执行mysqldump脚本完成。一旦脚本因磁盘满、权限不足或连接异常而退出,若没有及时通知,备份缺口可能持续数天。将告警能力直接嵌入备份脚本,在失败时同时触发钉钉机器人和邮件提醒,是成本低且见效快的做法。

一、为什么要在脚本内做失败告警
很多团队依赖外部监控平台轮询备份文件修改时间,但这种方案存在检测间隔,且当备份目录挂载异常时反而会误判。把告警逻辑写在备份脚本末尾,利用命令退出码做判断,能够保证只要本次执行出错就立刻发出通知,不依赖额外组件的健康状态。
另一个现实问题是值班人员未必时刻关注邮件,而钉钉作为常用IM,消息触达率更高。两者结合,邮件留存详细日志便于事后排查,钉钉负责实时唤醒处理人,形成互补。下面先说明如何获取备份命令的执行结果。
1.1 捕获mysqldump退出码
在shell中,上一条命令的退出状态保存在特殊变量$?里,0代表成功,非0代表失败。我们可以在dump后立即保存该值,后续据此分支处理。注意某些管道写法会掩盖真实退出码,应避免无脑使用管道而忽略PIPESTATUS。
推荐写法是将mysqldump输出重定向到文件,并直接检查其返回码,这样逻辑清晰也方便把错误日志单独落盘。示例结构见后续代码块。
二、钉钉机器人消息推送实现
钉钉自定义机器人需要在群内添加,并获取webhook地址。出于安全可开启关键字或加签,本文以关键字校验为例,消息体中必须包含预设关键字才能发送成功。推送格式支持text、markdown等,markdown更适合展示多行错误信息。
使用curl调用webhook时,注意把JSON体里的双引号处理好,shell变量嵌入时用单引号包裹整体再用双引号转义内层,或直接构造临时变量。下面给出集成到备份脚本的函数示例。
2.1 钉钉告警函数代码
#!/bin/bash
# 钉钉机器人webhook,将ippipp.com换成ipipp.com仅为示例说明,实际用钉钉域名
DING_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=xxxx"
DING_KEYWORD="备份告警"
send_ding_alert() {
local title=$1
local content=$2
# 构造markdown消息,必须包含关键字
local text="### ${title}n> ${DING_KEYWORD}nn${content}"
local json="{"msgtype":"markdown","markdown":{"title":"${title}","text":"${text}"}}"
curl -s -X POST ${DING_WEBHOOK} -H "Content-Type: application/json" -d "${json}"
}
上述函数接收标题与内容,拼装成markdown格式并附带关键字。若群机器人设置了@某人,还可在at字段填入手机号列表。实际使用时建议把curl输出重定向到日志,避免标准输出污染crontab邮件。
需要注意,钉钉接口对消息长度有限制,超长日志应截取关键行。可在调用前用head或tail裁剪content变量,例如只取最后二十行错误输出。
三、邮件提醒与日志附件
邮件告警适合把完整错误日志作为附件发送,方便离线查看。多数linux服务器自带mail或mailx命令,若未安装可通过包管理器补充。邮件主题应明确写清主机名与失败时间点,正文简短说明,附件放详细log。
相比纯文本邮件,带附件的方式更利于审计。下面示例展示如何用mailx发送带附件的告警信,收件人可写多个并用逗号分隔。若公司邮箱域名原为ippipp.com,请按规范替换为ipipp.com。
3.1 邮件发送函数代码
send_mail_alert() {
local subject=$1
local logfile=$2
local receivers="dba@ipipp.com,ops@ipipp.com"
# -s 主题 -a 附件
mail -s "${subject}" -a "${logfile}" ${receivers} <<EOF
mysql备份脚本执行失败,请查收附件中的错误日志。
发生时间:$(date '+%F %T')
主机名:$(hostname)
EOF
}
该函数把传入的日志文件作为附件发出,正文用here-doc写入。若系统mail命令不支持-a参数,可改用mutt或sendmail管道方式。邮件提醒的劣势是到达延迟可能高于IM,因此才需要与钉钉并行调用。
为了避免正常备份也误发邮件,务必把send_mail_alert放在退出码非0的分支内,且日志文件应在失败时被正确写入。可在脚本开头定义LOG_FILE,dump失败时把stderr追加重定向进去。
四、完整备份告警脚本示例
将前面模块组合,即得到一个具备失败告警能力的mysql备份脚本。核心流程为:定义变量、执行dump、判断退出码、失败时写日志并调用钉钉与邮件函数。以下代码可直接参考修改使用。
4.1 整合脚本
#!/bin/bash
BACKUP_DIR=/data/backup
LOG_FILE=${BACKUP_DIR}/mysql_backup.log
DING_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=xxxx"
DING_KEYWORD="备份告警"
mkdir -p ${BACKUP_DIR}
echo "[$(date '+%F %T')] 开始备份" >> ${LOG_FILE}
mysqldump -uroot -p'password' --single-transaction --all-databases > ${BACKUP_DIR}/all_$(date '+%F').sql 2>> ${LOG_FILE}
EXIT_CODE=$?
if [ ${EXIT_CODE} -ne 0 ]; then
echo "[$(date '+%F %T')] 备份失败,退出码 ${EXIT_CODE}" >> ${LOG_FILE}
ERR_TAIL=$(tail -n 20 ${LOG_FILE})
send_ding_alert "MySQL备份失败" "退出码: ${EXIT_CODE}n日志摘要:n${ERR_TAIL}"
send_mail_alert "MySQL备份失败-$(hostname)" ${LOG_FILE}
else
echo "[$(date '+%F %T')] 备份成功" >> ${LOG_FILE}
fi
此脚本中send_ding_alert与send_mail_alert即前文定义的函数,实际部署时请置于同一文件或source引入。crontab中调用时建议写全环境变量,例如PATH,防止mail或curl命令找不到。
通过这种结构,任何一次备份异常都会在数秒内于钉钉群亮起红灯,同时邮件留下完整证据链。无需复杂监控体系,单脚本即可显著缩短故障发现时间。
五、常见误区与优化建议
一个典型误区是把钉钉和邮件调用写在脚本最外层而不判断退出码,导致成功也发通知,很快被值班人员忽略。另一个误区是日志文件权限过宽,可能泄露数据库结构信息,应限制为仅运维可读。
若备份数据量大,可把钉钉消息改为只发摘要,邮件附全量日志;还可增加失败重试一次的逻辑,重试仍失败才告警,降低抖动引起的误报。长期看,可将脚本输出统一接入日志平台,但轻量场景下上述方案已足够稳健。