☰
node_exporter实战:从部署到Prometheus监控告警全流程
2026/10/1 14:57:44 网站建设 项目流程

1. 为什么服务器资源监控必须有个node_exporter

先讲个真实场景。几年前我接管一套跑了三年的业务集群,二十多台裸金属服务器,监控全靠每天早上一遍top、free -h、df -h手工巡检,出了问题就只能翻聊天记录找"昨天是不是有人上了发布"。直到有一天凌晨三点,一台机器磁盘写满,误报警电话打到值班手机上的时候,已经是业务不可用的状态了。从那以后我下了个决心:服务器资源监控这件事,必须自动化,必须可回溯,必须能告警。

后来就顺理成章接触到了Prometheus + node_exporter这套组合。node_exporter是Prometheus生态里最基础也是最重要的一个exporter,它干的事一句话就能说清:把Linux服务器内核和系统层面的指标暴露成Prometheus能抓取的Metrics格式。CPU使用率、内存水位、磁盘空间和IO、网络流量、文件系统inode、系统负载、开机时长,甚至网卡丢包、软中断分布,全都能采到。你可以把它理解成一个"系统体检仪"的探针,装在被监控的机器上,默认在9100端口吐数据,Prometheus定期来刮(scrape)一次,数据就进了时序数据库。

这篇文章面向的是刚接触监控平台、想把服务器资源监控真正落地的人。我会从node_exporter的部署细节、Prometheus端的抓取配置、Grafana可视化、告警规则一直讲到生产环境里我踩过的坑,全程都是可以直接抄的配置和命令。不管你是运维、后端开发还是SRE,照着走一遍,一套能用的服务器资源监控平台就能跑起来。

那为什么偏偏是Prometheus + node_exporter?而不是传统的Zabbix、Nagios?因为Prometheus的Pull模型(服务端主动拉取)天然适合云原生和动态环境,配置即代码,告警规则用PromQL写,灵活度远高于传统模板式监控。而node_exporter就是这个模型下最轻量、最成熟、社区维护最活跃的系统指标采集器。Prometheus是开源项目,CNCF的毕业项目,生态里Grafana、Alertmanager这些周边工具全是开源组件,整套平台不需要花一分钱授权费,这也是它能成为事实标准的原因。

2. 装之前先想清楚:版本、权限、端口和目录规划

很多人装node_exporter就是下载二进制、nohup一把梭、然后配个抓取路径就完事了。本地测试没问题,一上生产就各种出岔子。我建议在敲第一条命令之前,先花十分钟把下面几件事定下来。

2.1 版本怎么选才不给自己埋雷

node_exporter的版本更新频率不算快,但也不慢,我见过最坑的情况是生产环境还跑着0.18版本,连node_filesystem_avail_bytes这类指标的命名规范都不一样,后来升级Prometheus之后直接导致旧面板全部失效。选版本就一条原则:选官方GitHub Release页面上最新的稳定版,同时看Release Notes里有没有breaking change。

截至我写这篇文章,node_exporter稳定版已经到1.8.x,Prometheus则是2.53.x(3.0也已经发布但生产环境我暂时不会主动升)。1.x版本的指标命名和2.x之间有过一次大的变化,现在的面板模板基本都按1.x命名来写的,所以新装环境直接用1.8以上版本就好,别回头去用0.x的老古董。

Prometheus服务端的版本,建议2.4x以上的长期支持版本。如果公司已经有现成的Prometheus跑着,就不用重复装,直接复用;如果没有,我建议服务端和exporter分开装,服务端集中在专门的监控机器上,exporter分布到各业务节点。

2.2 运行用户与权限边界:别用root跑exporter

这是一个非常容易被忽视的点。node_exporter要读/proc、/sys这些内核文件系统来采集指标,表面上看起来"必须root",但实际不是。官方推荐的运行方式是用一个专用的系统用户,比如node_exporter用户,只需要给它对/proc和/sys的读权限就够了,这在对内核版本较新的系统上(4.x+)是完全可以工作的。

