☰
Prometheus+Grafana监控仪表盘搭建全攻略:从指标采集到告警通知
2026/9/29 1:41:51 网站建设 项目流程

先聊监控这件绕不开的事。做运维和开发的同学,早晚都会面对同一个问题:线上服务到底跑得怎么样?CPU 是不是快满了,内存有没有偷偷涨,磁盘哪一天会写爆,接口响应是不是开始变慢了。要是没有一套看得见的监控系统,这些问题基本上全靠猜、靠用户反馈、靠大半夜被报警电话叫醒来发现。而 Prometheus 加 Grafana 这套组合,是目前监控领域最主流、也最值得花时间搭起来的一套开源方案。Prometheus 负责采集和存储指标数据,内置强大的 PromQL 查询语言和告警规则引擎;Grafana 负责把数据画成直观的图表和可交互的仪表盘,还能对接告警渠道。这两条工具链都是开源免费的,组合在一起,不需要花一分钱授权费,就能搭出一个覆盖服务器、容器、数据库、中间件的监控平台。

这篇文章就是围绕“Prometheus + Grafana 搭建监控仪表盘”这个主题,把从零到一的全过程捋一遍。我不会只丢一堆命令,而是会把部署、配置、指标采集、仪表盘制作、告警接入到常见排坑都展开讲,尽量把每一步“为什么这么做”背后的逻辑也说清楚。适合正在准备搭建监控的运维工程师、后端开发,以及想把手头小项目监控起来的独立开发者。

我从单机裸跑 Prometheus 开始,一路玩到 Kubernetes 集群监控和 OpenTelemetry 指标接入,中间踩过的坑不少。下面这些内容,基本是我自己实操验证过、并且觉得值得写下来的经验。

1. 先想清楚监控体系怎么设计,再动手

1.1 为什么这个时代绕不开 Prometheus 和 Grafana

先回到一个基本问题:监控系统的核心职责是什么?无非三件事:采集指标、存储指标、展示和告警。

早期流行的 Zabbix 走的是“中心化采集”模型,监控端主动去轮询设备和主机。这个模型的配置相当繁琐,每加一台机器、一个监控项都要手动登记,扩展性也一般。Prometheus 的设计思路完全反过来,采用“拉取(Pull)”模型,被监控对象只需要暴露一个 /metrics 接口,Prometheus 服务端定期去抓取就行。这种设计的好处非常明显:

  • 被监控对象职责单一,不用关心告警和数据上报,只要把运行状态暴露成指标即可。
  • 抓取频率、超时时间全部由服务端统一控制,调参简单。
  • 天然适配 Kubernetes 这种动态变化的容器环境,通过服务发现能自动找到新出现的 Pod。

至于 Grafana,它的角色更纯粹,不负责采集和存储,只专注做可视化。它支持几十种数据源,包括 Prometheus、InfluxDB、MySQL、Elasticsearch、Loki 等,所以一套 Grafana 里可以同时看时序指标、日志、业务库数据。这也是为什么绝大多数人都会把 Prometheus 和 Grafana 绑在一起用,而不是用 Prometheus 自带的那个简陋图表界面。

1.2 每层组件各管一段,职责不要搞混

一套完整的 Prometheus + Grafana 监控体系,从下到上大致分四层,每一层的职责必须清晰,否则排查问题时会一头雾水。

层级组件职责
数据采集Node Exporter、cAdvisor、mysqld_exporter、otel-collector 等把系统、容器、中间件、业务应用的运行状态转换成 Prometheus 格式指标
存储与查询Prometheus Server定期拉取指标、本地落盘存储、执行 PromQL 查询、定期评估告警规则
告警处理Alertmanager接收 Prometheus 推送的告警事件,做分组、去重、路由,发送到邮件、企业微信、钉钉、webhook
可视化Grafana连接 Prometheus 数据源,制作 Dashboard,展示告警状态和变化趋势

很多人会忽略数据采集这一层,以为部署好 Prometheus 它就什么都能监控。其实 Prometheus 不会魔法般地知道你的机器有多少内存,它需要靠 Exporter 去系统里把数据读出来。每类监控对象都有对应的 Exporter:Linux 主机用 node_exporter,MySQL 用 mysqld_exporter,Redis 用 redis_exporter,容器资源用 cAdvisor。业务自定义指标则需要自己在代码里埋点、暴露接口。

