Skip to content

Node Exporter

一台 Linux 服务器上跑着各种服务。CPU 有没有打满、内存还够不够、磁盘快满了吗、网卡跑了多少流量——这些不是去问 MySQL 或 Nginx 才知道的,是操作系统本身随时在记录的。

Node Exporter 做的事情就是读取 Linux 内核暴露出来的状态信息(/proc/sys、网络统计、文件系统信息),把它们整理成 Prometheus 认识的标准格式,暴露在本机 9100 端口的 /metrics 路径上。它只负责"翻译状态成指标",不保存数据、不发告警、不画图——后面的事情全都交给 Prometheus。

Node Exporter 在整个监控链路中的位置

Node Exporter 是一个只读的翻译器:它看到 Linux 内核说"可用内存 6GB",就写成 node_memory_MemAvailable_bytes 6011232256,等 Prometheus 来取。

主机指标主要回答这几类问题:

问题用哪个指标看
这台机器还在被 Prometheus 抓吗up{job="node"}
CPU 是不是一直很忙node_cpu_seconds_total
内存还够不够node_memory_MemAvailable_bytes
磁盘是不是快满了node_filesystem_avail_bytes
机器负载(排队等 CPU 的进程数)高不高node_load1node_load5
网卡流量有没有突增node_network_receive_bytes_total

三台机器统一部署

实验里三台机器都装 Node Exporter:

主机角色Node Exporter 端口
192.168.10.11 mon01监控节点:9100
192.168.10.12 db01数据库节点:9100
192.168.10.13 cache01缓存节点:9100

三台机器执行同样的步骤。Exporter 使用一个无登录权限的专用用户运行,权限最小化——即使 exporter 进程被攻破,攻击者也没法登录系统:

bash
# system 用户——没有 home 目录,没有 login shell,仅用于运行服务进程
useradd --system --no-create-home --shell /sbin/nologin prometheus

cd /opt/monitor/src

# 下载 Node Exporter 二进制包
curl -fL -o node_exporter-1.11.1.linux-amd64.tar.gz \
  https://github.com/prometheus/node_exporter/releases/download/v1.11.1/node_exporter-1.11.1.linux-amd64.tar.gz

tar -xzf node_exporter-1.11.1.linux-amd64.tar.gz

# 二进制放到固定路径——后续升级只替换这个文件
install -m 0755 node_exporter-1.11.1.linux-amd64/node_exporter /usr/local/bin/node_exporter

/usr/local/bin/node_exporter --version

systemd unit 写为 /etc/systemd/system/node_exporter.service

ini
[Unit]
Description=Prometheus Node Exporter
After=network-online.target
Wants=network-online.target

