title: node_exporter 指标缺失排查:6 大症状决策树 + 4 个常见翻车原因
description: node_exporter 指标缺失系统性排查:node_filesystem、node_cpu、node_memory、node_network、node_diskio、node_netstat 六大指标块的常见缺失原因,collector 黑名单与权限问题,systemd override 陷阱,6 步决策树 + Cheat Sheet + 5 个真实生产翻车案例。
tags: [prometheus, node_exporter, monitoring, collectors, linux, kube-state-metrics]
lang: zh
date: 2026-10-24
answer: |
node_exporter 指标缺失先从 collector 层面查:curl http://localhost:9100/metrics | grep "^# HELP" 看哪些 collector 生效,/probe 页面能看到每个 collector 的错误。
常见缺失原因 4 类:① collector 被 --collector.xxx 黑名单(如 system 用户跑时 collector.filesystem 可能报错)② 权限不足(node_diskio 需要 root 读 /proc/diskstats)③ 内核不支持某些 /proc 文件(老内核)④ systemd override 或 K8s ServiceMonitor 的 scrape interval 太短导致采样丢失。
faq:
- q: node_exporter 的 /metrics 里看不到某个指标怎么排查?
a: 三步走:① 访问 http://localhost:9100/probe 看每个 collector 的 Last error ② 启动参数看 --collector.xxx.enabled=false 有没有禁掉 ③ 看容器/systemd 日志有没有权限报错。90% 是 collector 报错被静默吞了,/probe 页面能看到。
- q: node_filesystem 只显示了部分挂载点?
a: node_exporter 默认有 blacklist,会跳过 /boot/efi、tmpfs、proc、sysfs 等。自定义用 --collector.filesystem.mount-points-exclude 和 --collector.filesystem.fs-types-exclude。另外 systemd 挂载的 automount 有时抓不到,可以 --collector.filesystem.mount-points-include '.*' 放宽。
- q: node_diskio 没数据是什么情况?
a: 两个原因:① collector.diskstats 需要读 /proc/diskstats 和 /sys/block/*,容器没给 --privileged 或没挂载 /proc/diskstats:ro 会拿不到 ② 某些虚拟磁盘(如 LVM thin)内核不给完整统计。用 ls /sys/block/ 确认内核识别到磁盘,cat /proc/diskstats 确认有数据。
- q: node_exporter 部署到 K8s 上指标缺失怎么办?
a: 常见坑:① DaemonSet 的 hostNetwork: true 和 hostPID: true 必须开,否则拿不到节点真实指标 ② hostPath 挂载 /proc、/sys、/(read-only) ③ ServiceMonitor 的 interval 不能小于 30s,否则可能采样丢失 ④ NodePort 端口默认 9100,检查 Service 是否暴露。
node_exporter 指标缺失排查:6 大症状决策树 + 4 个常见翻车原因
Prometheus 生态里最稳定也最容易坑人的组件就是 node_exporter——它跑得比 Prometheus 本身还久,但指标突然少了是最难排查的一类问题。写这篇时我复盘了从裸金属到 K8s 集群踩过的 6 个坑,从 collector 报错到 systemd override,都是生产真实翻车场景。
node_exporter 的哲学是"从 /proc /sys 抓数据暴露成 Prometheus 格式"。所以指标缺失几乎一定来自两条线:collector 层面拿不到数据,或者 抓取层面根本没抓到这里。这条线一旦想通,6 个症状就能对应到决策树。
1. node_exporter 的组件结构
先看清楚 node_exporter 内部长什么样,才好定位缺失点。
node_exporter (单进程)
├── Collector 组(每组暴露一批指标)
│ ├── textfile — 从 /var/lib/node_exporter/textfile_collector/ 读 .prom 文件
│ ├── cpu — CPU 使用率、上下文切换、中断
│ ├── meminfo — 内存(对应 /proc/meminfo)
│ ├── filesystem — 挂载点容量(对应 /proc/self/mounts)
│ ├── diskstats — 磁盘 I/O(对应 /proc/diskstats)
│ ├── netdev — 网络接口(对应 /proc/net/dev)
│ ├── netstat — TCP/UDP 连接状态(对应 /proc/net/netstat)
│ ├── ntp — NTP 偏移
│ ├── time — 系统时间
│ ├── uname — 内核版本
│ ├── loadavg — 平均负载
│ ├── processes — 进程数、fork 失败
│ ├── socketstat — socket 状态
│ ├── hwmon — 硬件传感器(温度、风扇)
│ ├── systemd — systemd unit 状态(需要 D-Bus)
│ └── ...(完整列表 /metrics 或 /probe 看)
└── HTTP Server (:9100/metrics)
├── Prometheus scrape
├── /probe(诊断页)
└── /metrics(数据端点)
核心原则:每个 collector 独立开关,一个 collector 挂了不影响其他。看日志时按 collector 名字分。
2. 六大指标块的常见缺失原因
2.1 node_filesystem:挂载点看不到
症状:node_filesystem_size_bytes 只显示 /,看不到 /data、/home 等挂载点。
排查路径:
# 1. 看本机实际挂载
cat /proc/self/mounts | grep -v proc
mount | grep -v proc
# 2. 看 node_exporter 启动参数
ps aux | grep node_exporter
# 关注 --collector.filesystem.mount-points-exclude
# 关注 --collector.filesystem.fs-types-exclude
# 3. 直接调 textfile_collector 看文件系统原始数据
curl http://localhost:9100/metrics | grep node_filesystem
# 4. 看 collector 报错
curl http://localhost:9100/probe | grep -i filesystem
常见原因:
-
fs-types-exclude 太宽:默认排除
autofs,binfmt_misc,bpf,cgroup,configfs,debugfs,devpts,devtmpfs,fusectl,hugetlbfs,iso9660,mqueue,nfsd,overlay,proc,procfs,pstore,rpc_pipefs,securityfs,sfs,sysfs,tracefs。如果你的数据盘是 overlay(Docker 场景)或 fuse(备份软件常见),会被过滤。 -
mount-points-exclude 正则太贪:默认
'^(proc|sysfs|efivarfs|devpts|devtmpfs|none|auto|on|usr\.\.)$',正则写得不好会误杀业务挂载点。 -
权限不足:文件系统指标不需要 root,但 Docker 容器默认看不到宿主机的 mount,需要
hostPath挂载/proc。
修法:
# 只保留真实业务挂载点
--collector.filesystem.mount-points-include '^(?!/proc|/sys|/dev|/run).*'
# 或者精确到设备
--collector.filesystem.devices-include '^(sda|nvme0n1|vda)'
# 排除 fstype
--collector.filesystem.fs-types-exclude '^(sysfs|proc|autofs|binfmt_misc|overlay)$'
2.2 node_cpu:字段不完整
症状:只看到 node_cpu_seconds_total{mode="user"} 但看不到 idle, iowait, steal 等 mode。
排查:
原因:node_cpu_seconds_total 的 mode 标签由 /proc/stat 里的字段决定,内核版本决定 mode 有哪些。x86_64 完整字段是 user nice system idle iowait irq softirq steal guest guest_nice,老内核或某些 ARM 架构可能没有 steal 或 guest_nice。
修法:这不是 bug,是内核差异。PromQL 里写:
2.3 node_memory:MemAvailable 突然消失
症状:Prometheus 报警 "MemAvailable is empty",但 node_exporter 还在跑。
排查:
grep MemAvailable /proc/meminfo # 本机有没有
curl http://localhost:9100/metrics | grep MemAvailable
# 关注 node_memory_MemAvailable_bytes 标签是不是丢了
原因:
- **老内核(<3.14)**没有 MemAvailable,Prometheus 报警规则里硬编码了这个字段就报警
- container 场景里 cgroup 挂载点没 /proc/meminfo(除非 hostPID: true)
- collector.meminfo 被禁:--collector.meminfo.enabled=false
修法:
# 检查内核
uname -r
# 3.13 及以下没有 MemAvailable,用 `MemFree + Buffers + Cached` 组合计算
# 报警规则改成 fallback
node_memory_MemAvailable_bytes > 0 OR
(sum(node_memory_MemFree_bytes) +
sum(node_memory_Buffers_bytes) +
sum(node_memory_Cached_bytes)) > 0
2.4 node_network:网卡抓不到
症状:node_network_receive_bytes_total 只有 eth0,看不到 lo, veth*, docker0, br-* 等虚拟网卡。
原因:
- collector.netdev 的 device-exclude 默认是 ^(veth|docker|br|virbr|lxdbr|wwn|cni|cali).*,K8s 场景下几乎所有 CNI 网卡都被过滤
- systemd-networkd 动态创建的网卡有命名规范,正则不好写
修法:
# 保留 veth(K8s pod 网络诊断必需)
--collector.netdev.device-include '^(eth|ens|enp|cali|flannel|veth|cni|lo)'
--collector.netdev.device-exclude '' # 清空排除列表
# 或者反过来:只保留物理网卡
--collector.netdev.device-include '^(eth|ens|enp)'
2.5 node_diskio:磁盘 I/O 数据为空
症状:node_disk_read_bytes_total 完全没数据,或者只有个别磁盘。
排查:
# 1. 看内核识别到哪些磁盘
ls /sys/block/
cat /proc/diskstats | awk '{print $3}'
# 2. 看 node_exporter 有没有权限
sudo -u node-exporter cat /proc/diskstats
# 3. 看 collector 报错
curl http://localhost:9100/probe | grep -A2 diskstats
常见原因:
1. collector.diskstats 默认 exclude:^(dm-|loop|zram|ram),LVM thin pool 或 loop 设备被过滤
2. 容器没挂载 /sys/block:/proc/diskstats 里有数据但 /sys/block/<dev>/ 拿不到 stat 字段
3. 内核模块未加载:某些 NVMe 或 RAID 控制器驱动没加载
修法:
# 保留所有真实设备
--collector.diskstats.devices-include '^(sd|hd|nvme|vd|xvd|dm-|loop)'
# Docker 场景必须挂载
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
args:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --collector.diskstats
2.6 node_netstat:TCP 状态字段缺失
症状:node_netstat_Tcp_CurrEstab 有,但 node_netstat_Tcp_RetransSegs 或 node_netstat_Udp_InErrors 没有。
原因:/proc/net/netstat 是内核态 TCP/UDP 计数的原始数据,字段随内核版本变化。有些字段在内核 5.x 之前不存在(如 Tcp_RetransFail)。
排查:
修法:PromQL 报警规则用 OR 兜底:
3. 六步决策树:从"指标没了"到定位
任何"某个指标突然消失"的问题,按这 6 步走,10 分钟内定位。
[指标消失]
↓
[1] Prometheus Target 状态是 UP 吗?
├─ NO → 抓取层面问题,看下一段
└─ YES ↓
[2] 本机 curl http://localhost:9100/metrics 能看到指标吗?
├─ NO → node_exporter 内部问题,走 [3]-[6]
└─ YES ↓
[3] Prometheus 配置里的 interval/timeout 合理吗?
├─ NO → 调整 scrape_interval(<30s 会丢包)
└─ YES ↓
[4] Prometheus 侧有没有 remote_write 或者 relabel 过滤?
├─ YES → 检查 relabel_configs 有没有丢 metric
└─ NO → 报警规则本身问题
[5] Collector 层面:/probe 页面 Last error 列有没有报错?
├─ YES → 修 collector 配置或权限
└─ NO ↓
[6] Collector 是不是被 --collector.xxx 显式禁用?
├─ YES → 加回来
└─ NO → 内核/文件系统层面问题(老内核、权限、cgroup)
4. Cheat Sheet:常用命令速查
# === 端点诊断 ===
curl http://localhost:9100/metrics | grep "^# HELP" # 所有指标列表
curl http://localhost:9100/metrics | grep "^# HELP node_filesystem"
curl http://localhost:9100/probe | less # 每个 collector 的错误
curl http://localhost:9100/metrics?show_hidden=1 # 隐藏指标
# === Collector 状态 ===
systemctl status node_exporter
journalctl -u node_exporter -n 100 -f
node_exporter --version
ps aux | grep node_exporter | awk '{print $0}' # 看启动参数
# === Collector 配置 ===
# 查看默认启用/禁用
node_exporter --help | grep -E 'collector\.' | head -50
# 常用命令(systemd)
systemctl edit node_exporter
# [Service]
# ExecStart=
# ExecStart=/usr/bin/node_exporter \
# --collector.filesystem.mount-points-include '^(?!/proc|/sys).*' \
# --collector.netdev.device-include '^(eth|ens|cali|veth)' \
# --no-collector.systemd
# 重载
systemctl daemon-reload && systemctl restart node_exporter
# === K8s DaemonSet 检查 ===
kubectl get ds -A | grep node-exporter
kubectl describe ds node-exporter -n monitoring
kubectl logs -n monitoring ds/node-exporter --tail=100
kubectl port-forward -n monitoring ds/node-exporter 9100:9100
# === Prometheus 侧 ===
curl http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | select(.scrapeUrl|contains("9100"))'
curl http://localhost:9090/api/v1/label/__name__/values | jq '.data[]' | grep node_
5. 五个真实生产翻车案例
案例 1:systemd 服务启动参数被覆盖
现象:改了 node_exporter 启动参数(加了 collector 白名单),重启后指标还是老的。
根因:systemd drop-in 覆盖了主 config。
# 查看最终生效的 ExecStart
systemctl cat node_exporter
# 会列出所有 [Service] 配置来源,drop-in 在 /etc/systemd/system/node_exporter.service.d/*.conf
# 排查:drop-in 里的 ExecStart= 会覆盖主文件,即使没有 = 也会触发
grep -r ExecStart /etc/systemd/system/node_exporter.service.d/
修法:要么清空 drop-in 的 ExecStart=(不加 =),要么用 ExecStart= 覆盖完整命令(必须带 =)。
案例 2:K8s ServiceMonitor 端口名不匹配
现象:Prometheus Operator 里 ServiceMonitor 配好了,但目标一直是 DOWN。
根因:port 字段写死了 9100,但 Service 定义的 port name 是 metrics。
# WRONG
ports:
- port: 9100
scheme: http
# RIGHT
ports:
- name: metrics
scheme: http
targetPort: 9100
修法:Prometheus Operator 用 name 匹配 K8s Service 的 port name,不是数字端口。
案例 3:Prometheus scrape_interval 太短丢包
现象:Prometheus 里指标时有时无,重启 node_exporter 后短暂恢复。
根因:scrape_interval=10s,但 node_exporter 的 collector 采集耗时超过 10s(尤其是文件系统多、磁盘 I/O 高的机器),后续请求会互相覆盖。
修法:Prometheus 全局 scrape_interval 拉到 30s+,个别慢 target 用 job-level 覆盖:
案例 4:nft 表覆盖 iptables 规则
现象:加了防火墙规则后 Prometheus 抓不到 node_exporter。
根因:CentOS 8+ 默认 nft,但 iptables 命令还在(走 nft 兼容层)。老脚本用 iptables -A INPUT -p tcp --dport 9100 -j ACCEPT 加的规则在 nft 层面没生效。
# 用 iptables 看
iptables -L INPUT -n | grep 9100
# 实际内核里 nft 的规则
nft list ruleset | grep 9100
# 空的说明 iptables 命令没真正写进 nft
修法:直接用 nft:
nft add rule ip filter INPUT tcp dport 9100 accept
nft add rule ip filter FORWARD tcp dport 9100 accept
案例 5:textfile_collector 权限错误
现象:加了自定义 collector(textfile_collector),日志里刷 open /var/lib/node_exporter/textfile_collector/foo.prom: permission denied。
根因:node_exporter 跑 non-root(systemd 默认 node-exporter 用户),textfile_collector 目录权限不对。
ls -ld /var/lib/node_exporter/textfile_collector/
chown node-exporter:node-exporter /var/lib/node_exporter/textfile_collector/
chmod 755 /var/lib/node_exporter/textfile_collector/
修法:textfile_collector 目录归 node-exporter 用户,写入方(cron 或 systemd timer)用 runuser -u node-exporter。
6. FAQ
Q1: node_exporter 和 kube-state-metrics 什么关系?
A: 完全不同的东西。node_exporter 抓的是 节点操作系统 指标(CPU、内存、磁盘、网络),kube-state-metrics 抓的是 K8s 对象状态(Pod、Service、Deployment、StatefulSet 的字段)。前者每个节点跑一个(DaemonSet),后者跑一个 Deployment。两者经常配合使用但采集的是完全不同的东西。
Q2: node_exporter 和 cAdvisor 什么关系?
A: 也是不同维度。node_exporter 抓节点整体,cAdvisor 抓容器(CPU/内存/I/O 按容器分组)。cAdvisor 现在被 kubelet 内置,暴露于 kubelet 的 :10250/metrics/cadvisor。想要容器级指标看 kubelet,不想依赖 kubelet 就装 cAdvisor 单独实例。
Q3: node_exporter 部署在 K8s 里为什么指标和本地不一样?
A: 常见三个坑:① DaemonSet 没开 hostNetwork 和 hostPID,看到的是 pod 自己的 /proc 而不是宿主机 ② /proc /sys / 三个 hostPath 挂载要 read-only 加进来 ③ --path.procfs=/host/proc 参数没配。用 kubectl 直接 exec -it pod -- cat /proc/meminfo 看是不是宿主机数据。
Q4: node_exporter 报警规则该用哪些?
A: Prometheus 官方推荐 6 条基础规则:NodeHighCPU、NodeHighMemory、NodeFilesystemAlmostOutOfSpace、NodeFilesystemAlmostOutOfInodes、NodeNetworkReceiveErrors、NodeNetworkTransmitErrors。不要盲目加更多,先跑通这 6 条再根据业务补。官方规则库 prometheus/prometheus/tree/main/documentation/examples/prometheus.yml。
7. 常见误区
| 误区 | 真相 |
|---|---|
| "node_exporter 是 Prometheus 的必需组件" | 不是。它是 Node/Linux 指标的标准采集器,Windows 用 windows_exporter,MySQL 用 mysqld_exporter |
| "指标丢了就是 node_exporter 挂了" | 未必。可能 Prometheus 侧问题,或 relabel 过滤,先查 target 状态 |
| "所有指标都在 /metrics 里" | 默认只暴露启用的 collector。隐藏指标要 --collector.xxx.enabled=true 或 ?show_hidden=1 |
| "node_exporter 抓不到 K8s 数据" | 它本来就不抓 K8s,那是 kube-state-metrics 和 cAdvisor 的活 |
| "改启动参数要 kill 进程重启" | systemd 用户走 systemctl edit,K8s 用户改 DaemonSet spec,直接 kill -9 会导致 systemd 拉起老参数 |
8. 关联阅读
- Prometheus 部署 — 部署基础
- PromQL 速查 — 查询语法
- Alertmanager 路由树 — 告警配置
- Linux 监控 CPU — top 决策树与 node_exporter 联动