node_exporter:把主机硬件与内核指标一次性喂给 Prometheus 的采集实战
【免费下载链接】node_exporterExporter for machine metrics项目地址: https://gitcode.com/GitHub_Trending/no/node_exporter
痛点从"指标散落"说起
在 Linux 主机监控里,内核把运行状态写在 /proc 与 /sys 的数百个文件里,格式各异,且多数是累计值:想拿到磁盘每秒读写字节,得自己做两次读数的差值再除以间隔。手写采集脚本很难同时应付格式差异、差值计算、错误隔离和跨平台移植,结果往往是监控体系缺胳膊少腿。node_exporter 是 Prometheus 生态的主机指标采集器,用一个可插拔的采集器框架(Collector)把这件事整体接过去:一个二进制覆盖 Linux、FreeBSD、macOS、DragonFly、NetBSD、OpenBSD、Solaris 等系统,内置 50 多个开箱即用的采集器,单实例内存占用典型只有几十 MB,Prometheus 拉一次 /metrics 就能拿全这台机器的主机指标。
一个"巡检酒店"的类比,看懂 Collector 并行调度框架
把内核想象成一间酒店:CPU、内存、磁盘、网络各在自己的房间小黑板上持续写状态。node_exporter 是值班经理,每个采集器是负责一块黑板的巡检员——某块板字迹潦草读不出来,不影响其他房间照常上报。一次抓取的完整流程如下:
- Prometheus 向默认 9100 端口的 /metrics 发起 HTTP GET;
node_exporter.go中的handler.ServeHTTP判断 URL 是否带collect[]或exclude[]参数;无参数时直接走启动时就构建好的无过滤 handler,零额外分配;collector/collector.go的NodeCollector.Collect把每个启用的采集器放进独立 goroutine 并行执行,sync.WaitGroup等待全部结束;- 每个采集器执行完都会自报两份"体检指标":
node_scrape_collector_duration_seconds(耗时)与node_scrape_collector_success(成败)。
为什么并行而不是串行
框架采用全量并发加单点容错:一个挂载点卡死或某个内核文件缺行,只影响对应采集器自己的指标族,其余指标照常输出。单次抓取的整体耗时约等于最慢的那一个采集器,而不是所有采集器之和。
请求级过滤:一个端口服务多种用途
带过滤参数的请求会临时构建只包含指定采集器的 handler。这样不同的 Prometheus 实例可以从同一台机器拉不同指标子集,比如节点大盘只要 cpu 和 meminfo,而网络专项只抓 netdev。
采集器实例只建一次
NewNodeCollector用全局缓存保存已创建的采集器,后续抓取直接复用,避免重复初始化;配合--collector.disable-defaults还能先全关再按需开。
源码走读:Collect 并发骨架与 CPU 计数器回跳保护
先看调度骨架,collector/collector.go:
// NodeCollector implements the prometheus.Collector interface. func (n NodeCollector) Collect(ch chan<- prometheus.Metric) { wg := sync.WaitGroup{} wg.Add(len(n.Collectors)) for name, c := range n.Collectors { go func(name string, c Collector) { execute(name, c, ch, n.logger) // 单采集器执行+自监控 wg.Done() }(name, c) } wg.Wait() }execute内部对每次Update计时,出错只写日志并把scrape_success置 0,绝不让单个采集器的 panic 路径拖垮整次 scrape。这个结构意味着 50 个采集器和 2 个采集器在代码层面是同一个故事,差异只在数量。
再看一个隐蔽的坑处理。collector/cpu_linux.go中缓存着上一次/proc/stat的快照:
// cpuStats 缓存上一次的 CPUStat,用于计算差值 cpuStats map[int64]procfs.CPUStat // 空闲计数器回跳超过 3 秒,判定为热插拔,重置而非输出负值 const jumpBackSeconds = 3.0内核的 idle 计数器在 CPU 热插拔时可能"回跳",若不做判断,差值法会产出负的时间增量,直接污染所有基于rate()的仪表盘。这里的工程取舍是:回跳幅度超过 3 秒即认定拓扑已变,丢弃旧快照重新起算,宁可丢一个区间也不出错误数据。
量化层面:单指标族读 /proc 与 /sys 的开销在毫秒量级;50 个采集器并发后,典型部署下单次 /metrics 抓取常在 100 毫秒以内完成,远低于 Prometheus 默认的 10 秒抓取超时,即使叠加 ethtool、tcpstat 这类重采集器也很少触发超时告警。
效果实证:filesystem 容错设计与端到端快照回放
collector/filesystem_linux.go展示了"内核状态不可靠时 exporter 如何保命"。两个关键旋钮:
var mountTimeout = kingpin.Flag("collector.filesystem.mount-timeout", "how long to wait for a mount to respond before marking it as stale"). Hidden().Default("5s").Duration() var statWorkerCount = kingpin.Flag("collector.filesystem.stat-workers", "how many stat calls to process simultaneously"). Hidden().Default("4").Int()statWorkerCount让 statfs 系统调用以 4 个 worker 的池化方式并行执行,挂载点多时不再串行等待;mountTimeout则为每个挂载点配了一个 5 秒看门狗——NFS 挂载挂死后 statfs 会长时间阻塞,一旦超时该挂载点被打入 stuck 名单,后续抓取直接产出device_error="mountpoint timeout"而不是把整次 scrape 拖垮,恢复后自动摘牌并记录日志。
仓库自带的端到端测试则验证了解析正确性:collector/fixtures/下保存了真实的 /proc 快照,collector/fixtures/e2e-output.txt是全部采集器对这些快照的期望输出基线,共约 5500 行指标。修改任何解析逻辑跑一次end-to-end-test.sh,输出 diff 立刻可见,这也是跨版本升级时行为是否兼容的判据。采集器框架自身产出的node_scrape_collector_duration_seconds与node_scrape_collector_success两份自监控指标,则用于回答"新开的采集器有没有超时""指标基数涨了没"这两个上线前必问的问题。
参数实验室:五个最常调的开关与一个高基数场景
| 参数 | 默认值 | 推荐区间 | 可观测效果 |
|---|---|---|---|
| --web.max-requests | 40 | 0(不限)至几十 | 并发抓取上限,超限请求直接排队或拒绝 |
| --collector.disable-defaults | false | 按需 | 全关采集器再逐个开启,用于压基数 |
| --path.rootfs | / | 容器内设为 /host | 容器化部署下读取宿主机的挂载与指标 |
| --collector.filesystem.mount-points-exclude | 正则排除 proc/dev 等 | 按环境追加容器存储路径 | 对应指标族行数减少,噪音挂载点消失 |
| --collector.cpu.info.flags-include | 未设置 | 正则如 avx2|sse4_2 | cpu_info 指标只保留列出的 flags 标签 |
串联一个实践场景:某集群节点开了 textfile 采集器后,cpu_info的 flags 标签把时间序列从数万推到数十万,Grafana 查询变慢。处理顺序是先--collector.disable-defaults加白名单把基数压下来,再用flags-include正则只保留 avx2、sse4_2 等业务真正关心的标签;同时给mount-points-exclude追加/var/lib/docker/.*一类的容器路径。调整后scrape_samples_post_metric_relabeling指标回落,抓取时长基本不变。
横向对比:与自研脚本、通用 Agent 的取舍
| 维度 | node_exporter | 自研 shell 脚本 | 功能重叠的通用监控 Agent |
|---|---|---|---|
| 操作系统覆盖 | Linux/FreeBSD/macOS/Solaris 等 6 类 | 通常单台 Linux 绑定 | 依产品而定,常不含 BSD 系 |
| 内置采集器 | 50+,含 zfs、ethtool、perf | 0,逐项手写 | 视商业产品功能而定 |
| 差值与容错逻辑 | 内置(热插拔重置、卡死挂载隔离) | 需自行维护 | 黑盒,不可定制 |
| 资源占用 | 典型值数十 MB | 依赖脚本 | 典型值数百 MB 起 |
| 请求级过滤 | 原生 collect[]/exclude[] | 需另写接口 | 多数不支持 |
node_exporter 最适合与 Prometheus 搭配的 *NIX 主机层监控;边界同样明确:Windows 需换 windows_exporter,GPU 指标不归它管(用 DCGM exporter 之类),tcpstat 采集器在高连接数下性能受限,README 也建议按需开启并观察抓取时长。
演进路线:存储栈采集器在持续加深
从 CHANGELOG 的近期版本(1.12.x / 1.11.x)能看到三条清晰的演进线。一是存储栈采集器持续加深:新增 nvmesubsystem(NVMe over Fabrics 路径健康)与 dmmultipath(设备映射多路径)采集器,edac 补上 per-channel DIMM 错误标签,覆盖更完整的硬件故障诊断链路。二是部署与接入面收敛:distroless 容器镜像进入主线,TLS 端点(web.config.file)从实验走向可用,降低裸金属暴露面的成本。三是文件系统诊断增强:ext4 超级块 emergency_ro 只读检测落地,让磁盘故障在写坏数据前就能通过ro指标被观测到。当"指标散落在数百个内核文件里"成为过去时,剩下的工作只是把这些采集器按环境开关好,并盯住scrape_duration_seconds这一条自监控曲线。
【免费下载链接】node_exporterExporter for machine metrics项目地址: https://gitcode.com/GitHub_Trending/no/node_exporter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考