跳转至

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

常见原因:

  1. 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(备份软件常见),会被过滤。

  2. mount-points-exclude 正则太贪:默认 '^(proc|sysfs|efivarfs|devpts|devtmpfs|none|auto|on|usr\.\.)$',正则写得不好会误杀业务挂载点。

  3. 权限不足:文件系统指标不需要 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。

排查:

curl http://localhost:9100/metrics | grep node_cpu_seconds_total | head

原因: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 里写:

sum by (mode) (rate(node_cpu_seconds_total[5m]))
# 只取存在的 mode,不存在的返 NaN 但不报错

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)。

排查:

grep Tcp_RetransSegs /proc/net/netstat
# 有则 kernel 支持,无则不支持

修法:PromQL 报警规则用 OR 兜底:

node_netstat_Tcp_RetransSegs > 100 OR on()
node_netstat_Tcp_RetransSegs == 0  # 兜底

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 高的机器),后续请求会互相覆盖。

scrape_interval: 30s    # 别低于 30s
scrape_timeout: 25s     # 留 5s 缓冲

修法:Prometheus 全局 scrape_interval 拉到 30s+,个别慢 target 用 job-level 覆盖:

scrape_configs:
  - job_name: 'node'
    scrape_interval: 30s
    scrape_timeout: 25s
    metrics_path: /metrics

案例 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. 关联阅读