如果是 Kubernetes 集群,还有更高级的玩法:通过 Prometheus Operator(现在叫 kube-prometheus-stack)把采集配置全部变成 CRD 对象,动态发现 ServiceMonitor 和 PodMonitor,自动采集集群里所有的标准指标。

1.3 拉模型和推模型的取舍要提前想明白

Prometheus 是标准的拉模型,但实际业务里有些场景天然适合“推”。比如批处理任务、定时 Job,跑完就退出,Prometheus 还没来得及来拉,进程已经没了,指标自然采集不到。

这类短生命周期任务的指标采集,主流有两种解法。第一种是部署 Pushgateway,任务结束时主动把指标推给一个长期运行的中间组件,Prometheus 再从这个组件去拉。这种方式简单直接,但 Pushgateway 本身是个单点,而且如果多个任务往同一个指标名里推数据,标签很容易互相污染,指标只增不删,用起来要非常小心。

第二种是 OpenTelemetry Collector 作为数据网关,业务侧通过 OTLP 协议把指标推给 Collector,Collector 再由 prometheus exporter 暴露一个 /metrics 端口,让 Prometheus 来拉。网上很多人搜“Prometheus 是如何从 otel-collector 收取数据的”,本质就是这个过程。Collector 在这条链路里起的是协议转换的作用,Prometheus 看到的仍然是一个普通的 /metrics 端点。

我的建议是:短期临时用 Pushgateway 可以,但如果团队有计划统一下一代可观测性体系,直接一步到位用 OpenTelemetry 更明智,后面的扩展空间大得多。

2. 安装部署:用 Docker Compose 三分钟跑通核心组件

2.1 版本选择和镜像下载那些事

部署方式我强烈建议用 Docker。Prometheus 和 Grafana 虽然也有二进制压缩包,解压就能跑,但后续升级、迁移、隔离依赖,容器化都要省心太多。

国内网络环境下,拉取 Docker Hub 官方镜像经常超时,这是很多人入门的第一个坎。除了配置 registry-mirrors 镜像加速地址之外,更稳妥的做法是把常用镜像同步到公司内部的镜像仓库,生产环境直接走内网拉取。千万不要在镜像下载这件事上死磕太久,换加速地址、换网络都试过了还不行,就直接下载官方 tar.gz 二进制包,小规模实验环境完全够用。

版本选择上,Prometheus 建议选当前最新稳定版,2.x 系列的配置 API 都是兼容的;Grafana 选最新稳定版即可,9.x 到 11.x 我都用过,配置方式没有根本性变化。node_exporter 要注意架构匹配,x86 的机器下 arm64 的包跑不起来。

下面是我在测试环境使用的 docker-compose.yml,把 Prometheus、Grafana、node_exporter 一次拉起,三分钟就能看到数据:

version: '3.8' services: prometheus: image: prom/prometheus:v2.53.0 container_name: prometheus ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention.time=15d' restart: unless-stopped node-exporter: image: prom/node-exporter:v1.8.2 container_name: node-exporter ports: - "9100:9100" restart: unless-stopped grafana: image: grafana/grafana:11.2.0 container_name: grafana ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=admin123 volumes: - grafana-data:/var/lib/grafana restart: unless-stopped volumes: prometheus-data: grafana-data:

这里说一个容易忽略的参数:--storage.tsdb.retention.time=15d。Prometheus 默认只保留 15 天数据,如果磁盘够大、想让历史趋势保留得更久,可以调成 30d 或 90d。但要注意,指标量大的时候磁盘占用增长非常快。经验上,一个小规模测试环境(几台机器 + 容器基础指标),一天大概几百 MB;上千台机器的大集群,一天几十 GB 很正常。刚开始搭建不用追求长时间保留,先把链路跑通,后面再根据磁盘容量调整。

2.2 prometheus.yml 核心配置逐段拆解

Prometheus 的所有行为都围绕这个配置文件展开。下面是一份最常用的配置,我逐段解释它在干什么:

global: scrape_interval: 15s evaluation_interval: 15s scrape_timeout: 10s rule_files: - "rules/*.yml" scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] - job_name: 'node-exporter' static_configs: - targets: - '192.168.1.10:9100' - '192.168.1.11:9100' relabel_configs: - source_labels: ['__address__'] regex: '(.*):9100' target_label: 'instance' replacement: '$1'

