应读 /proc/stat 计算 CPU 使用率、/proc/meminfo 获取系统内存,容器需用 cgroup 接口;避免直接使用 runtime.NumCPU() 和 ReadMemStats() 代替系统指标。

别用 runtime.NumCPU() 和 runtime.ReadMemStats() 直接当系统 CPU 百分比和总内存用——它们返回的是进程调度能力与堆快照,不是系统资源水位。
怎么读 Linux 系统 CPU 使用率(不依赖第三方库)
Go 标准库不提供“CPU 占用率”这个值,必须靠两次采样 /proc/stat 计算差值。它第一行是累计的 jiffies(用户态、内核态、空闲等),除以总时间再归一化就能得到近似百分比。
- 每次读取后需解析
"cpu 12345 678 901 23456 ..."这一行,提取前 4 个数字(user,nice,system,idle) - 两次采样间隔建议 ≥500ms,太短会导致抖动;计算公式为:
(totalDelta - idleDelta) / totalDelta * 100.0 - 注意:单次采样无意义;若在容器中运行,该值反映的是宿主机整体负载,不是容器实际占用
- 要获取容器真实 CPU 使用率,应读
/sys/fs/cgroup/cpu/cpu.stat(cgroup v2)或/sys/fs/cgroup/cpuacct/cpuacct.usage(v1),再结合cpu.cfs_quota_us和cpu.cfs_period_us判断是否被限频
怎么查系统总内存和可用内存(Linux)
runtime.ReadMemStats() 返回的 MemStats.Sys 是 Go 进程向 OS 申请的虚拟内存总量,和 /proc/meminfo 中的 MemTotal: 完全无关。
- 直接读
/proc/meminfo,逐行匹配"MemTotal:"和"MemAvailable:"(优先用后者,Linux 3.14+ 内核才支持,比MemFree更准确) - 字段单位是
kB,不是 KB 或 bytes,解析后需乘以 1024 才是字节数 - 别用正则跨行匹配,
strings.Fields(line)[1]更安全;跳过空行和注释行 - 容器环境里,
MemAvailable仍反映宿主机状态;若需容器内存上限,应读/sys/fs/cgroup/memory.max(v2)或/sys/fs/cgroup/memory/memory.limit_in_bytes(v1)
为什么 gopsutil/v3 是生产首选
手动读 /proc 文件虽轻量,但跨平台时 macOS 和 Windows 需完全重写逻辑,且容易漏掉权限、路径不存在、字段变更等边界问题。
立即学习“go语言免费学习笔记(深入)”;
-
github.com/shirou/gopsutil/v3/cpu.Percent(0, false)返回最近 1 秒的 CPU 使用率,内部已处理 cgroup 限制、多核归一化、采样防抖 -
github.com/shirou/gopsutil/v3/mem.VirtualMemory()统一封装了 Linux/proc/meminfo、macOSsysctl hw.memsize、WindowsGlobalMemoryStatusEx,返回结构体含Total、Available、UsedPercent - Windows 下需额外
go get github.com/stackexchange/wmi,且必须启用 CGO(CGO_ENABLED=1) - 它不依赖 fork/exec,性能可控;但别在 HTTP handler 里直接调用——应起独立 goroutine 定期采集并缓存结果
容易被忽略的三个硬伤
就算你用对了 API,下面三点不注意,监控数据照样失真:
-
runtime.ReadMemStats()会触发 STW,高频调用(如每 100ms)会让 GC 停顿明显增加;生产环境最低建议 1s 间隔 - Linux
/proc/stat的 jiffies 值受系统HZ影响,不同内核版本默认值可能为 100 或 250,不能硬编码换算系数 - 容器中
runtime.NumCPU()仍返回宿主机逻辑核数,和docker run --cpus=2无关;真正影响并发的是runtime.GOMAXPROCS(),而它可被环境变量覆盖


