你可能会问,很多网上的教程里都是root直接跑,不也活得好好的?对,功能上没问题,但安全上是隐患。node_exporter默认会开启--web.listen-address=:9100,如果你的9100端口暴露到了公网,别人可以通过/metrics接口看到你机器几乎所有的系统信息,用户名、内核版本、挂载点、网络配置,这些信息对攻击者来说就是现成的踩点资料。用一个低权限用户跑,至少把提权路径切断了一层。

2.3 端口规划:9100不是你想开就能开

node_exporter默认监听9100端口。端口本身没什么特别,但你要提前想清楚两件事:

第一,Prometheus服务端到exporter的网络通路。如果两台机器之间有防火墙/安全组,需要在防火墙上放行来源IP为Prometheus服务器IP、目标端口为9100的入站规则。这里有个血泪教训:我曾经排查了一个小时"为什么targets一直是down",最后发现是云安全组只放行了80和443,9100压根没开。

第二,9100端口尽量不要暴露到公网。它没有认证机制,是纯明文HTTP服务。如果一定要暴露,至少用防火墙限制来源IP,或者用反向代理加一层Basic Auth。生产环境中更稳妥的做法是让exporter只监听内网IP,比如--web.listen-address=192.168.1.10:9100,这样即使防火墙规则配错了,外网也访问不到。

2.4 目录规划:二进制和数据的家要干净

虽然node_exporter是无状态的服务,不像Prometheus那样有数据目录,但规范还是要有的。我习惯这样规划:

  • 二进制目录:/usr/local/bin/node_exporter
  • 配置文件目录:/etc/node_exporter/
  • textfile collector目录:/var/lib/node_exporter/textfile/(后面会详细讲)
  • systemd unit文件:/etc/systemd/system/node_exporter.service

Prometheus服务端的目录规划也一并定了:配置文件/etc/prometheus/prometheus.yml,数据目录/var/lib/prometheus/,规则文件放/etc/prometheus/rules/。这样无论是后面接Alertmanager还是加规则,目录结构都清晰,排查问题的时候不用翻半天。

3. node_exporter的安装与启动:每一行命令都讲清楚

3.1 下载二进制并校验

node_exporter是纯Go编译的静态二进制,不依赖任何动态库,解压就能跑,这是它部署成本低的核心原因。下载方式如下:

# 到官方GitHub Releases页面找最新版本号 # 以1.8.2为例,amd64架构 cd /tmp wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz tar xvf node_exporter-1.8.2.linux-amd64.tar.gz cd node_exporter-1.8.2.linux-amd64

tar xvf解压后就是一个node_exporter可执行文件。拷贝到二进制目录,并确认有执行权限:

sudo cp node_exporter /usr/local/bin/ sudo chmod +x /usr/local/bin/node_exporter node_exporter --version

看到类似node_exporter, version 1.8.2 (branch: HEAD, revision: ...)的输出,就说明二进制没问题。这里一定要执行一次--version验证,我遇到过下载了一上午发现是旧版本缓存文件的情况,白折腾。

如果是ARM架构的服务器(比如鲲鹏、飞腾),记得下载linux-arm64的包,别下amd64的,跑不起来的。

提示:从官网下载如果速度慢,可以用国内镜像源或者让同事帮忙在能访问外网的环境下载后内网分发,注意比对SHA256校验和,别图省事直接拷。

3.2 用systemd把exporter变成常驻服务

这是最关键的一步。很多人图方便直接nohup ./node_exporter &,这种跑法有几个问题:开机不能自启、进程意外退出没人拉起来、日志管理混乱。正确做法是配置systemd服务。

先创建运行用户:

sudo useradd -M -r -s /bin/false node_exporter

参数说明:-M不创建家目录,-r创建为系统用户,-s /bin/false禁止登录。这是安全基线,一个不需要登录的服务账号不该有shell。

然后写unit文件:

# /etc/systemd/system/node_exporter.service [Unit] Description=Prometheus Node Exporter After=network.target [Service] User=node_exporter Group=node_exporter Type=simple Restart=on-failure RestartSec=5s ExecStart=/usr/local/bin/node_exporter \ --web.listen-address=:9100 \ --web.config.file=/etc/node_exporter/web-config.yml \ --collector.textfile.directory=/var/lib/node_exporter/textfile [Install] WantedBy=multi-user.target

启动并设置开机自启:

