Linux磁盘空间监控方案_提前预警思路解析【指导】

11次阅读

根本原因是df默认统计文件系统级可用空间,未考虑inode耗尽、root保留空间(通常5%)及已删除但被进程占用的文件;需同步运行df -i检查inode,并用lsof +L1或find /proc/*/fd -ls | grep deleted定位“隐形”占空间文件。

Linux磁盘空间监控方案_提前预警思路解析【指导】

df 命令的精度陷阱:为什么 df -h 显示还有 10% 却报 “No space left on device”

根本原因不是显示不准,而是 df 默认统计的是 **文件系统级可用空间**,不考虑 inode 耗尽、root 用户保留空间(通常是 5%)、或被已删除但进程仍占用的文件(/proc/*/fd/ 下的 deleted 文件)。

  • df -i 必须同步检查 —— 尤其在大量小文件场景(如日志归档、容器镜像层),Inodes 先用完很常见
  • 普通用户看到的 “Available” 是扣除了 root 保留空间后的值;但某些服务(如 nginxdockerd)以 root 身份运行,实际可用空间比 df -h 显示的 Avail 还多约 5%
  • lsof +L1find /proc/*/fd -ls 2>/dev/NULL | grep deleted 找出“看不见却占空间”的已删文件

inotifywait 监控关键目录写入暴增(比定时轮询更准)

定时脚本(如每 5 分钟跑一次 df)只能发现“已经满了”,而 inotifywait 可捕获 CREATEWRITEMOVED_TO事件,在磁盘还没满时就识别出异常写入源。

  • 只监控高风险路径:/var/log/tmp/var/lib/docker/overlay2(Docker 主机)、/data(业务数据盘)
  • 避免递归过深:用 -m(monitor 模式)+ --format '%w%f %e' 输出路径和事件,配合 awk 统计单位时间内的写入频次
  • 注意权限:若监控目录属其他用户(如 www-data),需用对应用户运行或加 sudo,否则收不到事件
inotifywait -m -e create,modify,attrib /var/log --format '%w%f %e' |    awk '{print $1}' |    awk '{count[$1]++}         NR%60==0 {for (i in count) if (count[i] > 50) print "ALERT: " i " written " count[i] " times in last minute"; delete count}'

Shell 脚本预警阈值设置:别只写 90%,要分层 + 排除临时波动

编码 if [ $(df / | awk 'NR==2 {print }' | sed 's/%//') -gt 90 ] 会误报。真实环境必须加缓冲、分等级、跳过瞬时峰值。

  • 连续 3 次超过阈值才触发(用文件记录上次时间戳和次数)
  • 设置两级阈值:85% 发 warning(钉钉/企业微信),95% 发 critical(短信 + 电话)
  • 排除已知临时目录:比如 /tmp 上的 systemd-private-* 目录,用 df --exclude-type=tmpfs 或过滤挂载点
  • 对 LVM 逻辑卷,用 lvs 替代 df 查看 LV 使用率,避免因 ext4 预分配导致的误判

python 脚本整合 prometheus + Alertmanager 实现自动分级告警

纯 Shell 难以支撑多维度判断(如:空间增长速率 + inode 使用率 + 特定目录子目录数量),Python 更适合做决策中枢。

  • psutil.disk_usage(path) 获取精确字节级数据,比 subprocess.run(["df"]) 更稳定
  • 计算 10 分钟内 /var/log 的大小变化率:(current_size - size_10m_ago) / 10 / 60,超 5MB/s 触发日志风暴告警
  • 暴露为 Prometheus metrics:用 prometheus_client 库注册 disk_used_percentinode_used_percentlog_dir_growth_rate_bytes
  • Alertmanager 配置中用 absent() 检测采集中断,避免“假阴性”——磁盘没满,但监控进程挂了
from prometheus_client import Gauge, start_http_server import psutil 

disk_gauge = Gauge('disk_used_percent', 'Disk usage percent', ['mount']) inode_gauge = Gauge('inode_used_percent', 'Inode usage percent', ['mount'])

def collect_disk_stats(): for part in psutil.disk_partitions(): if part.fstype in ('ext4', 'xfs', 'btrfs'): try: usage = psutil.disk_usage(part.mountpoint) disk_gauge.labels(mount=part.mountpoint).set(usage.percent)

注意:psutil 不直接提供 inode,需调用 os.statvfs

        except (OSError, FileNotFoundError):             pass

真正容易被忽略的,是 保留空间策略与服务身份的错配:比如把 /var/lib/postgresql 放在默认保留 5% 的 xfs 分区上,而 PostgreSQL 进程以 postgres 用户运行(非 root),它就无法使用那 5%,等于实际可用空间直接少了 5%。这种细节,只有查 xfs_infoid -u postgres 对齐后才能确认。

text=ZqhQzanResources