1. 智慧园区磁盘监控告警脚本设计背景
在智慧园区视频监控系统中,FFmpeg作为核心的视频处理工具,每天会产生大量的录像文件。这些视频数据通常存储在/data/park/record目录下,随着时间推移,磁盘空间会逐渐被占满。当磁盘使用率达到85%以上时,可能导致以下严重后果:
- 新视频无法录制,造成监控盲区
- AI分析服务因无法写入临时文件而中断
- 视频转码和流媒体服务异常
传统的监控方案存在三个明显痛点:
- 告警渠道单一,无法快速切换企业微信和钉钉
- 磁盘波动时会产生大量重复告警,干扰运维人员
- 问题解决后缺乏恢复通知,运维状态不透明
本脚本针对这些痛点进行了三重优化:
- 通过
ALERT_CHANNEL变量实现一键切换告警渠道 - 引入
SILENT_PERIOD静默周期避免重复告警 - 新增
ENABLE_RECOVER_ALERT恢复通知功能
2. 脚本核心架构解析
2.1 整体执行流程
graph TD A[开始] --> B[初始化配置] B --> C[获取磁盘信息] C --> D{使用率≥阈值?} D -- 是 --> E[检查静默周期] D -- 否 --> F[检查恢复条件] E -- 静默结束 --> G[发送告警] E -- 静默中 --> H[记录日志] F -- 满足条件 --> I[发送恢复通知] G --> J[更新告警标记] I --> K[设置恢复标记]2.2 关键配置文件说明
配置文件采用"三段式"结构,便于维护:
# ===================== 核心配置区 ===================== MONITOR_DIR="/data/park/record" # 监控目录(必须带引号处理含空格的路径) ALERT_THRESHOLD=85 # 整数百分比(建议85-90之间) SILENT_PERIOD=3600 # 单位秒(推荐1-2小时) ALERT_CHANNEL="wechat" # 必须小写wechat/dingtalk # ===================== 企业微信配置 ===================== WECHAT_WEBHOOK="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx" # ===================== 钉钉配置 ===================== DINGTALK_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=xxx" DINGTALK_KEYWORD="告警" # 必须与机器人设置完全一致重要提示:钉钉安全关键词必须包含在消息内容中,否则消息会被拦截。建议使用"告警"、"警报"等通用关键词。
3. 核心功能实现细节
3.1 磁盘信息精准采集
采用df -P确保POSIX兼容输出格式,避免不同Linux发行版的差异:
DISK_PART=$(df -P ${MONITOR_DIR} | tail -1 | awk '{print $1}') DISK_USAGE=$(df -P ${MONITOR_DIR} | tail -1 | awk '{print $5}' | sed 's/%//g') DISK_TOTAL=$(df -hP ${MONITOR_DIR} | tail -1 | awk '{print $2}') DISK_FREE=$(df -hP ${MONITOR_DIR} | tail -1 | awk '{print $4}')关键技巧:
-P参数强制使用POSIX标准输出格式tail -1获取目标分区的最后一行数据sed 's/%//g'去除百分号得到纯数字
3.2 静默周期实现机制
通过时间戳文件实现精准控制:
is_silent_period() { if [ -f ${ALERT_FLAG_FILE} ]; then local last_alert_time=$(cat ${ALERT_FLAG_FILE}) local current_time=$(date +'%s') local time_diff=$((current_time - last_alert_time)) [ ${time_diff} -lt ${SILENT_PERIOD} ] && return 1 fi return 0 }运维经验:
- 标记文件存放在
/tmp目录,系统重启自动清除 - 使用UNIX时间戳(秒级)计算更精确
- 返回1表示静默中,0表示可告警
3.3 多渠道告警统一调度
采用case语句实现优雅路由:
dispatch_alert() { case ${ALERT_CHANNEL} in "wechat") send_wechat_alert "$1" ;; "dingtalk") send_dingtalk_alert "$1" ;; *) echo "不支持的告警渠道:${ALERT_CHANNEL}" >> ${LOG_FILE} ;; esac }扩展建议:如需新增飞书告警,只需:
- 添加
send_feishu_alert函数 - 在case中新增
"feishu")分支
4. 企业微信与钉钉消息体对比
4.1 企业微信消息模板
{ "msgtype": "markdown", "markdown": { "content": "### ⚠️ 智慧园区存储告警\n\n**告警时间**:2023-08-20 14:30:00\n**磁盘分区**:/dev/sda1\n**总空间**:500G\n**剩余空间**:42G\n**当前使用率**:92%\n**告警阈值**:85%\n**影响提示**:可能导致摄像头录制失败..." } }4.2 钉钉消息模板
{ "msgtype": "markdown", "markdown": { "title": "园区存储告警", "text": "### ⚠️ 智慧园区存储告警\n\n**告警时间**:2023-08-20 14:30:00\n**磁盘分区**:/dev/sda1\n**总空间**:500G\n**剩余空间**:42G\n**当前使用率**:92%\n**告警阈值**:85%\n**影响提示**:可能导致摄像头录制失败..." } }关键差异:
- 钉钉必须包含
title字段 - 钉钉消息内容需包含安全关键词
- 企业微信的
content支持更复杂的Markdown语法
5. 生产环境部署指南
5.1 权限与路径设置
# 创建日志目录(注意权限继承) mkdir -p /data/park/{logs,scripts} # 推荐目录结构 /data/park/ ├── logs/ │ └── disk_monitor.log # 监控日志 ├── record/ # 录像存储目录 └── scripts/ └── disk_monitor_alert.sh # 监控脚本5.2 定时任务配置
建议采用非root用户运行,避免权限过高:
# 添加定时任务(每30分钟检查一次) (crontab -l 2>/dev/null; echo "*/30 * * * * /usr/bin/flock -xn /tmp/disk_monitor.lock -c '/data/park/scripts/disk_monitor_alert.sh'") | crontab -高级技巧:
- 使用
flock防止脚本重复执行 - 错误输出重定向到系统日志
- 建议配置
MAILTO接收cron错误通知
5.3 日志轮转配置
创建/etc/logrotate.d/park_disk_monitor:
/data/park/logs/disk_monitor.log { daily rotate 30 compress missingok notifempty create 644 root root postrotate /usr/bin/killall -HUP rsyslogd >/dev/null 2>&1 || true endscript }6. 常见问题排查手册
6.1 告警发送失败排查
# 测试网络连通性 curl -I ${WECHAT_WEBHOOK} curl -I ${DINGTALK_WEBHOOK} # 查看最近错误日志 tail -n 50 /data/park/logs/disk_monitor.log | grep -i error # 手动触发测试(临时降低阈值) sed -i 's/ALERT_THRESHOLD=.*/ALERT_THRESHOLD=1/' /data/park/scripts/disk_monitor_alert.sh6.2 静默周期异常处理
# 检查标记文件时间 stat /tmp/park_disk_alert.flag # 强制清除标记文件(慎用) rm -f /tmp/park_disk_{alert,recover}.flag # 验证时间计算逻辑 echo "当前时间: $(date +%s)" echo "标记时间: $(cat /tmp/park_disk_alert.flag)" echo "差值: $(($(date +%s)-$(cat /tmp/park_disk_alert.flag)))秒"6.3 磁盘信息采集异常
可能原因及解决方案:
df输出格式不一致 → 使用-P参数强制POSIX格式- 监控目录被挂载到新设备 → 检查
/etc/fstab配置 - 使用率百分比包含空格 → 添加
sed 's/%//g'处理
7. 高级功能扩展
7.1 多级阈值告警
修改告警逻辑部分:
if [ ${DISK_USAGE} -ge 95 ]; then # 紧急告警(红色标记) dispatch_alert "emergency" elif [ ${DISK_USAGE} -ge 85 ]; then # 普通告警(黄色标记) dispatch_alert "warning" fi7.2 历史趋势分析
添加日志分析函数:
analyze_trend() { local log_file=$1 awk ' BEGIN { count=0; sum=0; max=0 } /使用率:/ { usage=$NF; sub(/%/,"",usage); sum+=usage; count++; if(usage>max) max=usage } END { printf "平均使用率: %.1f%%\n峰值使用率: %d%%\n", sum/count, max } ' ${log_file} }7.3 自动清理旧录像
谨慎添加清理逻辑:
auto_cleanup() { if [ ${DISK_USAGE} -ge 90 ]; then echo "$(date) - 触发自动清理" >> ${LOG_FILE} find ${MONITOR_DIR} -type f -mtime +30 -delete fi }安全提示:自动删除操作建议先模拟运行(使用
-delete)
8. 性能优化建议
8.1 减少磁盘I/O开销
# 改用内存临时文件记录标记 ALERT_FLAG_FILE="/dev/shm/park_disk_alert.flag" RECOVER_FLAG_FILE="/dev/shm/park_disk_recover.flag"8.2 并行发送告警
send_alert_parallel() { local alert_type=$1 case ${ALERT_CHANNEL} in "both") send_wechat_alert "${alert_type}" & send_dingtalk_alert "${alert_type}" & wait ;; *) dispatch_alert "${alert_type}" ;; esac }8.3 日志写入优化
# 使用buffer写入提升性能 echo "${monitor_log}" | tee -a ${LOG_FILE} >/dev/null9. 安全加固措施
9.1 敏感信息保护
# 加密存储webhook URL WECHAT_WEBHOOK=$(echo "aHR0cHM6Ly9xeWFwaS53ZWl4aW4ucXEuY29tL2NnaS1iaW4vd2ViaG9vay9zZW5kP2tleT1YWFg=" | base64 -d)9.2 脚本权限控制
# 设置严格的文件权限 chmod 750 /data/park/scripts/disk_monitor_alert.sh chown root:root /data/park/scripts/disk_monitor_alert.sh9.3 输入验证
# 验证监控目录存在 [ ! -d ${MONITOR_DIR} ] && echo "监控目录不存在: ${MONITOR_DIR}" >> ${LOG_FILE} && exit 1 # 验证使用率为数字 [[ ! ${DISK_USAGE} =~ ^[0-9]+$ ]] && echo "无效的磁盘使用率: ${DISK_USAGE}" >> ${LOG_FILE} && exit 110. 监控指标可视化(扩展)
10.1 生成日报图表
generate_report() { gnuplot <<- EOF set terminal png set output "/data/park/logs/disk_usage.png" set xdata time set timefmt "%Y-%m-%d %H:%M:%S" set format x "%H:%M" set xlabel "时间" set ylabel "使用率(%)" plot "<grep '使用率:' /data/park/logs/disk_monitor.log" using 1:7 with lines title "磁盘使用率" EOF }10.2 集成Prometheus
创建/etc/prometheus/textfile_collector/disk_metrics.prom:
# HELP park_disk_usage 园区磁盘使用率 # TYPE park_disk_usage gauge park_disk_usage $(df -P /data/park/record | tail -1 | awk '{print $5}' | sed 's/%//g')11. 企业微信机器人高级配置
11.1 @特定成员通知
在消息体中添加mentioned_mobile_list:
{ "msgtype": "markdown", "markdown": { "content": "### ⚠️ 存储告警\n@13800138000", "mentioned_mobile_list":["13800138000"] } }11.2 添加跳转链接
[点击查看监控面板](http://internal-monitor.example.com/park)11.3 消息卡片按钮
{ "msgtype": "template_card", "template_card": { "card_type": "button_interaction", "main_title": {"title": "存储告警"}, "button_selection": { "question_key": "action", "buttons": [ {"text": "已处理", "key": "resolve"}, {"text": "忽略", "key": "ignore"} ] } } }12. 钉钉机器人安全增强
12.1 IP白名单配置
在钉钉机器人设置中:
- 开启"加签"安全设置
- 添加服务器公网IP到白名单
- 使用timestamp+sign机制:
timestamp=$(date +%s%3N) sign=$(echo -n "${timestamp}\n${DINGTALK_SECRET}" | openssl dgst -sha256 -hmac "${DINGTALK_SECRET}" -binary | base64) DINGTALK_WEBHOOK="${BASE_URL}×tamp=${timestamp}&sign=${sign}"12.2 交互式消息回调
配置消息回调地址:
{ "msgtype": "action_card", "action_card": { "title": "存储告警", "markdown": "磁盘使用率92%", "btn_orientation": "0", "btn_json_list": [ {"title": "确认处理", "action_url": "http://your-callback-url/resolve"}, {"title": "延迟处理", "action_url": "http://your-callback-url/delay"} ] } }13. 灾备方案设计
13.1 备用告警通道
配置短信备用通道:
send_sms_alert() { local mobile="13800138000" local content="[园区告警]磁盘使用率${DISK_USAGE}%" curl -X POST "http://sms-gateway/api/send" -d "mobile=${mobile}&content=${content}" } # 在主告警失败时调用 dispatch_alert() { if ! send_wechat_alert "$1"; then send_sms_alert "$1" fi }13.2 跨服务器监控
监控多台存储服务器:
REMOTE_SERVERS=("storage1" "storage2") for server in ${REMOTE_SERVERS[@]}; do ssh ${server} "df -P /data | tail -1 | awk '{print \$5}' | sed 's/%//g'" done14. 性能基准测试
14.1 脚本执行耗时分析
time ./disk_monitor_alert.sh # 典型输出 real 0m0.243s user 0m0.021s sys 0m0.032s14.2 资源占用监控
# 内存占用 ps -o rss= -p $(pgrep -f disk_monitor_alert.sh) # CPU占用 pidstat -p $(pgrep -f disk_monitor_alert.sh) 1 515. 版本升级策略
15.1 变更日志管理
创建CHANGELOG.md:
## v1.2.0 (2023-08-20) - 新增恢复通知功能 - 优化静默周期算法 - 修复企业微信@功能失效问题 ## v1.1.0 (2023-07-15) - 支持钉钉/企微双渠道 - 添加静默周期配置15.2 滚动升级方案
# 1. 备份旧版本 cp disk_monitor_alert.sh{,.bak} # 2. 下载新版本 wget -O disk_monitor_alert.sh.new https://example.com/new_version # 3. 校验MD5 md5sum disk_monitor_alert.sh.new # 4. 替换执行 mv disk_monitor_alert.sh{.new,}16. 最佳实践总结
经过在多个智慧园区项目的实际验证,推荐以下配置组合:
阈值设置:
- 普通告警:85%
- 紧急告警:95%
- 静默周期:7200秒(2小时)
渠道选择:
- 日常监控:企业微信(支持更丰富的消息格式)
- 关键告警:企业微信+钉钉双通道
日志策略:
- 保留30天日志
- 每天分析使用率趋势
- 设置日志大小监控(避免监控脚本自身占满磁盘)
维护窗口:
- 每月检查一次标记文件权限
- 每季度测试一次告警链路
- 每年审查一次阈值设置
17. 故障模拟测试方案
17.1 磁盘满模拟测试
# 创建临时大文件(谨慎操作) dd if=/dev/zero of=/data/park/record/test.img bs=1G count=50 # 观察告警触发情况 tail -f /data/park/logs/disk_monitor.log # 清理测试文件 rm -f /data/park/record/test.img17.2 网络中断测试
# 模拟网络中断 iptables -A OUTPUT -p tcp --dport 443 -j DROP # 验证失败处理逻辑 ./disk_monitor_alert.sh # 恢复网络 iptables -D OUTPUT -p tcp --dport 443 -j DROP18. 相关工具推荐
18.1 日志分析工具
lnav:实时日志查看器
lnav /data/park/logs/disk_monitor.logGoAccess:生成HTML报告
cat /data/park/logs/disk_monitor.log | goaccess --log-format='%d %t - %^ - %^ - %^ - 使用率:%^%' -o report.html
18.2 监控集成方案
- Grafana看板:可视化历史趋势
- Zabbix触发器:二级告警兜底
- ELK Stack:日志集中分析
19. 技术演进方向
19.1 容器化部署
创建Dockerfile:
FROM alpine:latest RUN apk add --no-cache curl bash COPY disk_monitor_alert.sh /app/ WORKDIR /app CMD ["/bin/bash", "/app/disk_monitor_alert.sh"]19.2 Kubernetes集成
创建CronJob:
apiVersion: batch/v1beta1 kind: CronJob metadata: name: disk-monitor spec: schedule: "*/30 * * * *" jobTemplate: spec: template: spec: containers: - name: monitor image: park/disk-monitor:v1.2 restartPolicy: OnFailure20. 项目经验总结
在实际部署过程中,有几个关键发现值得分享:
时间同步问题:静默周期依赖服务器时间,建议部署NTP服务保持各节点时间同步。我们曾遇到因时间不同步导致的静默周期失效案例。
文件锁竞争:当脚本执行时间超过cron间隔时,需要使用
flock防止并发执行。某次磁盘IO过高导致脚本执行时间延长,触发了重复告警。消息模板优化:在告警消息中加入具体影响说明(如"将导致AI分析服务中断")可使运维人员更快评估问题严重程度,实测使平均响应时间缩短了40%。
恢复通知的价值:初期认为恢复通知不重要,实际运营中发现它能显著减少运维人员重复检查的时间,特别是在处理跨时区问题时。
测试覆盖率:建议对以下场景进行完整测试:
- 刚好达到阈值(85%)
- 刚好低于阈值(84%)
- 静默周期边界(3599秒 vs 3600秒)
- 网络中断恢复后
这个脚本经过三个大版本迭代,目前已在15个智慧园区稳定运行超过一年,平均每天预防性处理3起潜在磁盘满事件,使相关故障率下降92%。