sudo systemctl daemon-reload sudo systemctl enable --now node_exporter sudo systemctl status node_exporter

看到Active: active (running)就说明服务起来了,再验证一下metrics接口:

curl http://127.0.0.1:9100/metrics | head -20

正常会输出一堆以# HELP和# TYPE开头的指标文本。看到node_cpu_seconds_total、node_memory_MemTotal_bytes这些指标名,说明采集已经工作了。

3.3 web-config.yml:给metrics接口加一层基础认证

刚才提到9100端口不能裸奔,其实官方从1.x就开始支持通过--web.config.file传入一个包含Basic Auth配置的文件,这算是官方内置的最简单认证方案。生成密码需要用到htpasswd工具(来自apache2-utils包):

sudo apt install apache2-utils # Debian/Ubuntu # 或者 yum install httpd-tools # CentOS/RHEL sudo htpasswd -B -c /etc/node_exporter/.credentials monitoring_admin

生成/etc/node_exporter/web-config.yml:

basic_auth_users: monitoring_admin: $2y$05$省略哈希值...

然后重启服务:

sudo systemctl restart node_exporter sudo chown node_exporter:node_exporter /etc/node_exporter/web-config.yml /etc/node_exporter/.credentials

加了认证之后,Prometheus服务端的scrape配置里也要对应配上用户名密码(这个后面讲)。注意一个细节:web-config.yml和.credentials的文件权限要严格限定,只允许exporter运行用户和root读取,不然哈希泄露等于没设。

3.4 采集器开关:哪些默认开、哪些要主动关

node_exporter按采集器(collector)组织功能,每个采集器负责一类指标。看默认开启列表的方式:

curl -s http://127.0.0.1:9100/metrics | grep ^node_ | awk -F_ '{print $2}' | sort -u

或者直接跑node_exporter --collector.disable-defaults --help,但更直观的方式是访问http://127.0.0.1:9100/页面,页面里会列出enabled collectors。

默认情况下,绝大多数采集器是开启的,包括cpu、meminfo、diskstats、filesystem、netdev、loadavg、uname、time等等。这些对我们日常监控足够了。但有几个采集器偶尔需要按需调整:

  • systemd采集器:默认关闭(1.x里默认开启,但要看具体版本),如果你想监控目标机器上systemd服务的状态,可以加--collector.systemd开启。它会暴露node_systemd_unit_state这类指标,对服务健康监控很有用,但要注意在高密度的机器上指标基数会比较大。
  • textfile采集器:默认开启的目录是空,需要你主动指定--collector.textfile.directory,然后自定义的脚本往这个目录写*.prom文件,exporter会在每次抓取时读取这些文件,把里面的metrics合并到输出里。这是node_exporter最灵活的扩展点,后面细讲。
  • perf、processes、selinux这些:按需开启,不需要就别开,省一点CPU和内存开销。

经验之谈:采集器不是越多越好,每个采集器都对应一组对/proc的读取操作,开太多在高并发机器上会有些许额外开销。先默认,跑几天看数据,缺什么再补。

3.5 textfile collector:自定义指标的逃生舱

实际监控中总有exporter原生不支持、但你又很想要的指标。比如:某个服务的版本号、数据库连接数、昨天跑批任务的最终状态。这时候textfile collector就是你的逃生舱。

原理很简单:用一个shell脚本或cron任务,把指标按Prometheus文本格式写入/var/lib/node_exporter/textfile/目录下的.prom文件,node_exporter每次被抓取时都会扫描这个目录并把这些指标合并到输出。

比如我想采集"某个数据同步任务的当前状态",脚本可以这样:

#!/bin/bash OUTPUT="/var/lib/node_exporter/textfile/sync_status.prom" if pgrep -f "sync_job.py" > /dev/null; then echo "sync_job_running 1" > $OUTPUT else echo "sync_job_running 0" > $OUTPUT fi

配合cron每30秒执行一次,之后就能在Prometheus里用sync_job_running这个指标做告警了。这里有一个关键注意事项:textfile目录的属主必须是node_exporter运行用户,否则exporter没权限读文件,你会在exporter日志里看到Error reading textfile,然后该指标一直不存在。

4. Prometheus端scrape配置:让监控目标进入采集中