global里的三个参数是全局默认值。scrape_interval决定 Prometheus 每隔多久去拉一次指标,15 秒是通用设置;evaluation_interval决定告警规则每隔多久被评估一次,如果设成 15 秒,意味着一条告警从触发到被系统发现,最长可能延迟 15 秒;scrape_timeout是单个采集请求的超时时间,一般要小于scrape_interval,否则可能出现上一次抓取还没结束、下一次又开始了的情况。

rule_files用来加载告警规则文件,目录支持通配符,推荐把规则按业务或告警等级拆成多个小文件,方便维护。

scrape_configs是采集配置。每个job_name代表一组监控目标,最基础的用static_configs直接写 IP 和端口。注意relabel_configs这段小逻辑:它的作用是把192.168.1.10:9100里的 IP 提取出来,写到instance标签里。这样在 Grafana 图表和告警消息里看到的主机标识就是干净的 IP,而不是始终带着:9100端口的一长串。这个习惯建议从最开始就养成,否则后面所有面板和告警分组都会很难看。

2.3 启动之后先验证抓取链路,再碰 Grafana

执行docker compose up -d之后,不要急着打开 Grafana。先确认 Prometheus 真的把数据抓上来了。

打开浏览器访问http://localhost:9090/targets,正常情况下 Prometheus 和 node-exporter 两个采集目标都应该是 UP 状态。如果某个目标显示 DOWN,不要慌,用curl http://192.168.1.10:9100/metrics直接测一下,基本上就能判断是防火墙没放行端口,还是 exporter 本身没起来。

再打开http://localhost:9090/graph,输入一个最简单的查询:

up

这个查询会返回所有监控目标的状态,1 表示在线,0 表示挂掉,是判断 Prometheus 有没有在正常抓取的最快捷方式。然后试一个稍微实用点的:

node_memory_MemTotal_bytes / 1024 / 1024 / 1024

如果结果能算出这台机器内存的 GB 数,说明 node_exporter 的指标已经进入 Prometheus。到这里,采集链路跑通了,下一节才能真正发挥 Grafana 的威力。

3. Grafana 接入数据源与仪表盘制作实战

3.1 数据源连接填错 localhost,是最容易踩的坑

Grafana 默认账号是 admin/admin,第一次登录会要求改密码。在 docker-compose 里预设了GF_SECURITY_ADMIN_PASSWORD=admin123,就可以跳过首次改密环节。

进入 Grafana 后,添加数据源的路径是:左侧菜单 Connections -> Data sources -> Add data source -> 选择 Prometheus。真正容易翻车的是 HTTP URL 这一项。

很多人在这里填http://localhost:9090,然后发现怎么都连不上。原因很简单:Grafana 如果跑在 Docker 容器里,它看到的 localhost 是容器自身,而不是宿主机。正确写法分几种情况:

  • Grafana 和 Prometheus 都在同一台宿主机上用 Docker 跑:填http://host.docker.internal:9090(macOS/Windows)或http://<宿主机IP>:9090(Linux)。
  • 用 docker-compose 管理且两个容器在同一个自定义网络里:直接填http://prometheus:9090,用服务名通信,这是最推荐的方式,IP 变了也不受影响。
  • 两台不同的机器:填http://Prometheus服务器IP:9090。

我在正式环境里习惯把 Prometheus、Grafana、Alertmanager 放到同一个 docker-compose 项目里,并显式声明一个自定义网络。这样组件之间都能用服务名互相访问,不会因为宿主机 IP 变动导致监控链路断裂。

填好 URL 后点击 Save & test,出现 “Successfully queried the Prometheus API” 的绿色提示就说明数据源配好了。

3.2 两个社区精品仪表盘,导入即用

数据源接通后,没必要从零开始画图,社区里已经沉淀了很多高质量仪表盘。我最常用的有两块:

  • Node Exporter Full(ID: 1860):最经典的主机监控面板,CPU、内存、磁盘、网络、IO 全覆盖,图表布局经过很多人验证,第一次用很容易被它的完整度惊到。
  • Node Exporter for Prometheus Dashboard(ID: 8919):看板信息更紧凑,适合投到大屏上做展示。

导入路径:左侧 Dashboards -> Import,输入仪表盘 ID,点击 Load,选择刚才创建的 Prometheus 数据源,Import 即可。