[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/node_exporter \
  --web.listen-address=:9100 \
  --collector.systemd \
  --collector.processes
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

--collector.systemd 可以暴露各 systemd 服务单元的运行状态(哪些服务在 running、哪些 failed),--collector.processes 暴露进程数量统计。开启的 collector 越多,/metrics 返回的数据越大,Prometheus 抓取消耗也越大。实验环境这两个很常用,生产环境按实际需要增减。

启动并验证:

bash
systemctl daemon-reload
systemctl enable --now node_exporter

# 确认进程已被 systemd 托管
systemctl is-active node_exporter

# 确认 /metrics 有正常返回——node_uname_info 会带内核版本信息
curl -s http://127.0.0.1:9100/metrics | grep '^node_uname_info'

node_uname_info 会带上内核版本、系统架构等标签信息。它不是性能指标,只是证明 exporter 能正常工作——类似"先看机器有没有开机"。

让 Prometheus 抓取三台 Node Exporter

三台机器的 Node Exporter 都启动后,在 Prometheus 配置里增加 node job:

yaml
scrape_configs:
  - job_name: node
    static_configs:
      - targets:
          - 192.168.10.11:9100
        labels:
          env: lab
          role: monitor
          hostname: mon01

      - targets:
          - 192.168.10.12:9100
        labels:
          env: lab
          role: database
          hostname: db01

      - targets:
          - 192.168.10.13:9100
        labels:
          env: lab
          role: cache
          hostname: cache01

job 把同类采集目标归在一起,instance 默认来自 target 地址。这里额外加了 hostnamerole 标签——是用来说明用途的,不是必须要的。排查时看到 db01 比看到 192.168.10.12 更快反应出角色。这些信息适合放在标签里,因为它是稳定的(一台机器不会今天叫 db01 明天叫 cache01)。不过要注意:标签总数和取值种类会直接决定序列数量,不要在一个指标上放太多标签。

改完配置后检查语法再热加载——热加载比重启好,它不会造成采集中断:

bash
# 先检查 YAML 语法和规则文件路径
promtool check config /etc/prometheus/prometheus.yml

# 热加载——需要 Prometheus 启动参数里开了 --web.enable-lifecycle
curl -X POST http://127.0.0.1:9090/-/reload

在 Targets 页面选 node scrape pool,展开后看:Endpoint 是三台机器的 9100,Labels 里应有 hostnameroleenvState 都应该是 UP

主机核心指标

CPU

node_cpu_seconds_total 是 Counter 类型——记录每个 CPU 核心在不同模式下累计消耗的秒数(idle=空闲、user=用户态运行、system=内核态、iowait=等待磁盘 IO)。

因为它是累加值,直接看绝对值没意义——"CPU 累计空闲了 15000 秒"不说明现在忙不忙。所以 CPU 使用率用 rate() 算最近一段时间的增长速度:

promql
100 - (
  avg by (instance) (
    rate(node_cpu_seconds_total{job="node",mode="idle"}[5m])
  ) * 100
)

这条表达式的思路是:先按机器(by (instance))算最近 5 分钟 idle 占比的平均值,再用 100 减去它得到使用率。不写 by (instance) 的话会把所有 CPU 核心分别画一条线,同一台机器能出几十条曲线。

CPU 使用率不能只看一个数字。user=高通常偏应用计算,system=高可能关联系统调用和网络包处理,iowait=高要接着看磁盘。负载很高但 CPU 使用率不高——说明大量进程在等 IO 或锁,CPU 没忙但进程在排队。

内存

Linux 内存管理有个特点:空闲内存会被拿来当 page cache(缓存磁盘数据),所以 MemFree 很低但内存并不紧张——这些缓存随时可以被回收给应用。MemAvailable 更接近"还能给新进程分配多少内存":

promql
100 * (1 - (
  node_memory_MemAvailable_bytes{job="node"}
  /
  node_memory_MemTotal_bytes{job="node"}
))

告警和看板里用 MemAvailable 而不是 MemFree,能减少"明明内存够用但报了内存不足"的假告警。

磁盘

promql
100 * (1 - (
  node_filesystem_avail_bytes{job="node",mountpoint="/",fstype!~"tmpfs|overlay"}
  /
  node_filesystem_size_bytes{job="node",mountpoint="/",fstype!~"tmpfs|overlay"}
))

fstype!~"tmpfs|overlay" 这一截很重要。tmpfs 是内存文件系统(不是真实磁盘),overlay 常见于容器环境。不把它们滤掉的话,图上会混进很多和真实磁盘容量不相关的挂载点。

除了容量,inode 也值得关注——磁盘还有空间但 inode 耗光了,文件也创建不了。

网络

promql
rate(node_network_receive_bytes_total{job="node",device!~"lo|veth.*"}[5m])

lo 是本地回环网卡(127.0.0.1 通的流量),veth.* 是容器虚拟网卡。看主机真实的业务网卡流量时要把它们滤掉。网络排查除了看流量大小,还要看丢包、TCP 重传和连接数——流量正常不等于网络健康。

Target Down 排查三步走

up{job="node"} == 0 只说明 Prometheus 没抓到这个 exporter。原因可能是机器宕机、网络不通、端口没监听、进程挂了、地址写错,也可能是抓取超时。

排查按链路顺序来,一层一层排除:

第一步:在 Targets 页面看错误信息。页面路径:Status → Target health,选 node 采集池。State=DOWN 时展开具体目标,会显示最近一次抓取的错误原因:

错误信息大概原因下一步
connection refused目标端口没有进程在监听上目标机器看 systemctl status node_exporter
context deadline exceeded网络不通或 exporter 响应慢查路由、防火墙、目标机器的负载
no route to host网络路径不可达查 IP 配置、网关、路由表
server returned HTTP status抓到了错误的 HTTP 响应可能是端口上跑了另一个服务

第二步:在 Prometheus 机器测试到目标的连通性

bash
# 确认 Prometheus 所在机器能访问到 exporter
curl -sS http://192.168.10.13:9100/metrics | grep '^node_uname_info'

第三步:登录目标机器看本地状态

bash
# 确认 9100 端口有进程在监听
ss -lntp | grep ':9100'

# 看 exporter 自身日志——collector 报错通常在这里
journalctl -u node_exporter -n 80 --no-pager

第一条主机告警

从最简单的开始——Exporter 抓不到了就告警:

yaml
groups:
  - name: node-basic
    rules:
      - alert: NodeExporterDown
        expr: up{job="node"} == 0
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "Node Exporter down on {{ $labels.instance }}"
          description: "Prometheus cannot scrape node_exporter for more than 1 minute."

for: 1m 的意思是"表达式持续满足 1 分钟才进入 firing"。这是为了防止偶发指标抖动触发告警——偶尔一次抓取失败不一定要通知,持续抓不到才需要处理。

这个规则加载后可以在 Prometheus 的 Alerts 页面(中文:告警)搜索 NodeExporterDown。状态可能是 inactive(没有异常)、pending(异常出现了但 for 时间还没够)、firing(正在触发)。告警怎么从 Prometheus 到 Alertmanager、怎么配置分组和通知,在告警设计和 Alertmanager 两篇里展开。