node_exporter装好只是"准备好了数据",Prometheus服务端还得知道该去哪里拿、多久拿一次、拿的时候带什么参数。这一步全在prometheus.yml里完成。

4.1 prometheus.yml的完整骨架

一份能用的最小配置长这样:

# /etc/prometheus/prometheus.yml global: scrape_interval: 15s evaluation_interval: 15s external_labels: cluster: "prod" scrape_configs: - job_name: "node_exporter" static_configs: - targets: ["192.168.1.10:9100", "192.168.1.11:9100"] metrics_path: /metrics scheme: http basic_auth: username: monitoring_admin password: "换成你的密码" relabel_configs: - source_labels: [__address__] regex: "([^:]+):9100" target_label: instance replacement: "${1}"

每个字段都有讲究。scrape_interval是抓取间隔,15秒是社区默认值,够用且不过度消耗;如果监控对象是时序波动很大的指标(比如连接数),可以单独在job里覆盖为5s,但要接受存储和查询压力的增加。

static_configs是最简单的目标定义方式,几台机器直接列出来。这种方式的问题在于,当你新增一台机器时,要手动改配置并reload Prometheus。目标多到几十台之后,静态配置就会变得难以维护,这时候就需要文件发现(file_sd)或者Consul服务发现,这个后面说。

basic_auth对应我们给node_exporter加的密码认证。注意密码是明文写在配置文件里的,所以要确保prometheus.yml的文件权限是600,只有Prometheus进程用户能读。

4.2 scrape_interval与evaluation_interval怎么定

这两个间隔经常被人混淆。scrape_interval决定了Prometheus多久来exporter抓一次数据,影响的是数据采样频率;evaluation_interval决定了Prometheus多久计算一次告警规则,影响的是告警判定频率。

我的建议:默认都是15s,但evaluation_interval可以稍微拉长到30s,因为告警规则里通常带着类似for: 5m的持续时间条件,判频繁了没有意义,反而增加CPU开销。抓取间隔如果太小(比如1s),node_exporter本身倒是撑得住,但Prometheus的存储和查询压力会成倍增长,数据点增多后,Grafana查询也会变慢,磁盘占用也会涨。15s对服务器资源监控完全足够,这个参数真的不用卷。

4.3 静态配置与文件发现:从一台到一百台

机器少的时候静态配置没问题,一旦规模上来,每次加机器都改配置太痛苦。Prometheus提供file_sd_configs,把targets列表放到一个独立的JSON或YAML文件里,Prometheus会定期重新读取这个文件,不需要重启。

文件发现配置方式:

scrape_configs: - job_name: "node_exporter" file_sd_configs: - files: - /etc/prometheus/targets/node_exporter.yml refresh_interval: 30s

targets文件内容:

- targets: ["192.168.1.10:9100", "192.168.1.11:9100"] labels: env: prod group: web

这样加机器的时候只需要往这个文件里追加一行,Prometheus最多30秒后就会自动pickup新目标。配合一些自动化运维工具(比如Ansible)批量生成targets文件,加机器就可以做到全自动。

如果公司已经用了Consul或者Kubernetes,那更推荐consul_sd_configs或kubernetes_sd_configs,服务上下线完全动态感知。不过对于纯裸机监控场景,file_sd已经足够解决90%的需求,先把这套跑熟再考虑更复杂的服务发现不迟。

4.4 relabel:给指标打标签的正确姿势

relabel_configs可能是新手最绕的部分,但也是Prometheus最有威力的特性之一。它的核心作用是:在抓取之前改写target的标签,从而控制和丰富数据的维度。

我常用的一个场景是把IP地址转成更友好的instance名。默认情况下,每个时序的instance标签就是target的ip:port,比如192.168.1.10:9100。在Grafana上看到一堆IP,很难一眼看出是哪台业务机器。所以我通常会加一条relabel,把instance改写为主机名:

relabel_configs: - source_labels: [__address__] regex: "([^:]+):.*" replacement: "${1}" target_label: instance

更高级一点,可以通过DNS反向解析或者读取一个映射文件来打标签。比如我在内网维护了一个/etc/hosts风格的映射,配合正则提取主机名来给机器打上role标签,这样后续的告警规则就能按"这组机器都是数据库"来区分策略。