导入后大概率直接就能看到数据。但也会遇到一个经典报错:failed to upgrade legacy queries datasource ... was not found。这个报错的本质是仪表盘的 JSON 里引用了旧数据源的 UID,而导入到当前 Grafana 实例后,数据源的 UID 对不上。解决办法是进入仪表盘设置,逐个检查面板的数据源是否都指向正确的 Prometheus;或者直接编辑仪表盘的 JSON Model,把datasource部分的uid改成当前数据源的 uid。理解了 UID 机制之后,这个报错就再也不会困扰你了。

还有一点:老面板里引用的一些指标在新版本 node_exporter 中可能已经改名,出现部分图表显示 No data 时,用 Grafana 的 Explore 页面手动查一下指标名,替换成新名字即可。

3.3 手写一个 CPU 使用率面板,搞懂 PromQL 核心

导入模板固然快,但想真正理解监控,最好自己动手画一个面板。拿最简单的“系统 CPU 使用率”举例。

新建 Dashboard -> Add visualization,数据源选 Prometheus,在 Query 编辑器里写:

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

这个查询的每个部分都要理解:

  • node_cpu_seconds_total是 CPU 各模式下的累计运行时间(计数器类型),mode="idle"过滤出空闲状态。
  • rate(..., 5m)计算该计数器在过去 5 分钟内每秒的增长量,换算过来就是空闲率。
  • avg by (instance)按主机分组取平均,因为一台机器通常有多颗 CPU 核心。
  • 100 - 空闲率,剩下的就是 CPU 使用率。

PromQL 初学者不需要背语法,掌握rate、increase、sum by、avg by这几个核心函数,就能覆盖绝大多数场景。rate处理计数器类型(累计值,如 CPU 时长、请求总数),gauge 类型(瞬时值,如当前内存使用量)直接用原始指标即可。一个是算增量,一个是看瞬时,这个区别是新手最容易搞混的地方。

面板右侧的设置里,Unit 选 Percent(0-100),Thresholds 标上告警色:80% 黄色,95% 红色。这样看板上一眼就能看出哪台机器 CPU 异常。

类似的常用表达式也可以顺手记下:

内存使用率:

