Kubernetes Node Exporter Down 告警排查实战:隐形杀手 Processes 采集器

摘要

  • 告警现象: 核心 OLAP 节点 Node Exporter Down,日志报 broken pipe
  • 排查路径: 从网络连通性验证到具体采集器性能分析,逐步缩小范围。
  • 根因定位: processes 采集器在遍历海量进程时耗时过长(>30s),导致抓取超时。
  • 解决方案: 禁用高开销采集器,恢复监控稳定性。

背景

在 Kubernetes 生产环境中,监控系统的稳定性至关重要。最近,我们收到了一条 KubernetesNodeExporterDown 告警,指向一个核心的 OLAP 计算节点。

该节点承载了大量的计算任务,负载较高。告警显示 Prometheus 无法从该节点获取监控数据,但在初步检查中,节点本身处于 Ready 状态,业务容器也运行正常。这显然不是一次简单的“节点宕机”,而是一次典型的监控组件故障。

故障复现与初步排查

1. 现象确认

首先检查告警对应的 Pod 状态:

1
2
kubectl get pod -n arms-prom -l app=prometheus-node-exporter -o wide | grep <故障节点IP>
# 输出: prometheus-node-exporter-xxxxx   1/1   Running   0   5d

Pod 状态是 Running,说明进程未崩溃。接着查看 Pod 日志:

1
kubectl logs -n arms-prom prometheus-node-exporter-xxxxx --tail=100

日志中充斥着如下错误:

1
error encoding and sending metric family: write tcp 10.89.48.213:9100 -> 10.89.48.10:35630: write: broken pipe

解读: broken pipe 通常意味着服务端(Node Exporter)试图向客户端(Prometheus/vmagent)发送数据时,发现连接已经被客户端关闭了。这通常指向抓取超时——客户端等不及了。

2. 网络连通性验证

为了排除网络隔离或防火墙问题,我们登录到同集群的 vmagent Pod 中进行手动验证。

1
2
3
# 验证 HTTP 响应头 (快速检查连通性)
curl -vI 10.89.48.213:9100
# 结果: HTTP/1.1 200 OK -> 网络是通的

3. 复现超时

既然网络通,那为什么会超时?我们模拟 Prometheus 的行为,带上超时时间进行完整抓取:

1
2
3
4
5
6
7
# 模拟 5秒超时
curl -m 5 -s -o /dev/null -w "Time Total: %{time_total}s\n" 10.89.48.213:9100/metrics
# 结果: 5.00s (Exit Code 28: Timeout)

# 模拟 30秒超时 (极端情况)
curl -m 30 -s -o /dev/null -w "Time Total: %{time_total}s\n" 10.89.48.213:9100/metrics
# 结果: 30.00s (Exit Code 28: Timeout)

结论: 即便给予 30 秒的宽限期,Node Exporter 依然无法返回完整的 Metrics。这说明它内部处理请求被卡死了。

抽丝剥茧:定位慢采集器

Node Exporter 默认启用了大量采集器(Collectors),我们需要找出是谁拖慢了整体速度。通常的嫌疑对象包括磁盘统计 (diskstats)、文件系统 (filesystem) 和网络连接 (netstat/ipvs)。

我们可以通过 URL 参数 collect[] 来单独测试特定的采集器。

1. 排除磁盘与文件系统

OLAP 节点通常挂载大量存储,这是头号嫌疑人。

1
2
3
4
5
6
7
# 测试 diskstats
curl -m 10 -s -o /dev/null -w "Only diskstats: %{time_total}s\n" "10.89.48.213:9100/metrics?collect[]=diskstats"
# 结果: 1.42s (稍慢,但远未超时)

# 测试 filesystem
curl -m 10 -s -o /dev/null -w "Only filesystem: %{time_total}s\n" "10.89.48.213:9100/metrics?collect[]=filesystem"
# 结果: 2.30s (正常范围)

虽然比空载慢,但 1-2 秒的耗时完全在可接受范围内,嫌疑排除

2. 排除网络相关

1
2
curl -m 10 -s -o /dev/null -w "Only ipvs: %{time_total}s\n" "10.89.48.213:9100/metrics?collect[]=ipvs"
# 结果: 0.49s (飞快)

3. 锁定嫌疑人:processes

在排除了常见大户后,我们将目光转向 processes 采集器。该采集器会遍历 /proc 目录统计进程状态。在计算节点上,如果存在大量短命进程、僵尸进程或线程,/proc 的遍历开销极大。

1
2
curl -m 30 -s -o /dev/null -w "Only processes: %{time_total}s\n" "10.89.48.213:9100/metrics?collect[]=processes"
# 结果: 30.00s (Exit Code 28: Timeout) !!!

根因找到processes 采集器在该节点上执行耗时超过 30 秒,直接导致了整个抓取请求超时。

解决方案

针对此类高负载节点,我们需要精简 Node Exporter 的采集项,禁用不必要的、高开销的采集器。

修改 DaemonSet 配置

prometheus-node-exporter 的启动参数中,显式禁用 processes 采集器。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
spec:
  template:
    spec:
      containers:
      - name: node-exporter
        args:
        # ... 保留原有参数
        - --no-collector.processes  # 新增禁用参数
        # 建议同时检查以下高开销项是否需要
        - --no-collector.tcpstat
        - --no-collector.btrfs

执行 Patch 操作(或更新 Helm Values):

1
2
3
kubectl patch daemonset prometheus-node-exporter -n arms-prom --type='json' -p='[
  {"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--no-collector.processes"}
]'

验证修复

等待 Pod 重启后,再次测试抓取耗时:

1
2
curl -m 5 -s -o /dev/null -w "Time Total: %{time_total}s\n" 10.89.48.213:9100/metrics
# 结果: 1.85s (恢复正常)

SRE 最佳实践与建议

  1. 分而治之 (Divide and Conquer): 当面对复杂的超时问题时,不要盲目猜测。利用 Node Exporter 的 collect[] 参数将问题拆解,逐个击破,是最高效的排查手段。

  2. 默认配置陷阱: 开源组件的默认配置往往追求功能全覆盖,而非性能最优。在生产环境(特别是高负载场景)中,务必审查并禁用不需要的采集器(如 btrfs, zfs, wifi, processes 等)。

  3. 监控的监控: 关注 scrape_duration_seconds 指标。如果抓取耗时长期接近 scrape_timeout,这就是隐患。对于关键组件,不仅要看它是否 Up,还要看它“多快能 Up”。

  4. 超时设置: Prometheus 的 scrape_timeout 默认通常为 10s。对于重型节点,适当调大(如 15s/30s)可以缓解抖动,但不能解决根本的性能瓶颈。优化采集源才是治本之策。

0%