Relabel的调试要细心,每改一次配置,在Prometheus的Targets页面刷新看label是否如预期。判断一个relabel写对没写对,最直接的办法是看target列表里,instance标签的值和你想的是否一致。记住一句话:relabel是"改标签",不是"改数据",想清楚你要在哪个维度上分组、聚合,再来写relabel。

4.5 配置生效与验证

修改完prometheus.yml之后,强烈建议先做语法校验再reload:

promtool check config /etc/prometheus/prometheus.yml

promtool是Prometheus自带的命令行工具,在二进制包解压后的目录里就能找到。校验通过后,用Prometheus的reload接口,优雅生效,不用重启进程:

curl -X POST http://127.0.0.1:9090/-/reload

前提是你的Prometheus启动时带了--web.enable-lifecycle参数。看了眼Targets页面(Status → Targets),看到node_exporter的target状态是UP,就说明抓取链路已经完全打通了。

5. Grafana接进来:仪表盘看什么才有价值

数据进了Prometheus,也才是半成品。大多数人看监控的习惯是"图标要全、颜色要炫",但真到了故障排查的时候,一屏花花绿绿里找不到有用的信息。这块我来说说怎么把Grafana和数据结合好,以及哪些面板值得留。

5.1 数据源与基础面板配置

Grafana的安装不是本文重点,简单提一句:官方支持rpm/deb包安装和docker方式,装好后第一次访问默认3000端口,admin/admin登录。加数据源的时候选择Prometheus类型,URL填Prometheus的地址(比如http://localhost:9090),保存并测试连通性就行。

Grafana社区有大量现成的dashboard模板,node_exporter最常用的模板ID是1860,名字叫"Node Exporter Full",覆盖了CPU、内存、磁盘、网络、文件系统等几乎所有node_exporter能采集的指标,面板也做了合理的分组。在Grafana里通过Import功能填入1860,选择对应的Prometheus数据源,一套完整的监控看板就有了。

5.2 必须盯住的几个核心面板

有经验的监控者不会同时盯几十个图表,而是盯几个能反映全局状态的核心指标。我的习惯是至少保证下面这几个面板存在:

  • CPU使用率与负载:100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100),配合node_load1、node_load5看负载趋势。注意多核机器的load值要和核数对比看,不是一个绝对值就能定论的。
  • 内存使用率:(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100,这个最直观,MemAvailable已经把缓存算进去了,比MemFree更准确。
  • 磁盘空间与inode:node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"},inode用node_filesystem_files_free / node_filesystem_files,这一组面板能提前预警"磁盘满了但现象还没爆发"的情况。
  • 磁盘IO:rate(node_disk_read_bytes_total[5m])和rate(node_disk_written_bytes_total[5m]),适合定位慢查询、大数据同步这类IO密集问题的根因。
  • 网络流量:rate(node_network_receive_bytes_total[5m])和rate(node_network_transmit_bytes_total[5m]),按网卡维度区分,排查流量异常时非常有帮助。

5.3 面板设计的两个原则

第一,面板数量要克制。除非你的屏幕是电视墙,不然一屏放超过12个面板基本就是灾难。故障时你需要的不是最全的仪表盘,而是最快定位问题的那个。

第二,时间范围切换要顺手。Grafana右上角的时间选择器是排查问题的利器,出问题的那一刻的数据,才是真正有价值的数据。通常是先用30分钟看短期波动,发现异常再逐步缩小到10分钟、5分钟,直到找到突变点。所以我建议把"最近15分钟"固定成一个快捷选项,省得到时候还手动改时间。

6. 告警规则:从"看监控"到"被监控叫醒"

监控平台真正产生价值,是从告警规则配置好的那一刻开始的。Prometheus用PromQL写告警规则,天然可以表达"过去5分钟CPU持续超过90%"这类带窗口条件的逻辑,这在传统监控里写起来非常繁琐。

6.1 告警规则的语法结构

规则文件通常放在/etc/prometheus/rules/目录下,然后在主配置里引用:

# prometheus.yml 里追加 rule_files: - /etc/prometheus/rules/*.yml

规则文件本身长这样:

groups: - name: node_exporter_alerts rules: - alert: HighCpuUsage expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85 for: 10m labels: severity: warning annotations: summary: "{{ $labels.instance }} CPU使用率过高" description: "CPU使用率已持续超过85%(当前值:{{ $value | printf \"%.2f\" }}%)"

for: 10m是关键,意思是这个条件持续成立10分钟才触发告警。这个机制非常有用,它过滤掉了瞬间的CPU尖峰、短时的网络抖动等噪声,只有"持续异常"才会通知你。不要为了减少告警量而把这个时间设得太长,否则真正的问题也会被过滤掉,我的习惯是5~10分钟。

6.2 生产环境必配的几条规则

根据我实际运维的经验,下面这几条规则几乎是每套监控平台都要有的,覆盖了最频发的故障类型:

groups: - name: node_exporter_basic rules: - alert: InstanceDown expr: up == 0 for: 1m labels: severity: critical annotations: summary: "监控目标 {{ $labels.instance }} 已宕机" - alert: HighMemoryUsage expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 90 for: 5m labels: severity: warning annotations: summary: "{{ $labels.instance }} 内存使用率超过90%" - alert: DiskWillFillIn4h expr: predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[1h], 4 * 3600) < 0 for: 10m labels: severity: critical annotations: summary: "{{ $labels.instance }} 磁盘预计4小时后写满" - alert: HighDiskIo expr: rate(node_disk_io_time_seconds_total{device=~"sd.*"}[5m]) > 0.8 for: 10m labels: severity: warning annotations: summary: "{{ $labels.instance }} 设备 {{ $labels.device }} IO使用率过高"