(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100

根分区磁盘使用率:

100 - ((node_filesystem_avail_bytes{mountpoint="/"} * 100) / node_filesystem_size_bytes{mountpoint="/"})

需要强调一点:node_exporter 只能看到操作系统层面的资源使用情况。如果你想监控业务指标,比如接口 QPS、错误率、延迟分布,就需要在应用代码里引入 Prometheus 客户端库,自行暴露 /metrics 接口。Python 用 prometheus_client,Java 用 micrometer,Go 用 client_golang,都有非常成熟的支撑。

4. 接上 Alertmanager,让监控真正发挥价值

4.1 告警规则文件的写法,比想象中简单

监控不能光看着,还得在出事的时候通知到人。Prometheus 自身负责产生告警事件,规则用 YAML 描述。我习惯在/etc/prometheus/rules/下建一个node_alerts.yml:

groups: - name: node_alerts rules: - alert: InstanceDown expr: up == 0 for: 1m labels: severity: critical annotations: summary: "Instance {{ $labels.instance }} down" description: "{{ $labels.job }} 任务下的实例 {{ $labels.instance }} 已经不可达超过 1 分钟" - alert: HighCpuUsage expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90 for: 5m labels: severity: warning annotations: summary: "Instance {{ $labels.instance }} CPU 使用率过高" description: "当前 CPU 使用率已超过 90%,持续 5 分钟"

几个值得注意的点:

  • expr是告警触发条件,本质就是 PromQL 表达式。Prometheus 会按照evaluation_interval周期性地评估这些规则,所以从指标越界到真正推送告警,存在最多一个评估周期的延迟,这是设计如此,不是故障。
  • for表示触发条件必须持续多久才真正产生告警。强烈建议任何告警都加一个for,比如 CPU 短时间冲到 95% 可能只是某个定时任务瞬间占满,持续 5 分钟才说明真的出问题了,能有效过滤抖动。
  • labels里的severity用来给告警分级,方便 Alertmanager 对不同级别的告警走不同通知渠道。
  • annotations是告警的正文内容,支持$labels和$values模板变量,可以把具体的实例名、当前数值带进去。

写完规则后需要重载 Prometheus 配置:curl -X POST http://localhost:9090/-/reload。注意如果容器以非 root 用户运行,或者配置文件是只读挂载,reload 会失败,这个细节很容易忽略。

4.2 Alertmanager 部署与路由参数逐项解读

告警事件产生后,Prometheus 不会直接发邮件,而是推送给 Alertmanager,由它决定发给谁、怎么发。先加一个服务:

alertmanager: image: prom/alertmanager:v0.27.0 container_name: alertmanager ports: - "9093:9093" volumes: - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml restart: unless-stopped

然后在 prometheus.yml 里加上关联配置:

alerting: alertmanagers: - static_configs: - targets: ['alertmanager:9093']

alertmanager.yml 的核心是路由和接收器:

global: smtp_smarthost: 'smtp.example.com:465' smtp_from: 'monitor@example.com' smtp_auth_username: 'monitor@example.com' smtp_auth_password: 'password' smtp_require_tls: false route: group_by: ['alertname'] group_wait: 10s group_interval: 2m repeat_interval: 4h receiver: 'email-notify' routes: - matchers: - severity = critical receiver: 'email-notify-critical' receivers: - name: 'email-notify' email_configs: - to: 'team@example.com' send_resolved: true - name: 'email-notify-critical' email_configs: - to: 'oncall@example.com' send_resolved: true

路由里的四个参数是理解 Alertmanager 的钥匙,我详细说下:

  • group_by:按什么维度把告警合并成组。按alertname分组的意思是,同一种告警规则产生的多个实例告警会合并到一条通知里。否则整个机房 10 台机器同时掉线,你会瞬间收到 10 条内容几乎一样的邮件,体验非常糟糕。
  • group_wait:同一组内第一批告警的等待时间。设为 10 秒,是说第一批告警到达后等 10 秒,如果这段时间里有新告警进入同一组,会合并成一条发出去。
  • group_interval:一组告警已经发过通知后,再有新告警加入这一组,至少要间隔多久才发第二轮。要是网络抖动导致 100 台机器陆续掉线,这个参数决定了通知轰炸的节奏。
  • repeat_interval:同一条告警没有恢复时,隔多久重新通知一次。设 4 小时比较合理,过短会让人觉得天天被狼来了骚扰,过长可能错过故障状态的恶化。

send_resolved: true表示故障恢复后也要发一条“已恢复”通知。这个开关我建议一定打开,否则团队其他人不知道问题是不是已经解决,凌晨 3 点的告警可能一直到 10 点都还有人不敢动服务。

除了邮件,Alertmanager 还支持 webhook、企业微信、钉钉、Slack。webhook 最通用,Alertmanager 会以 JSON 格式 POST 到指定 URL,自己写几十行代码就能对接任意 IM 系统。我之前接企业微信机器人,就是写一个小的转发服务,把 Alertmanager 的 JSON 转成企业微信机器人支持的 markdown 格式,再 POST 到 webhook 地址,整个链路跑通之后,告警能直接推到手机端,比看邮件快得多。

4.3 告警链路怎么验证,以及误报控制

配置全部完成后,务必做一次完整的告警演练。最简单的方法:把 node_exporter 容器停掉,等 1 分钟左右,打开 Alertmanager 的 Web UIhttp://localhost:9093,如果没有意外,能看到一条 InstanceDown 告警状态为 Active。

如果没出现告警,按下面的顺序排查:

  1. Prometheus 的/rules页面看规则是否加载成功,规则文件语法错误会在这里直接暴露。
  2. Prometheus 的/alerts页面看规则当前状态,如果已经 fired,说明推送到 Alertmanager 的环节可能有问题,检查alerting配置段。
  3. Alertmanager 的/status页面看通知是否发送,邮件发送失败最常见的原因是 SMTP 端口选错:465 是隐式 TLS,587 是 STARTTLS,两者的 TLS 配置方式完全不同。

在告警配置上我吃过几次亏,分享三个经验:

  • 告警规则不要一上来就追求大而全。先把四条最基本的配上:实例存活、CPU 高、内存高、磁盘满。跑稳之后再逐步加业务告警。
  • 阈值要结合自己业务的基准线,不要照搬网上随便抄的 90%。有些服务的 CPU 常年 5% 波动,设 90% 就是废规则;另一些数据库到 60% CPU 就已经开始性能恶化了,设 90% 会错过最佳处理窗口。
  • 告警文案一定要写清楚“收到后该干嘛”。不要只写“CPU 高”,在annotations里把建议的排查命令写进去,比如top、pidstat、docker logs。凌晨三点收到告警时,多一句话能少走很多弯路。

5. 进阶方向:Kubernetes 集群监控和 OpenTelemetry 接入

5.1 玩 K8s 就别手动维护静态配置了

如果你已经跑在 Kubernetes 上,再手工维护 prometheus.yml 里的静态 target 列表不现实,因为 Pod 的 IP 是动态的,扩缩容随时发生。K8s 环境的监控,业界标准方案是 kube-prometheus-stack,一个 Helm Chart 打包了 Prometheus Operator、Alertmanager、Grafana 和各类通用 Exporter。

核心概念是 CRD:ServiceMonitor 和 PodMonitor。你可以声明一个 ServiceMonitor 对象来描述“我想监控哪个 Service 的哪些指标”,Prometheus Operator 会监听这些 CRD 的变更,自动生成 Prometheus 的采集配置:

apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: example-app namespace: monitoring spec: selector: matchLabels: app: example-app endpoints: - port: metrics interval: 30s

这套机制和静态配置完全不同:创建或删除 ServiceMonitor,采集目标就会自动增删,完全不需要 reload 配置。对自动伸缩频繁的 Kubernetes 环境来说,这是唯一合理的方案。

安装方式很简单:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack -n monitoring

装完之后用kubectl -n monitoring port-forward svc/kube-prometheus-stack-grafana 3000:80临时访问 Grafana,默认账号密码是 admin/prom-operator。集群节点的 CPU、内存、Pod 资源、API Server 状态这些核心指标,Chart 里已经自带仪表盘,不用重新配。

上生产环境前有几个参数必须改:一是存储持久化,默认 emptyDir 重启就丢数据,要挂到持久卷上;二是资源 limits,集群规模上来后 Prometheus 的内存占用会涨得很快,提前估算并调整;三是认证,Grafana 默认管理员密码要立刻换掉,通过 Ingress 对外暴露时建议加一层反向代理认证。

5.2 Prometheus 与 OpenTelemetry Collector 的配合方式

关于“Prometheus 是如何从 otel-collector 收取数据的”,这个问题其实不复杂。OpenTelemetry Collector 在这里的角色是数据网关:业务应用通过 OTLP 协议把指标推给 Collector,Collector 再通过 prometheus exporter 暴露一个 /metrics 端口,最后 Prometheus 像抓普通 target 一样来拉取。

关键配置片段:

receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: batch: exporters: prometheus: endpoint: 0.0.0.0:9091 namespace: app service: pipelines: metrics: receivers: [otlp] processors: [batch] exporters: [prometheus]

Prometheus 侧再加一个 target:

- job_name: 'otel-collector' static_configs: - targets: ['otel-collector:9091']

这个方案的精髓在于解耦。业务应用只关心怎么把 OTLP 数据发出去,完全不需要知道 Prometheus 的存在;Prometheus 也只看到一个标准的 /metrics 端点,对上游是什么完全无感。将来就算要把指标同时发给多个监控后端,也只是改 Collector 配置的事。相比 Pushgateway,这种方案没有单点问题,也没有“指标只增不删”的累积陷阱,是更值得长期投入的方向。

6. 高频问题和排查思路,直接抄作业

6.1 Grafana 数据源和仪表盘导入报错

最经典的报错就是开头提到的:

failed to upgrade legacy queries datasource ... was not found

一句话解释:仪表盘的 JSON 里声明了一个旧数据源引用,但导入到当前 Grafana 实例后,数据源的 UID 对不上。通常发生在从老版本 Grafana 导出模板,或者导入别人分享的旧面板时。

处理顺序:

  1. 先确认数据源本身可用:Configuration -> Data sources,点 Prometheus,Save & test。
  2. 打开仪表盘 Settings -> Variables,检查所有模板变量的数据源是否都指向正确的 Prometheus。
  3. 面板数量多时,直接编辑仪表盘 JSON:Settings -> JSON Model,搜索datasource,把uid改成当前数据源的 uid。当前 uid 可以在数据源列表页看到,是一串形如im7_otuvz的随机字符串。
  4. 还没解决就删掉数据源重新添加,让 Grafana 生成新的 uid,再回到面板重新关联。

理解了“Grafana 用随机 UID 引用数据源”这个机制,以后遇到同类报错都能自己定位。

6.2 指标抓取失败和存储膨胀

Prometheus 采集失败的典型表现是 /targets 页面上显示 DOWN,或者查询时看不到数据。排查顺序:

  • curl http://目标IP:端口/metrics直接访问,确认 exporter 是不是活着。node_exporter 默认 9100,cAdvisor 默认 8080,mysqld_exporter 默认 9104,端口别搞混。
  • 检查防火墙和云安全组。很多云服务器默认安全组只放行 80/443/22,9100 这类端口不显式放行的话,外网永远抓不到。
  • 能访问但 Prometheus 一直报context deadline exceeded,多半是网络延迟太高导致抓取超时,可以在scrape_configs里单独调大scrape_timeout,或者把 exporter 挪到离 Prometheus 更近的网络区域。
  • 检查时间同步。Prometheus 的采样和查询非常依赖时间戳,被监控机和监控机之间时钟漂移过大,会出现各种奇怪现象。生产环境必须配置 NTP。

存储膨胀的排查方向:采集了太多无用的指标、保留时间过长、标签基数失控。最后这一点最致命:如果把请求 URL 直接作为 label,URL 千变万化,Prometheus 内存直接爆掉。设计指标时务必控制标签值集合的规模,不要在 label 里放高基数数据。

6.3 Docker 镜像拉取失败的应对

部署阶段最常见的拦路虎就是镜像拉不下来。我实测有效的办法有三个:

  1. 配置 registry-mirrors。编辑/etc/docker/daemon.json:
{ "registry-mirrors": ["https://你选择的加速地址"] }

然后systemctl restart docker。不同网络环境下各加速地址的可用性差异很大,没有万能地址,需要自己测试。

  1. 同步到内部镜像仓库。如果公司有 Harbor 或者其它内网仓库,把需要的外部镜像一次同步进去,然后 pull 时指定内网地址。这是长期最稳定、最推荐的做法。等你被外部网络问题折磨过几次就会明白,内部镜像仓库才是生产环境的正解。

  2. 直接用二进制包。Prometheus、Grafana、node_exporter 都有官方 tar.gz 包,解压就能跑,完全不依赖容器网络。小规模实验环境够用。

6.4 时区、时间线偏移等小坑

  • Grafana 面板默认使用服务器时区,服务器是 UTC 的话,图表上的时间会整体偏 8 小时。在 Grafana 的 Default preferences 里把 timezone 设为 Asia/Shanghai,问题立刻消失。
  • 计数器类型指标在进程重启后可能出现rate负值,这不是配置错误,是计数器重置导致的,用increase()或者调整窗口可以平滑掉。
  • Grafana 里接了多个数据源时,每个面板都要确认数据源选择,否则会出现“明明 Prometheus 里有指标,面板却显示 No data”的怪象。

7. 后续值得深耕的几个实战方向

到这里,一套能用的监控体系已经跑通了。再往后走,根据你自己的情况,有三条路可以选一条深入。

第一条是把监控体系产品化。把告警规则、仪表盘配置、采集配置全部代码化,放到 Git 仓库统一管理。新项目接入监控时,拉取模板,改几个变量,就能自动生成一整套仪表盘和告警规则。这能极大减少重复劳动,也让整个团队的监控水位保持一致。

第二条是数据成本治理。Prometheus 指标数量增长非常快,很多指标其实从来没人查询过。可以通过 recording rules 对高频查询做预聚合,或者用 remote write 把冷数据转储到对象存储,控制本地 TSDB 的容量。监控系统搭建起来只是开始,持续运营才是长期课题。

第三条是往业务指标走。基础设施监控做到位之后,更有价值的其实是接口成功率、订单量、付款用户数这类业务指标。把这些从业务库或日志里算出来,暴露成 Prometheus 指标,和基础设施指标放进同一个 Grafana,老板问数据的时候打开大屏就能讲清楚。这才是监控体系从“技术工具”走向“业务支撑”的分水岭。

再分享一个我自己养成的小习惯:每次新上一个服务,都强制自己先回答三个问题才准上线。第一,这个服务的核心指标是什么,怎么量化“它正常在干活”?第二,它挂了会先影响谁,那个人靠什么感知到?第三,如果指标出现异常,我第一步去哪里查?把这三个问题想明白了,监控体系的架构就会自然浮出来,剩下的只是照着方案填 Prometheus 配置而已。

如果你正准备从零开始搭,我的建议很简单:先按这篇文章把单机版跑起来,导入 Node Exporter Full 面板,配上 CPU、内存、磁盘、存活四条告警,用一个月。等你习惯了每天花五分钟看一眼仪表盘,再慢慢往上加业务指标和自动扩展。监控这件事,不怕起步小,就怕一直停留在收藏了无数教程、但从未真正跑通过一次。

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

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

立即咨询