资讯详情

Node.js 获取磁盘空间:从原理到监控告警实战

📅 2026/10/13 15:23:43 | 华诺云谱 👁 阅读
Node.js 获取磁盘空间:从原理到监控告警实战
做文件上传功能的时候我踩过一个特别实在的坑用户传大文件传到一半磁盘满了程序直接抛异常前台上传失败后台上半截数据还留在那儿占着空间。后来我养成了一个习惯——凡是涉及写盘的服务启动前先看看磁盘还剩多少地方。在 Node.js 里把这个需求落地就是这篇要写的“获取磁盘空间信息”。这个功能听起来不起眼但它在服务器监控、自动化运维、日志清理、桌面应用存储展示这些场景里都是刚需中的刚需。这篇内容适合三类人跑 Node.js 后端服务的开发者、喜欢用脚本做运维自动化的朋友、还有用 Electron 做桌面应用的工程师。我会从技术选型、原生 API 原理、跨平台兼容、完整演练案例到生产环境的坑一层一层拆开讲。看完之后你不光能直接抄代码还能明白这些代码背后的逻辑遇到问题知道怎么排查。1. 需求场景与技术选型获取磁盘空间为什么没有想象中简单1.1 先从几个真实需求场景说起获取磁盘空间信息这个需求乍一看特别简单。写命令的在 Linux 终端里输入 df -h三秒钟就能看到文件系统的挂载点、容量、已用空间、可用空间和使用率。但问题在于服务是拿 Node.js 写的我们需要用程序化的方式拿到磁盘信息然后参与到业务逻辑里去。手动敲一条命令和写代码自动获取完全是两码事。我梳理了一下实际开发中常见的需求场景大概有这么几类第一类是上传前的空间预检。比如做一个文件共享系统或者网盘应用用户上传大文件之前服务端先检查目标目录所在磁盘的剩余空间如果不够就直接拒绝上传给用户一个明确的提示。省得用户传了半天才发现失败也避免服务端陷入“写了一半磁盘满了”的尴尬状态。第二类是磁盘告警监控。服务器上跑着日志服务、数据库和各种定时任务磁盘一旦满了会引发连锁反应——数据库写入失败、日志丢失、备份任务中断。所以需要在后台定时读取磁盘空间超过阈值就推送告警通知。这类场景通常要同时采集多块磁盘、多个挂载点的信息。第三类是桌面应用的存储展示。用 Electron 做桌面应用的时候界面上要显示本机磁盘使用情况某个路径在哪个盘符、用了多少、剩多少做成可视化进度条。这里涉及的平台就多了开发环境是 macOS用户环境是 Windows服务器是 Linux。这些场景共同要求方案有足够的跨平台能力。选型的第一原则就是不能只在 Linux 上能用然后 Windows 用户一跑就崩。1.2 四条技术路线对比选原生还是选第三方库我在项目里实际比较过四条技术路线各有各的适用场景。第一条调用系统命令再解析输出。通过 child_process 执行 df 命令Linux/macOSWindows 上执行 wmic 或 PowerShell 的 Get-PSDrive然后解析标准输出拿到数据。这个方案的好处是不装任何额外依赖但缺点非常突出不同系统的命令格式完全不同解析逻辑要分平台写还要处理本地化语言环境的差异。举个例子德语系统的 df 输出里“已用空间”那一列的标题用的不是英文如果正则写死了匹配 Used解析就直接失败。光这一条就把我劝退了。第二条使用 Node.js 原生 API。Node.js 在 v18.15.0 和 v19.2.0 之后提供了 fs.statfs 方法可以直接返回文件系统的统计信息不需要安装任何包。这是目前最推荐的方式条件允许的情况下优先用它。第三条使用 diskusage 这个第三方库。这是社区里比较经典的方案用原生模块包装了系统调用底层做了一些跨平台兼容接口非常简洁一行代码就能拿到 { available, free, total }。但它需要编译原生模块在部分环境安装时可能遇到构建工具缺失的问题。第四条使用 check-disk-space 这个库。它的定位和 diskusage 类似但实现思路完全不同——它是通过 child_process 包装系统命令来获取数据的。好处是安装简单纯 JavaScript 实现不会遇到编译问题坏处是每次调用要启动子进程速度稍微慢一点。不过检查磁盘空间本来就是低频操作多花几毫秒完全可以接受。这四条路线我用一个表格做个对比方便大家按自己的场景挑方案跨平台额外依赖需要编译性能适用场景child_process 系统命令需分平台写解析无否中快速原型、无依赖要求fs.statfs 原生 API支持无否高Node.js 18.15diskusage支持有是高老版本 Node.js 项目check-disk-space支持有否中老版本 Node.js 项目我个人的选型建议如果项目用的是 Node.js 18.15 及以上版本直接用原生 fs.statfs少一个依赖就少一个风险如果项目还挂着老版本 Node.js那就选 check-disk-space。我们团队当前的项目锁定在 Node.js 20 LTS所以这篇文章的主体我会以原生 API 为主再补一个 check-disk-space 的兼容方案供参考。2. 核心细节解析fs.statfs 返回值与磁盘空间的换算原理2.1 fs.statfs 的返回值到底是什么意思很多朋友第一次看到 fs.statfs 的返回对象会愣一下为什么属性名这么奇怪为什么不是直接给多少字节我们先来看一眼这个 API 的基本用法import fs from node:fs/promises; const stats await fs.statfs(/); console.log(stats);在一台 Linux 服务器上输出大概长这样{ type: 234881026, bsize: 4096, blocks: 195260887, bfree: 182350748, bavail: 172561534, files: 19660800, ffree: 19539435, favail: 19539435 }逐个解释这些字段type文件系统的类型标识。这是一个数字编码不同的文件系统对应不同的值比如 ext4、xfs、btrfs 各有各的编号。如果你需要判断当前路径挂载的是什么类型的文件系统就用这个字段。bsize块大小单位是字节。绝大多数 Linux 文件系统的块大小是 4096 字节4K但有些文件系统可能是 512 或 1024。你可以把它理解为文件系统的“最小计量单位”就像你买米包装袋的规格是 1 公斤一袋所有统计数字都是按“袋”来算的。blocks文件系统总块数。bfree空闲块数。bavail非特权用户可用的块数也就是普通用户实际能用的空间。files文件系统上 inode索引节点的总数。ffree空闲的 inode 数量。favail非特权用户可用的 inode 数量。这里有个特别关键的点bfree 和 bavail 的区别。在 Linux 上文件系统默认会给 root 用户保留一部分空间通常是总容量的 5%。这部分保留空间普通用户是写不进去的但它会包含在 bfree 里。所以如果程序以普通用户身份运行真正能用的空间应该看 bavail。用 bfree 做空间判断高估了可用容量可能会导致误判。2.2 字节换算和“为什么不能用 blocks 乘以 bsize 来算已用空间”获取了这些原始数字之后我们需要把它们换算成人类能看懂的 GB 或者 TB。这是一道小学数学题但执行顺序有讲究。直接说结论总容量 blocks * bsize可用容量 bavail * bsize已用容量 (blocks - bfree) * bsize。注意已用容量用的是 blocks - bfree而不是 blocks - bavail。因为 blocks - bfree 才是文件系统视角下真正被占用的块数包含了 root 保留空间而 blocks - bavail 会把 root 保留空间也算成“已用”这样算出来的使用率会偏高 5% 左右。打个比方一间房子总共有 100 个储物格主人刻意留了 5 个格子只给自己用别人不能用。从“用了多少”的角度看那 5 个格子算不算“已被占用”不同场景答案不同但做告警监控的时候用前者更符合实际风险。写一个完整的换算工具函数function formatDiskInfo(stats) { const totalBytes Number(stats.blocks) * Number(stats.bsize); const availableBytes Number(stats.bavail) * Number(stats.bsize); const usedBytes (Number(stats.blocks) - Number(stats.bfree)) * Number(stats.bsize); return { totalBytes, availableBytes, usedBytes, usagePercent: Number(((usedBytes / totalBytes) * 100).toFixed(1)), availablePercent: Number(((availableBytes / totalBytes) * 100).toFixed(1)) }; }这里还有一个隐藏的坑如果磁盘总容量特别大blocks 乘以 bsize 的乘积可能超过 JavaScript Number 的安全整数范围。Node.js 的 fs.statfs 支持传入 { bigint: true } 选项让所有返回值变成 BigInt 类型避免大数溢出。涉及超过 2PB 的存储阵列时这一点非常关键。2.3 第三方库的底层逻辑与使用边界再回头看看 check-disk-space 这个库。它在 Windows 上执行的是 PowerShell 的 Get-PSDrive 命令来解析盘符容量在 Linux 和 macOS 上执行的是 df -Pk 命令。因为它拿到的是命令输出所以返回的单位也不一样接口文档里会明确告诉你所有字段单位是字节。它的典型用法是const checkDiskSpace require(check-disk-space); const space await checkDiskSpace(C:\\); console.log(space); // { diskPath: C:\\, free: 12345678, size: 87654321 }这里有个细节值得注意这个库返回的信息里free 字段对应的是 bavail 还是 bfree我在实际使用中发现不同版本的表现并不完全相同。因为在 Windows 上没有 root 保留空间的概念PowerShell 返回的剩余空间就是当前用户可见的剩余空间而 Linux 上 df -Pk 默认输出的“可用”列就是 bavail也就是普通用户可用。所以综合来看这个库给出的 free 更贴近“普通用户可用”的语义跟我们推荐的 bavail 口径是一致的。diskusage 库的接口更少const diskusage require(diskusage); const info await diskusage.check(/); console.log(info); // { available: 12345678, free: 12345678, total: 87654321 }它的 available 和 free 都是直接从系统 API 拿的在不同平台上的语义略有差异但总体也是“当前进程权限下可用空间”的口径。搞清楚这个边界特别重要如果你的服务是 root 身份运行的可用空间按 bfree 算也没错但以普通用户身份运行时必须按 bavail/available 算否则你在监控脚本里看到还剩 5% 空间实际上用户侧已经满了。3. 实操过程从最小实现到完整磁盘告警监控脚本3.1 环境准备与初始化开始动手之前先确认 Node.js 版本。原生 fs.statfs 在 18.15.0 和 19.2.0 中正式可用在 20.x 及之后的所有版本中都稳定可用。查看当前版本node -v如果输出的是 v18.15.0 以上或者 v20.x 以上就可以放心用原生方案。这里我建议尽量用 Node.js 20 LTS 或更高因为 LTS 版本维护周期长生产环境踩坑的概率低。然后创建一个空项目并初始化mkdir disk-monitor cd disk-monitor npm init -y如果你要用 check-disk-space 做兼容方案再执行npm install check-disk-space3.2 基于原生 API 的最小实现先写一个获取单一路径磁盘信息的函数这里我把目标路径指向项目所在的根目录// disk-info.js import fs from node:fs/promises; async function getDiskInfo(path) { try { const stats await fs.statfs(path); const totalBytes Number(stats.blocks) * Number(stats.bsize); const availableBytes Number(stats.bavail) * Number(stats.bsize); const usedBytes (Number(stats.blocks) - Number(stats.bfree)) * Number(stats.bsize); return { path, totalBytes, availableBytes, usedBytes, usagePercent: Number(((usedBytes / totalBytes) * 100).toFixed(1)) }; } catch (err) { throw new Error(获取磁盘信息失败: ${err.message}); } } const info await getDiskInfo(/); console.log(info);把这段代码跑起来你应该能看到类似这样的输出{ path: /, totalBytes: 800108482560, availableBytes: 706525589504, usedBytes: 68850606080, usagePercent: 8.6 }这个结果是 745GB 总容量、658GB 可用空间的典型 4K 块大小的 ext4 文件系统。这段最小实现有两个设计细节值得说明。第一我在错误抛出的地方重新包了一层 Error保留了原始错误信息但加上了业务上下文。这样在监控日志里看到 获取磁盘信息失败: EACCES 的时候你能很快定位到是权限问题。第二我没有直接在函数里做单位换算而是把字节数原样返回让上层调用方决定展示成 KB、MB 还是 GB。这符合“一个函数只做一件事”的原则也方便单元测试。3.3 大整数安全与 BigInt 方案前面提到过当磁盘容量特别大的时候普通 Number 会有精度问题。看一下用 BigInt 的版本// disk-info-bigint.js import fs from node:fs/promises; async function getDiskInfoSafe(path) { const stats await fs.statfs(path, { bigint: true }); const totalBytes stats.blocks * stats.bsize; const availableBytes stats.bavail * stats.bsize; const usedBytes (stats.blocks - stats.bfree) * stats.bsize; const usagePercent Number((usedBytes * 100n / totalBytes).toString()) / 100; return { path, totalBytes: totalBytes.toString(), availableBytes: availableBytes.toString(), usedBytes: usedBytes.toString(), usagePercent }; }BigInt 运算需要注意一点不能用小数所以计算百分比的时候我先把 usedBytes 乘以 100n再除以 totalBytes得到的是一个放大 100 倍的整数百分比然后转成 Number 再除以 100。这个顺序不能反否则精度就丢了。实际生产环境中单块磁盘容量一般不会超过 2PB用 Number 完全够但如果做存储集群管理、聚合多台机器的容量数据用 BigInt 更稳妥。3.4 封装跨平台工具模块原生 fs.statfs 在 Linux、macOS、Windows 上都能用Windows 上对应的是 NTFS 卷的统计信息但路径写法需要处理。Windows 的路径比较特殊用 C:\ 这样的形式时末尾的反斜杠不能少更稳妥的办法是直接用 process.cwd() 或者项目的某个固定数据目录作为参数。我封装一个更通用的模块让调用方传路径的时候不那么容易出错// disk-tool.js import fs from node:fs/promises; import path from node:path; export async function getDiskUsage(targetPath process.cwd()) { const resolvedPath path.resolve(targetPath); const stats await fs.statfs(resolvedPath); const totalBytes Number(stats.blocks) * Number(stats.bsize); const availableBytes Number(stats.bavail) * Number(stats.bsize); const usedBytes (Number(stats.blocks) - Number(stats.bfree)) * Number(stats.bsize); return { path: resolvedPath, totalBytes, availableBytes, usedBytes, usagePercent: Number(((usedBytes / totalBytes) * 100).toFixed(2)), availablePercent: Number(((availableBytes / totalBytes) * 100).toFixed(2)), inode: { total: stats.files, free: stats.ffree, usedPercent: stats.files 0 ? Number(((Number(stats.files) - Number(stats.ffree)) / Number(stats.files) * 100).toFixed(2)) : 0 } }; }这里用 path.resolve 转了一次路径目的有两个一是把 .. 这类相对路径统一成绝对路径保证 fs.statfs 拿到的路径不会因为相对路径解析产生歧义二是把 Windows 路径里常见的正斜杠/反斜杠混用问题交给 Node.js 的 path 模块处理不用自己在代码里拼字符串。注意一点fs.statfs 获取的是“目标路径所在挂载点”的信息不是“这个路径对应的文件或目录”的信息。比如你在 Linux 上调用 fs.statfs(/tmp)如果 /tmp 是根分区的子目录它返回的是根分区的统计如果 /tmp 是独立挂载的 tmpfs它返回的就是 tmpfs 的统计。这个行为跟 df 命令完全一致设计监控脚本的时候要搞清楚每个路径落在哪个挂载点上。3.5 完整案例一个磁盘告警监控脚本现在把这些函数拼起来做一个真正能用的磁盘告警监控脚本。假设我们管理一台文件服务器需要监控根分区、数据盘、日志盘三个位置任何一个可用空间低于 10% 就触发告警。// disk-monitor.js import { getDiskUsage } from ./disk-tool.js; import fs from node:fs/promises; const MOUNT_POINTS [ { path: /, name: 系统盘 }, { path: /data, name: 数据盘 }, { path: /var/log, name: 日志盘 } ]; const WARN_THRESHOLD 20; const CRITICAL_THRESHOLD 10; async function monitorDisks() { const issues []; const reports []; for (const mount of MOUNT_POINTS) { try { const info await getDiskUsage(mount.path); reports.push(formatReport(mount.name, info)); if (info.availablePercent CRITICAL_THRESHOLD) { issues.push([严重] ${mount.name}(${info.path}) 可用空间仅剩 ${info.availablePercent}%); } else if (info.availablePercent WARN_THRESHOLD) { issues.push([警告] ${mount.name}(${info.path}) 可用空间低于 ${WARN_THRESHOLD}%); } } catch (err) { issues.push([错误] 检查 ${mount.path} 失败: ${err.message}); } } console.log( 磁盘空间巡检报告 ); console.log(reports.join(\n)); console.log(); if (issues.length 0) { console.log(\n待处理告警); issues.forEach(item console.log( -, item)); // 这里可以接入钉钉、企业微信、邮件等通知渠道 // await sendAlert(issues); } else { console.log(\n所有挂载点空间正常。); } } function formatReport(name, info) { return ${name} | 路径: ${info.path} | 总量: ${formatBytes(info.totalBytes)} | 已用: ${formatBytes(info.usedBytes)} | 可用: ${formatBytes(info.availableBytes)} | 空间使用率: ${info.usagePercent}% | Inode使用率: ${info.inode.usedPercent}%; } function formatBytes(bytes) { if (bytes 1024 * 1024 * 1024 * 1024) return (bytes / 1024 / 1024 / 1024 / 1024).toFixed(2) TB; if (bytes 1024 * 1024 * 1024) return (bytes / 1024 / 1024 / 1024).toFixed(2) GB; if (bytes 1024 * 1024) return (bytes / 1024 / 1024).toFixed(2) MB; return (bytes / 1024).toFixed(2) KB; } monitorDisks().catch(err { console.error(巡检脚本执行异常:, err); process.exit(1); });这个脚本的输出大概是 磁盘空间巡检报告 系统盘 | 路径: / | 总量: 745.03 GB | 已用: 64.13 GB | 可用: 658.02 GB | 空间使用率: 8.61% | Inode使用率: 0.04% 数据盘 | 路径: /data | 总量: 3.64 TB | 已用: 2.98 TB | 可用: 660.55 GB | 空间使用率: 82.02% | Inode使用率: 0.12% 日志盘 | 路径: /var/log | 总量: 100.00 GB | 已用: 98.21 GB | 可用: 1.79 GB | 空间使用率: 98.21% | Inode使用率: 99.87% 待处理告警 - [严重] 数据盘(/data) 可用空间仅剩 17.98% - [严重] 日志盘(/var/log) 可用空间仅剩 1.79%这套监控脚本实际跑起来第二天就应该能收到日志盘的告警——日志文件增长很快如果没做 logrotate100GB 的日志分区几天就满了。脚本里的 sendAlert 函数你按自己的通知渠道补上就行我一般习惯是先用 webhook 发到团队群再配合邮件兜底。4. 常见问题与排查技巧实录4.1 Windows 路径写法的深坑在 Windows 上调用 fs.statfs第一个参数是路径。如果传 C 会直接报错必须是 C: 或 C:\。最坑的是反斜杠转义问题在字符串里写 C:\Users\data 会被当成转义字符正确写法是 C:\Users\data更推荐直接用 path.join(C:, \) 或者 path.resolve 来处理。此外Windows 的盘符映射还有一种特殊情况网络驱动器。如果你映射了一个网络共享盘到 Z 盘fs.statfs(Z:\) 返回的是远程服务器的磁盘统计信息而不是本地磁盘的。这本身没什么问题但要注意获取结果可能会受网络延迟影响调用时间会变长。在生产环境里如果监控程序要遍历多个盘符建议对网络驱动器做单独的容错处理超时或失败时降级到本地盘符检查。4.2 EACCES 权限错误与容器用户差异化我在容器环境里经常遇到一种情况容器以非 root 身份运行挂载了一个只读的卷或者对某个目录没有读取权限调用 fs.statfs 就会抛 EACCES。很多人以为 statfs 只是读元数据不需要权限但实际上操作系统对路径的父目录解析、挂载点访问都有权限校验。典型的解决思路有三个一是让容器以合适的 UID 运行确保有对应目录的读权限二是只监控有权限的路径不要试图一网打尽所有挂载点三是在调用前后判断错误码针对 EACCES 单独给出日志提示。还有一个容易被忽略的坑在 Docker 的默认配置下容器里看到的磁盘空间是容器所在宿主机对应挂载点的空间。如果你在容器里监控 /看到的是宿主机一块磁盘的空间而不是容器假定的“有限空间”。这对告警阈值的设计有直接影响。4.3 挂载点与符号链接的干扰Linux 服务器上至少会有根分区 /、swap、可能还有 /boot、/home 这几个挂载点。如果你的监控脚本写死了挂载点列表当运维同事给数据盘重新分区、调整挂载点的时候脚本就会漏掉新挂载的分区或者对着已经不存在的路径报错。更稳妥的做法是动态扫描。在 Linux 上可以读取 /proc/self/mounts 拿到当前进程可见的所有挂载点然后用 fs.statfs 逐个检查。这是我后来在项目中调整过的方案效果很好import fs from node:fs/promises; async function listMountPoints() { const mounts await fs.readFile(/proc/self/mounts, utf8); return mounts .split(\n) .filter(line { // 过滤掉伪文件系统和重复挂载点 if (!line) return false; const parts line.split( ); const fsType parts[2]; const mountPoint parts[1]; if (fsType.startsWith(proc) || fsType.startsWith(sysfs) || fsType.startsWith(cgroup)) return false; return mountPoint.startsWith(/); }) .map(line line.split( )[1]); }符号链接的坑也要单独说fs.statfs 会跟随符号链接解析到目标路径的挂载点。比如 /var 是 /data 的符号链接你调用 fs.statfs(/var) 拿到的其实是 /data 所在磁盘的空间。这在大多数情况下是符合预期的但如果你误以为拿了根分区的空间可能会导致监控数据错位。调试时建议打印一下 path 的 resolve 结果确认实际解析到哪个路径。4.4 inode 耗尽但磁盘还有空间这个坑在文件数量特别多的服务上非常常见。inode 是文件系统用来存储文件元数据权限、所有者、文件大小、数据块指针等的索引节点每个文件或目录都要占一个 inode。如果一个分区 inode 用完了即使磁盘还有大量空闲空间你也创建不了任何新文件。所以在监控磁盘空间时inode 使用率同样不能忽视。fs.statfs 返回的 files、ffree、favail 三个字段就是为这个准备的。我在前面的 disk-tool.js 里已经把 inode 信息一起返回了格式报告里也有这一项。这里再提醒一个细节inode 用尽后最典型的症状是“No space left on device”错误但 df -h 显示剩余空间还很大。如果你遇到这个诡异现象先用 df -i 看一下 inode 使用率八成就是它。4.5 大文件系统与单位转换偏差前文提到 BigInt 的问题实际操作中我见过有人用 Number 去乘 stats.blocks 和 stats.bsize在大容量存储上算出来一个负数或者奇怪的小数。这是因为乘积超过了 2^53。除了用 BigInt还有一个小技巧先判断 blocks 是否小于 safeCapacity 再决定是否用 BigInt 分支。但更简单的做法是一律用 BigInt反正性能影响微乎其微。展示层还有一个常见的转换错误把字节数转 GB 时直接除以 1000^3跟除以 1024^3 的结果差了差不多 7%。SSD 厂商实验室标称 240GB操作系统显示 223GB根源就是十进制和二进制换算的差异。代码里要统一口径我一般默认按照 1024 换算但在界面显示上标注清楚避免用户拿磁盘标称容量跟系统报告对不上时产生困惑。5. 生产环境落地定时巡检、阈值设计与联动运维5.1 定时任务别只用 setInterval很多人写定时任务第一反应是 setInterval但在生产环境里这不是最优解。setInterval 没有处理任务执行时长超过间隔的问题——如果一次磁盘巡检因为网络文件系统超时卡了 30 秒而间隔设置的是 60 秒第二次巡检并不会跳过可能导致任务堆积。推荐做法是用“递归 setTimeout”的方式。每次执行完巡检逻辑之后再设置下一次执行时间。这样哪怕某次执行时间超长也不会有两个巡检任务同时跑。function scheduleMonitor(intervalMs 5 * 60 * 1000) { const run async () { try { await monitorDisks(); } catch (err) { console.error(巡检运行异常稍后继续调度:, err.message); } finally { setTimeout(run, intervalMs); } }; setTimeout(run, intervalMs); } scheduleMonitor();作为后台常驻服务外面一般再用 systemd 或者 pm2 包一层保证进程挂了能自动拉起。如果不想常驻服务也可以用 crontab 配合 node 脚本定时执行简单粗暴但每次启动进程都有额外开销看你的实际需求。5.2 告警阈值设定双阈值加去抖磁盘空间告警最大的痛点是抖动。想象一下监控脚本每 5 分钟跑一次日志文件一小时内从 20% 涨到 85%告警触发了一次。但因为清理任务马上又把空间释放了下一次巡检掉回 15%告警恢复。这种反复告警又恢复的过程非常烦人容易造成告警疲劳。我的做法是设两个阈值警告阈值 20%严重阈值 10%并且加一个“持续时间”条件——只有连续 3 次巡检都低于阈值才发送告警。这个去抖逻辑很好实现用三个布尔的“窗口”记录最近三次状态只有连续三次命中才通知。还要加一个恢复通知从告警状态回到正常状态时发一条“已恢复”的消息事件闭环运维人员就不需要反复确认。5.3 与日志清理、文件分发的联动获取磁盘空间信息的价值在与其他系统联动时才能发挥到最大。我们之前做的一个文件服务会把生成的文件先写到本地磁盘然后再上传对象存储。在写盘之前我加了一个空间预检逻辑// 写文件前检查 const DISK_RESERVE_BYTES 500 * 1024 * 1024; // 保留 500MB 安全余量 async function checkWritableSpace(targetDir, fileSize) { const info await getDiskUsage(targetDir); if (info.availableBytes fileSize DISK_RESERVE_BYTES) { throw new Error(磁盘剩余空间不足当前可用 ${info.availableBytes} 字节需要 ${fileSize DISK_RESERVE_BYTES} 字节); } }这里的 DISK_RESERVE_BYTES 是安全余量目的是防止业务并发情况下多请求同时通过检查但空间被写满的情况。加上一个简单的互斥措施或者在检查通过后立刻占位能更稳。这类联动逻辑没有标准答案大家根据自己的业务特点来设计。我个人在实际操作中的体会是磁盘空间检查这个功能难点从来不是“会写那几行 API”而是你对操作系统、文件系统、部署环境有没有足够的理解。把这些边界情况都摸透了遇到生产事故的时候才能不慌。最后再分享一个小技巧把巡检脚本跑起来之后自己人为地把磁盘写满测试一次观察告警是否能正确触发、通知渠道是否通畅。这个测试看着折腾但能省下以后半夜被叫起来处理磁盘告警的大把时间。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