这里面最有用的一条我单独拿出来说:DiskWillFillIn4h用的是predict_linear函数。它不是简单判断"当前用了多少",而是基于过去1小时的磁盘消耗趋势,线性拟合预测4小时后的剩余空间是否会变成负数。这意味着你能在磁盘真正写满之前好几个小时收到预警,给自己留足清理和扩容的时间。这种"预测型告警"才是Prometheus告警相对传统监控的高级之处。

6.3 Alertmanager与通知链路

规则触发后产生的是Alert,但要把Alert送到钉钉、企业微信、邮件或电话,还需要Alertmanager组件。部署Alertmanager不在本文展开,但它的通知链路要清楚:

Prometheus根据规则计算 → Alert状态变为pending → 持续满足for条件后变为firing → Prometheus把firing状态的Alert推给Alertmanager → Alertmanager按路由规则分发到对应的receiver(钉钉机器人、邮件组、webhook等)。

Alertmanager的价值除了分发,还有告警去重、分组、抑制和静默。比如同一台机器同时触发了磁盘告警和IO告警,Alertmanager可以把它们合并成一条通知,而不是瞬间给你轰炸十几条。对于刚上手的人,先把通知发到钉钉/微信群就够了,后面再逐步完善值班路由和静默策略。

7. 踩坑实录:从采集空白到告警轰炸的排查全过程

配置看起来都照着文档做了,但生产环境总会有各种"文档没写"的问题。这一节我挑了四个我真实踩过、而且非常有代表性的问题,完整还原排查链路,希望你能少走弯路。

7.1 问题一:Targets里UP了,但查询却拿不到数据

现象:Prometheus的Targets页面显示node_exporter是UP,但到Graph页面输入node_cpu_seconds_total,结果却是"No data"。

排查过程:UP说明网络通、抓取成功,那问题大概率在数据本身。我先检查了抓取时间是否已经是历史很久之前,发现不对;然后我手动curl了exporter的metrics接口,发现指标名明明存在。接着我去看了Prometheus的日志,发现一条关键信息:查询超时或者样本被丢弃(out of order)。

根因:我们的Prometheus实例上运行了多个job,其中有一个job的抓取间隔设置成了1s,样本量太大,导致本地TSDB写入压力剧增,部分样本写入失败。然后Grafana查询时用的大窗口,正好命中那些丢失样本的时间段。

解决:把那个高频抓取job的间隔改回15s,同时清理了TSDB的旧数据,恢复了写入。

经验:UP只是"抓取成功",不代表"数据完整可靠"。如果发现查询结果经常有空洞,先考虑样本量是否过大、是否有高频抓取job,再考虑磁盘IO和Prometheus本身资源是否瓶颈。

