Prometheus + Grafana 云原生监控告警实战:从指标采集到可视化大盘与告警规则完整指南
监控是系统稳定运行的"眼睛"。当服务从单机走向容器化、微服务化之后,传统靠人工 top 看一眼的方式彻底失效:实例动态扩缩、IP 随时漂移、调用链跨几十个服务。本文以 Prometheus + Grafana + Alertmanager 这套云原生事实标准监控栈为主线,带你从零搭建一套"采集 → 存储 → 查询 → 可视化 → 告警"的完整体系,并给出可直接抄进生产环境的配置。
一、为什么是 Prometheus
在微服务与 Kubernetes 场景下,监控对象有两个特征:数量多、生命周期短。这带来三个核心诉求:
- 自动发现:新实例上线要能被自动纳入监控,而不是改配置文件。
- 高维数据模型:能用
服务名 / 实例 / 接口 / 状态码等多维度自由切片。 - 拉取模型 + 时序存储:统一从目标抓取指标,天然适合做趋势与告警。
Zabbix 这类基于 Agent 主动上报 + 关系型存储的方案,在标签维度爆炸和动态拓扑面前力不从心;而 Prometheus 的 Pull + TSDB + Label 设计正好命中痛点,因此成为 CNCF 毕业项目中采用率最高的监控系统。
二、Prometheus 核心架构与数据模型
Prometheus 采用拉取(Pull)模型:服务端周期性地访问各目标暴露的 /metrics HTTP 端点,抓取文本格式的指标。一条完整的指标由三部分构成:
- Metric Name(指标名):如
http_requests_total。 - Label(标签键值对):如
{method="POST", status="200", instance="10.0.0.3:8080"},维度就来自这里。 - Sample(样本):由时间戳 + 浮点数值组成,即
(timestamp, value)。
关键纪律:标签的**基数(cardinality)**要可控。千万不要把 `user_id`、`order_id` 这种取值无限多的字段做成标签,否则 TSDB 内存和磁盘会被瞬间打爆。
一次抓取的数据流如下:
Exporter/App (/metrics)
│ Pull (HTTP)
▼
Prometheus Server ──▶ TSDB 本地时序库
│ │
│ PromQL 查询 │ 远程写(可选)
▼ ▼
Grafana 可视化 VictoriaMetrics / Thanos
│
▼
Alertmanager ──▶ 钉钉 / 邮件 / Webhook
三、快速部署:docker-compose 一键拉起
先写 prometheus.yml,定义抓取目标与频率:
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: prod-cn
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ['localhost:9090']
- job_name: node
static_configs:
- targets: ['node-exporter:9100']
- job_name: app
# 配合 K8s 时改用 kubernetes_sd_configs 做服务发现
static_configs:
- targets: ['app:8080']
再用 docker-compose.yml 编排 Prometheus 与 Node Exporter:
version: '3'
services:
prometheus:
image: prom/prometheus:v2.53.0
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prom-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=15d'
node-exporter:
image: prom/node-exporter:v1.8.0
container_name: node-exporter
ports:
- "9100:9100"
volumes:
prom-data:
启动后访问 http://localhost:9090,在 Graph 页输入 up 就能看到所有目标的存活状态——up == 1 表示抓取成功,up == 0 意味着目标下线或端口不通。
四、指标采集:Exporter 与自定义埋点
大多数中间件官方或社区都提供了 Exporter,直接挂上即可:
- node-exporter:主机 CPU、内存、磁盘、网络。
- mysqld-exporter / redis-exporter:数据库内部指标。
- cadvisor / kube-state-metrics:容器与 K8s 对象状态。
业务应用自身也要埋点。以 Go 为例,暴露一个 HTTP 请求计数器:
var httpReqTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "HTTP 请求总量",
},
[]string{"method", "status"},
)
func init() {
prometheus.MustRegister(httpReqTotal)
}
func handler(w http.ResponseWriter, r *http.Request) {
httpReqTotal.WithLabelValues(r.Method, "200").Inc()
w.Write([]byte("ok"))
}
func main() {
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8080", nil)
}
Python(Prometheus Client)同理:
from prometheus_client import Counter, start_http_server
import time
REQ = Counter("http_requests_total", "请求总数", ["method", "status"])
start_http_server(8080)
while True:
REQ.labels(method="GET", status="200").inc()
time.sleep(1)
五、PromQL 查询语言实战
PromQL 是 Prometheus 的灵魂。几个最常用、也最容易被用错的函数:
| 函数 | 作用 | 典型用法 |
|---|---|---|
| `rate()` | 区间内的平均每秒增长率(自动去毛刺) | `rate(http_requests_total[5m])` |
| `irate()` | 只取区间首尾两个点,更灵敏 | `irate(http_requests_total[5m])` |
| `histogram_quantile()` | 计算分位数延迟 | `histogram_quantile(0.95, ...)` |
| `sum by()` | 按标签聚合 | `sum by (instance) (rate(...))` |
几个高频实战查询:
# 1. QPS(按接口聚合)
sum by (method) (rate(http_requests_total[5m]))
# 2. 错误率(5xx 占比)
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
# 3. P95 接口延迟(假设用了 histogram 指标 http_request_duration_seconds)
histogram_quantile(0.95,
sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
# 4. 节点 CPU 使用率
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
经验法则:看趋势、画图的报表用 `rate`;做实时灵敏度要求高的告警阈值可酌情用 `irate`,但注意 `irate` 在区间内有数据缺失时会显得很跳。
六、Grafana 可视化大盘
Grafana 负责把 PromQL 查询结果变成好看的面板。接入步骤:
- 添加数据源:
Configuration → Data Sources → Prometheus,URL 填http://prometheus:9090。 - 新建 Dashboard,每个 Panel 的查询框直接写 PromQL。
- 推荐直接导入社区成熟模板:Node Exporter 官方模板
1860,K8s 集群模板6417,改改数据源即可用。
一个典型的"服务健康度"大盘应包含:QPS、P95/P99 延迟、错误率、实例 CPU/内存、GC 停顿。把核心 SLO(如错误率 < 0>
七、告警体系:Alertmanager 实战
可视化让人"看见"问题,告警让人"被通知"问题。告警分两层:Prometheus 负责判定规则,Alertmanager 负责路由与分发。
在 prometheus.yml 中挂载规则文件:
rule_files:
- /etc/prometheus/rules/*.yml
编写 rules/alert.yml:
groups:
- name: service-alerts
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m])) > 0.05
for: 10m
labels:
severity: critical
annotations:
summary: "服务错误率超过 5%(持续 10 分钟)"
description: "当前错误率 {{ $value | humanizePercentage }}"
- alert: InstanceDown
expr: up == 0
for: 2m
labels:
severity: warning
annotations:
summary: "实例 {{ $labels.instance }} 已下线"
for: 10m 表示条件持续 10 分钟才真正触发,避免瞬时抖动产生误报——这是生产环境减少"告警疲劳"的关键。
Alertmanager 配置化路由与通知渠道:
route:
receiver: dingtalk
group_by: ['alertname', 'instance']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- match:
severity: critical
receiver: dingtalk
receivers:
- name: dingtalk
webhook_configs:
- url: https://oapi.dingtalk.com/robot/send?access_token=xxxx
进阶:用 `inhibit_rules` 做告警抑制——比如"实例宕机"的告警触发后,自动抑制该实例上的"错误率过高"告警,避免一条根因引发一堆连锁噪音。
八、生产级最佳实践
- 长期存储:单机 Prometheus 本地 TSDB 建议保留 15–30 天。需要长期留存或跨集群聚合时,用 Thanos 或 VictoriaMetrics 做远程写与全局查询。
- 标签基数治理:定期用
prometheus_tsdb_head_series监控序列总量,对高基数标签做降维(如把path改为有限的route模板)。 - 高可用:Prometheus 本身无内置 HA,采用"双副本采集 + 上层 Thanos/VictoriaMetrics 去重"是主流方案。
- 告警分级:
warning走 IM 通知,critical同时打电话/短信,并接入值班轮转(如 Grafana OnCall)。 - 配置即代码:
prometheus.yml、rules、dashboards全部纳入 Git,配合 CI 做规则语法校验,变更可回溯。
九、总结
本文梳理了一条从 0 到生产的监控告警主线:用 Exporter / 自定义埋点采集指标,Prometheus 以 Pull + TSDB 存储,靠 PromQL 灵活查询,Grafana 做可视化大盘,Alertmanager 完成分级告警与路由。真正落地时,记住三句话——标签基数要克制、for 阈值要留缓冲、配置全部进 Git。把这套体系搭稳,系统的每一次异常都会第一时间"自己喊出来"。
下一篇可延展方向:Thanos 全局视图搭建、eBPF 无侵入采集、或 OpenTelemetry 统一 Trace/Metric/Log。欢迎在评论区点单。

发表评论 取消回复