Appearance
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_load1、node_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 --versionsystemd 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: cache01job 把同类采集目标归在一起,instance 默认来自 target 地址。这里额外加了 hostname 和 role 标签——是用来说明用途的,不是必须要的。排查时看到 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 里应有 hostname、role、env,State 都应该是 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 两篇里展开。