Prometheus/Grafana 监控体系:从指标采集到告警设计,全链路可观测性实战

一、监控的盲区:有指标无洞察
很多团队的监控体系是"指标堆砌"——部署了 Prometheus 和 Grafana,采集了数百个指标,搭建了几十个仪表盘,但故障发生时仍然无法快速定位。根本原因是监控设计缺少"问题导向"——采集了指标但没有定义什么是异常,搭建了仪表盘但没有设计告警规则。
更深层的问题是指标粒度的错配。CPU 使用率是节点级指标,无法反映单个容器的资源竞争;请求延迟是服务级指标,无法区分是哪个接口变慢。缺少请求级别的上下文(如 trace ID),指标和日志之间无法关联,排查时需要在多个工具之间反复切换。
二、监控体系架构设计
flowchart TD
A[应用/基础设施] –> B[指标采集层]
B –> B1[Prometheus: 拉取式采集]
B –> B2[Pushgateway: 短任务推送]
B –> B3[Exporter: 第三方集成]
B1 –> C[指标存储层]
C –> C1[本地存储: TSDB]
C –> C2[远程存储: Thanos/Cortex]
C1 –> D[可视化层]
C2 –> D
D –> D1[Grafana: 仪表盘]
D –> D2[告警规则: AlertManager]
D2 –> E[告警分发]
E –> E1[Slack/钉钉]
E –> E2[PagerDuty/电话]
2.1 指标设计与采集
# prometheus.yml — Prometheus 配置
# 设计意图:配置采集目标和告警规则,
# 覆盖基础设施、应用和业务三个维度
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: 'production'
env: 'prod'
# 告警规则文件
rule_files:
– 'alerts/*.yml'
# 采集目标
scrape_configs:
# Kubernetes 集群指标
– job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
– role: node
relabel_configs:
– source_labels: [__address__]
regex: '(.*):10250'
replacement: '${1}:9100'
target_label: __address__
# 应用指标(Pod 注解自动发现)
– job_name: 'kubernetes-pods'
kubernetes_sd_configs:
– role: pod
relabel_configs:
– source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
– source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
2.2 告警规则设计
# alerts/service-alerts.yml — 服务告警规则
# 设计意图:基于 SLI/SLO 设计告警,避免告警噪声
groups:
– name: service_slo
rules:
# SLO 违规告警:5分钟内错误率超过 1%
– alert: HighErrorRate
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/ sum(rate(http_requests_total[5m])) by (service)
) > 0.01
for: 2m
labels:
severity: critical
team: sre
annotations:
summary: "服务 {{ $labels.service }} 错误率过高"
description: "5xx 错误率 {{ $value | humanizePercentage }},超过 1% SLO 阈值"
# 延迟 SLO 告警:P99 延迟超过 500ms
– alert: HighLatency
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (service, le)
) > 0.5
for: 5m
labels:
severity: warning
team: sre
annotations:
summary: "服务 {{ $labels.service }} P99 延迟过高"
description: "P99 延迟 {{ $value }}s,超过 500ms SLO 阈值"
# Pod 重启告警
– alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0
for: 5m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 频繁重启"
# 资源饱和告警:CPU 节流
– alert: CPUThrottling
expr: |
rate(container_cpu_cfs_throttled_periods_total[5m])
/ rate(container_cpu_cfs_periods_total[5m]) > 0.5
for: 10m
labels:
severity: warning
annotations:
summary: "容器 {{ $labels.container }} CPU 节流超过 50%"
description: "考虑增加 CPU limits 或优化 CPU 使用"
2.3 Grafana 仪表盘配置
{
"dashboard": {
"title": "服务 SLI 仪表盘",
"panels": [
{
"title": "请求速率 (QPS)",
"type": "timeseries",
"targets": [
{
"expr": "sum(rate(http_requests_total[5m])) by (service)",
"legendFormat": "{{service}}"
}
]
},
{
"title": "错误率",
"type": "timeseries",
"targets": [
{
"expr": "sum(rate(http_requests_total{status=~\\"5..\\"}[5m])) by (service) / sum(rate(http_requests_total[5m])) by (service)",
"legendFormat": "{{service}}"
}
],
"thresholds": [
{ "value": 0.01, "color": "red" }
]
},
{
"title": "P99 延迟",
"type": "timeseries",
"targets": [
{
"expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (service, le))",
"legendFormat": "{{service}}"
}
]
}
]
}
}
三、告警路由与升级
3.1 AlertManager 配置
# alertmanager.yml — 告警路由与升级配置
# 设计意图:根据告警严重程度和团队分配路由,
# 支持告警抑制和升级
global:
resolve_timeout: 5m
route:
group_by: ['service', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'slack-default'
routes:
# Critical 告警:电话 + Slack
– match:
severity: critical
receiver: 'pagerduty-critical'
repeat_interval: 1h
# Warning 告警:Slack
– match:
severity: warning
receiver: 'slack-warning'
repeat_interval: 4h
receivers:
– name: 'slack-default'
slack_configs:
– api_url: 'https://hooks.slack.com/services/xxx'
channel: '#alerts'
title: '{{ .GroupLabels.service }}: {{ .CommonAnnotations.summary }}'
– name: 'pagerduty-critical'
pagerduty_configs:
– service_key: 'xxx'
severity: 'critical'
– name: 'slack-warning'
slack_configs:
– api_url: 'https://hooks.slack.com/services/xxx'
channel: '#alerts-warning'
# 告警抑制规则
inhibit_rules:
# 如果服务有 Critical 告警,抑制同服务的 Warning 告警
– source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['service']
四、边界分析与架构权衡
指标基数爆炸:高基数标签(如 user_id、request_id)会导致 Prometheus 的 TSDB 急剧膨胀。每个唯一的标签组合创建一个时间序列,百万级用户意味着百万级时间序列。解决方案是移除高基数标签,或在查询时聚合。
告警疲劳:过多的告警导致运维团队忽视告警,包括真正严重的告警。需要严格控制告警数量——只对 SLO 违规告警,不对中间指标告警。每个告警必须有明确的操作指南,无法操作的告警应删除。
远程存储的查询延迟:Thanos/Cortex 等远程存储的查询延迟远高于本地 TSDB。长时间范围的查询(如 30 天趋势)可能需要数十秒。需要在查询性能和存储成本之间权衡——热数据存本地,冷数据存远程。
Grafana 仪表盘的维护:仪表盘数量随服务增长而膨胀,很多仪表盘创建后无人维护,查询语句过时导致数据不准确。需要建立仪表盘的生命周期管理——定期审查、归档过时仪表盘。
五、总结
Prometheus/Grafana 监控体系的核心是"问题导向而非指标导向"——基于 SLO 设计告警规则,基于故障场景设计仪表盘,基于团队职责设计路由策略。关键实践包括:SLO 违规触发告警而非阈值触发,告警抑制减少噪声,分级路由确保 Critical 告警不被遗漏。但指标基数、告警疲劳、远程存储延迟和仪表盘维护是需要权衡的边界条件。落地建议:从 SLO 定义开始设计监控;告警只保留可操作的;高基数标签在采集时移除;仪表盘定期审查归档。
补充落地建议:围绕“Prometheus/Grafana 监控体系:从指标采集到告警设计,全链路可观测性实战”继续推进时,应把验证标准写成可执行清单,而不是停留在经验判断。性能类方案要给出基准数据,架构类方案要给出故障隔离方式,AI 类方案要给出输出质量和人工兜底策略。每一次迭代都应回答三个问题:收益是否可量化,失败是否可回滚,维护成本是否被团队接受。
如果短期资源有限,可以先保留最关键的观测指标,包括处理耗时、失败率、资源占用和人工介入次数。等这些指标稳定后,再扩展自动化能力。这样的节奏更慢,但风险更低,也更符合生产级技术文章强调的工程可验证性。