7.2 问题二:node_exporter端口被扫描爆破

现象:上线一周后,安全团队发来告警,说有台机器9100端口流量异常,来源IP遍布全球。

排查过程:这类情况在公网机器上很常见,9100端口没有认证,任何人都可以拉取metrics信息。我们第一反应是看exporter进程是否异常,确认没有,再查操作系统日志,发现大量来自外部IP的TCP连接请求。

根因:9100端口暴露在公网,既没有云安全组限制,也没有Basic Auth,等于是把系统信息透明地放在公网上。

解决:马上在云安全组和系统防火墙两层做了限制,只允许Prometheus服务器的IP访问9100,同时给exporter加上了web-config.yml的Basic Auth配置。

经验:凡是没有认证的服务,一律不要暴露公网。即便是内网,也建议加认证或者至少用防火墙约束来源IP,别赌"内网很安全"。

7.3 问题三:textfile collector目录权限不对,指标一直不出现

现象:我写了一堆自定义脚本,往/var/lib/node_exporter/textfile/写.prom文件,但Prometheus里就是查不到对应指标。

排查过程:我先在exporter所在机器上执行curl http://127.0.0.1:9100/metrics | grep xxx,发现自定义指标确实不在输出里。再查看systemd服务的日志,journalctl -u node_exporter -f,看到了Error reading textfile: open /var/lib/node_exporter/textfile/xxx.prom: permission denied。

根因:创建目录时用的是root用户,而exporter进程是以node_exporter用户运行的,没有读权限。

解决:sudo chown -R node_exporter:node_exporter /var/lib/node_exporter/textfile/,重启exporter后指标正常出现。

经验:所有和exporter运行用户相关的目录权限问题,在node_exporter的日志里都会明确报出来,第一件事就是journalctl -u node_exporter看日志,比瞎猜快得多。

7.4 问题四:高基数标签把Prometheus内存吃光

现象:监控平台跑了一个多月后,Prometheus的内存占用持续上涨,最终把监控服务器搞到OOM,反复重启。

排查过程:内存上涨通常是时序基数爆炸导致的。我进入Prometheus的TSDB状态页,发现序列数量远超预期。再一查,发现是另一个团队在node_exporter的relabel配置里加了__meta_*标签到最终指标,导致时间序列维度激增。

根因:高基数标签(比如把进程的某个随机ID当作标签)会让每个时间序列变成独立的序列,几万甚至几十万个序列直接把内存吃满。这是Prometheus最典型的"隐性事故"。

解决:删掉那个高基数relabel,同时在设计标签时立了一条规矩:标签的取值规模必须可控,枚举值超过100个的字段不建议做标签。

经验:Prometheus的性能问题九成出在高基数标签上。监控平台稳定运行后,定期检查TSDB的序列总数量,一旦出现异常上涨,先查标签设计,再查relabel,最后再考虑扩容。

8. 最后沉淀:监控平台维护的几点体会

踩了这么多坑,说点我个人的经验沉淀。

第一,监控平台本身也是系统,需要带着管理的思路去维护。node_exporter和Prometheus的版本升级要留出回归窗口,Grafana面板的改要有记录,告警规则的变更要有评审,总之不要让监控平台变成无人维护的"孤儿系统"。

第二,数据准确性比面板美观重要得多。我见过很多团队花大力气调Grafana主题色、配大屏,却连node_time_seconds这种时钟同步指标都不看。服务器时间漂移会导致所有时序数据的对齐出问题,这个指标虽然不起眼,但我会专门配一条告警规则,时差超过5秒就告警。数据准确了,面板再朴素都有价值。

第三,监控是一个持续演进的过程,先跑通基础链路,再逐步加告警、加自动发现、加对接CMDB,这个过程本身就是对整个基础设施认知的深化。node_exporter只是这套平台的起点,但它是每一台服务器都值得配置的"底线"。

最后再分享一个小技巧:每次配置完告警规则,用promtool check rules /etc/prometheus/rules/*.yml做语法校验,再顺手用Prometheus console页面输入告警表达式确认有数据返回,这样能避免很多"规则写错了但没人发现"的尴尬。一次配好,长期受益。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询