1. 为什么需要磁盘空间监控告警
在服务器运维工作中,磁盘空间耗尽是最常见也最危险的故障之一。想象一下凌晨三点被电话叫醒,因为生产数据库突然停止写入,而原因仅仅是日志文件占满了整个分区。这种情况我经历过不止一次,直到建立了完善的磁盘监控体系才彻底解决这个问题。
传统的解决方式是人工定期执行df -h命令查看,但这种方式存在三个致命缺陷:
- 依赖人工记忆检查频率
- 无法实时发现问题
- 缺乏历史数据对比
通过Shell脚本实现的自动化监控方案能完美解决这些问题。我曾为一个电商客户部署的监控脚本,在双十一前一周就预警了日志分区即将爆满的情况,避免了可能造成的千万级损失。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 监控脚本核心设计思路
2.1 基础命令组合方案
核心监控逻辑只需要两个命令的巧妙组合:
bash复制df -h | awk '$5 > 90 {print $6 " 使用率: " $5}'
这个管道命令的工作原理:
df -h以人类可读格式输出磁盘使用情况awk筛选第五列(使用百分比)大于90%的行- 输出第六列(挂载点)和第五列信息
但实际生产环境需要更复杂的处理逻辑,主要考虑:
- 多磁盘分区监控
- 不同分区设置不同阈值
- 告警抑制机制(避免重复告警)
2.2 进阶脚本架构设计
经过多个项目的迭代,我总结出生产级脚本应包含的模块:
bash复制#!/bin/bash
# 配置区
THRESHOLD=90
EXCLUDE_LIST=("/dev/loop" "/snap") # 排除虚拟设备
LOG_FILE="/var/log/disk_monitor.log"
# 初始化函数
init_check(){
[ -f "$LOG_FILE" ] || touch "$LOG_FILE"
}
# 核心监控函数
check_disk(){
local output=$(df -h | awk -v threshold=$THRESHOLD '$5+0 > threshold {print $6,$5}')
# 后续处理逻辑...
}
# 告警函数
send_alert(){
local msg="[$(date)] 警告: $1 使用率 $2"
echo "$msg" >> "$LOG_FILE"
# 实际告警发送逻辑...
}
# 主流程
main(){
init_check
check_disk
}
main
3. 生产环境完整实现方案
3.1 多阈值分级告警机制
不同业务分区应设置不同阈值:
bash复制declare -A THRESHOLDS=(
["/"]=90
["/data"]=95
["/log"]=85
)
对应的检查逻辑升级为:
bash复制check_disk(){
df -h | grep -vE '^Filesystem|tmpfs|cdrom' | while read line; do
local part=$(echo $line | awk '{print $6}')
local use=$(echo $line | awk '{print $5}' | tr -d '%')
[[ -n "${THRESHOLDS[$part]}" ]] && \
[ $use -gt ${THRESHOLDS[$part]} ] && \
send_alert "$part" "$use%"
done
}
3.2 告警抑制与升级策略
为避免告警风暴,需要实现:
- 相同问题30分钟内不重复告警
- 持续问题升级告警级别
bash复制# 在send_alert函数中添加时间判断
last_alert_time=$(grep "$1" "$LOG_FILE" | tail -1 | awk '{print $2}')
current_time=$(date +%s)
if [ -n "$last_alert_time" ]; then
time_diff=$((current_time - $(date -d "$last_alert_time" +%s)))
[ $time_diff -lt 1800 ] && return # 30分钟内不重复告警
fi
4. 告警渠道集成实践
4.1 邮件告警实现
使用mailx发送邮件告警:
bash复制send_mail(){
echo "$1" | mailx -s "磁盘告警 $(hostname)" admin@example.com
}
4.2 企业微信机器人集成
更实时的告警方式:
bash复制send_wechat(){
local api_url="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
curl -s "$api_url" -H 'Content-Type: application/json' \
-d '{"msgtype": "text","text": {"content": "'"$1"'"}}'
}
4.3 告警模板优化技巧
好的告警信息应包含:
- 服务器标识
- 问题详情
- 建议处理方案
- 相关日志片段
示例模板:
bash复制generate_msg(){
echo "主机: $(hostname)
时间: $(date)
问题: $1 使用率 $2
建议: 1. 清理日志 2. 扩容磁盘
最近10条相关日志:
$(grep "$1" "$LOG_FILE" | tail -10)"
}
5. 高级功能扩展
5.1 历史趋势分析
在日志中记录磁盘使用数据:
bash复制log_disk_usage(){
df -h | awk 'NR>1 {print strftime("%Y-%m-%d %H:%M"), $6, $5}' >> /var/log/disk_history.log
}
然后用awk生成简单报表:
bash复制generate_report(){
awk '{
usage[$2][$3]++
} END {
for(part in usage) {
print "分区:", part
for(pct in usage[part]) {
print pct "%:", usage[part][pct], "次"
}
}
}' /var/log/disk_history.log
}
5.2 自动清理机制
对于已知的可清理目录,添加自动处理:
bash复制auto_clean(){
case $1 in
"/log") find /log -type f -mtime +7 -delete ;;
"/tmp") find /tmp -type f -atime +1 -delete ;;
esac
}
注意要添加清理前的确认检查:
bash复制check_before_clean(){
local free_before=$(df -h $1 | awk 'NR==2 {print $4}')
auto_clean $1
local free_after=$(df -h $1 | awk 'NR==2 {print $4}')
echo "清理释放空间: $free_before -> $free_after"
}
6. 生产环境部署要点
6.1 crontab配置建议
合理的检查频率:
bash复制# 每5分钟检查,但只在工作时间告警
*/5 * * * * /path/to/script.sh >> /var/log/disk_monitor.log 2>&1
6.2 日志轮转配置
在/etc/logrotate.d/下创建配置:
code复制/var/log/disk_monitor.log {
daily
rotate 30
missingok
notifempty
compress
}
6.3 性能优化技巧
避免频繁调用df命令:
bash复制# 使用tmpfs缓存结果
CACHE_FILE="/dev/shm/disk_status.cache"
[ -f "$CACHE_FILE" ] && [ $(date +%s -r "$CACHE_FILE") -gt $(date +%s --date="5 minutes ago") ] || df -h > "$CACHE_FILE"
7. 常见问题排查指南
7.1 虚拟文件系统误报
解决方法是在检查中排除特定类型:
bash复制df -h | grep -vE 'tmpfs|devtmpfs|overlay'
7.2 NFS挂载点超时
添加超时控制:
bash复制timeout 5s df -h /nfs_mount || echo "NFS检查超时"
7.3 容器环境适配
在Docker容器中需要特殊处理:
bash复制if [ -f /.dockerenv ]; then
df -h | grep -vE 'overlay|shm'
fi
8. 脚本安全注意事项
- 设置正确的文件权限:
bash复制chmod 750 /path/to/script.sh
chown root:root /path/to/script.sh
- 敏感信息保护:
bash复制# 将API密钥存储在单独的文件中
source /etc/disk_monitor.conf
- 添加执行超时:
bash复制timeout 30s /path/to/script.sh
这套方案在我管理的200+服务器上稳定运行了3年,平均每月预防磁盘问题15+次。关键是要根据实际环境调整阈值和告警方式,建议先在小范围测试后再全量部署。
