最可靠的方式是使用 github.com/shirou/gopsutil/v3/disk 的 disk.Usage(),它自动过滤伪文件系统、统一返回字节数与百分比,避免 os.Statfs 手动计算误差及 df 解析脆弱性。

用 gopsutil/disk 获取磁盘使用率最可靠
Go 原生 os.Statfs 虽能拿到基础空间信息,但不直接提供百分比、易受挂载点嵌套干扰,且需手动处理单位换算和边界情况。生产环境推荐用 gopsutil/disk —— 它封装了 /proc/mounts 和 statfs,自动过滤伪文件系统(如 tmpfs、devtmpfs),并统一返回 uint64 字节数与 float64 百分比。
安装:
go get github.com/shirou/gopsutil/v3/disk
关键点:
-
disk.Usage(“/”)返回根分区信息;传入具体路径(如"/home")可查子挂载点,不是设备名(别传"/dev/sda1") - 结果中
UsedPercent是已用百分比(含保留空间),Free是用户可用字节数(不含 root 保留的 5%),Total和Used是原始统计值 - 若需查所有挂载点,用
disk.Partitions(true)先获取列表,再对每个Mountpoint调用Usage
避免 df -h 解析这种脆弱方式
有人会想用 exec.Command("df", "-P", "/") 拿 shell 输出再 parse,这在 Linux 上看似简单,但实际问题很多:
- 不同发行版
df输出格式可能微调(如列顺序、空格数),-P虽保证 POSIX 格式,但字段对齐仍依赖空格,易被长路径或 i18n 破坏 - 无法区分 bind mount 和真实物理分区,
df只显示挂载点层级,不反映底层设备拓扑 - 权限问题:容器内或受限环境可能禁用
exec,或df不在$PATH - 性能开销:每次调用都要 fork 新进程,比纯 Go 调用
statfs慢一个数量级
disk.Usage 的常见误用与修复
错误现象:调用 disk.Usage("/nonexistent") 返回 nil + "no such file or directory" 错误,但没检查 err 就直接访问字段,导致 panic。
正确做法:
usage, err := disk.Usage("/")
if err != nil {
log.Printf("failed to get disk usage: %v", err)
return
}
log.Printf("used: %.1f%%, free: %d bytes", usage.UsedPercent, usage.Free)
其他注意点:
- 路径必须是已挂载的目录,不能是符号链接终点(
disk.Usage内部用filepath.EvalSymlinks,但最好传规范路径) - 在容器中运行时,若挂载了
hostPath,要确保该路径在容器内真实存在且可访问,否则返回syscall.ENOENT -
UsedPercent可能 >100(如启用了配额或 ext4 的 reserved blocks 被占满),这时需结合usage.InodesUsedPercent判断是否 inode 耗尽
需要精确到设备(如 /dev/sda)时怎么办
gopsutil/disk 默认按挂载点工作,不暴露设备名映射。如果真要关联设备,得组合使用:
- 先用
disk.Partitions(false)获取所有分区(false表示不过滤伪文件系统),它返回的PartitionStat包含Device(如"/dev/sda1")和Mountpoint - 再对每个
Mountpoint调用disk.Usage,最后按需合并或筛选 - 注意:同一设备可能有多个挂载点(如
/和/boot分属不同分区),不能假设 1:1
这个逻辑稍重,多数监控场景只需关注挂载点容量,而非底层设备健康——后者更适合用 smartctl 或 nvme-cli 单独采集。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











