云原生可观测性体系构建:Prometheus + Grafana 全栈监控方案设计与落地

一、监控盲区导致的生产故障:从"不知道出问题了"到"提前发现问题"
一次线上事故的复盘会上,团队发现一个尴尬的事实:数据库连接池在故障前 30 分钟就已经开始缓慢耗尽,但监控面板上没有任何告警触发。原因很简单——只监控了 CPU 和内存,没有覆盖连接池、线程池等应用层指标。监控体系存在盲区,等于在黑夜里开车没有仪表盘。
云原生环境下的监控挑战更大:服务数量多、调用链路长、容器生命周期短。传统的 Zabbix Agent 模式已经无法适应动态调度的容器环境。本文将给出一套基于 Prometheus + Grafana 的全栈监控方案,覆盖基础设施、中间件、应用层三个维度。
二、Prometheus 监控数据流与多维度采集架构
Prometheus 采用拉取(Pull)模式采集指标,通过 Service Discovery 自动发现监控目标。在 K8s 环境中,这一机制天然适配动态扩缩容场景。
flowchart TD
subgraph 采集层
A1[Node Exporter<br/>节点指标]
A2[cAdvisor<br/>容器指标]
A3[kube-state-metrics<br/>K8s 资源指标]
A4[应用 /metrics<br/>业务指标]
A5[Blackbox Exporter<br/>探测指标]
A6[中间件 Exporter<br/>MySQL/Redis/Kafka]
end
subgraph 存储层
B1[Prometheus Server<br/>短期存储]
B2[Thanos/VM<br/>长期存储]
end
subgraph 展示与告警层
C1[Grafana Dashboard]
C2[Alertmanager<br/>告警路由]
C3[钉钉/企微/邮件]
end
A1 & A2 & A3 & A4 & A5 & A6 -->|HTTP Pull| B1
B1 -->|远程写入| B2
B1 --> C1
B1 -->|告警规则| C2
B2 --> C1
C2 --> C3
关键设计决策:
- 采集频率:默认 15s,核心服务可缩短到 10s。频率越高存储压力越大,需要权衡。
- 标签设计:标签是 Prometheus 数据模型的核心。必须统一标签命名规范,如
env、service、instance、namespace。避免高基数标签(如 user_id),否则会导致时间线爆炸。 - 联邦架构:大规模集群采用联邦模式,分片 Prometheus 各自采集,全局 Prometheus 汇聚关键指标。
三、全栈监控配置与最佳实践
3.1 Prometheus 核心配置
# prometheus.yml - 生产级配置
global:
scrape_interval: 15s # 默认采集间隔
evaluation_interval: 15s # 规则评估间隔
scrape_timeout: 10s # 采集超时
external_labels:
cluster: "prod-cluster-01" # 集群标识,用于联邦汇聚
env: "production"
# K8s 服务自动发现
scrape_configs:
# 采集 K8s 节点指标
- job_name: "kubernetes-nodes"
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__meta_kubernetes_node_name]
target_label: node
metric_relabel_configs:
# 过滤无用指标,降低存储开销
- source_labels: [__name__]
regex: "node_cpu_.*|node_memory_.*|node_disk_.*|node_network_.*"
action: keep
# 采集带注解的应用 Pod
- job_name: "kubernetes-pods"
kubernetes_sd_configs:
- role: pod
relabel_configs:
# 只采集带有 prometheus.io/scrape 注解的 Pod
- 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: (.+)
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
# 远程写入长期存储
remote_write:
- url: "http://thanos-receive:19291/api/v1/receive"
queue_config:
max_samples_per_send: 10000
max_shards: 10
batch_send_deadline: 5s
# 告警规则文件
rule_files:
- "/etc/prometheus/rules/*.yml"
3.2 多维度告警规则
# 基础设施告警
groups:
- name: infrastructure-alerts
rules:
# 节点 CPU 使用率持续高
- alert: NodeCPUHigh
expr: |
100 - (avg by (node) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
for: 10m
labels:
severity: warning
team: infra
annotations:
summary: "节点 {{ $labels.node }} CPU 使用率超过 85%"
runbook: "https://wiki.internal/runbook/node-cpu-high"
# 节点内存压力
- alert: NodeMemoryPressure
expr: |
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 90
for: 5m
labels:
severity: critical
team: infra
annotations:
summary: "节点 {{ $labels.node }} 内存使用率超过 90%"
# 应用层告警
- name: application-alerts
rules:
# HTTP 错误率飙升
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/ sum(rate(http_requests_total[5m])) by (service) > 0.05
for: 3m
labels:
severity: critical
team: app
annotations:
summary: "服务 {{ $labels.service }} 5xx 错误率超过 5%"
# P99 延迟异常
- alert: HighLatencyP99
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
) > 2
for: 5m
labels:
severity: warning
team: app
annotations:
summary: "服务 {{ $labels.service }} P99 延迟超过 2s"
# 中间件告警
- name: middleware-alerts
rules:
# Redis 连接池耗尽
- alert: RedisConnPoolExhausted
expr: |
redis_connected_clients / redis_config_maxclients > 0.8
for: 3m
labels:
severity: critical
team: middleware
annotations:
summary: "Redis {{ $labels.instance }} 连接数超过最大连接数的 80%"
# Kafka 消费延迟
- alert: KafkaConsumerLag
expr: |
kafka_consumer_group_lag > 100000
for: 10m
labels:
severity: warning
team: middleware
annotations:
summary: "Kafka 消费组 {{ $labels.group }} 延迟超过 10万条"
3.3 Alertmanager 告警路由配置
# alertmanager.yml - 告警路由与降噪
global:
resolve_timeout: 5m
route:
group_by: ["alertname", "namespace", "service"]
group_wait: 30s # 同组告警等待合并时间
group_interval: 5m # 同组新告警发送间隔
repeat_interval: 4h # 重复告警发送间隔
receiver: "default"
routes:
# 严重告警立即通知
- match:
severity: critical
receiver: "critical-channel"
group_wait: 10s
repeat_interval: 1h
# 基础设施告警发送到运维组
- match:
team: infra
receiver: "infra-channel"
# 应用告警发送到开发组
- match:
team: app
receiver: "app-channel"
receivers:
- name: "default"
webhook_configs:
- url: "http://alert-gateway:8080/api/alert"
- name: "critical-channel"
webhook_configs:
- url: "http://alert-gateway:8080/api/alert/critical"
- name: "infra-channel"
webhook_configs:
- url: "http://alert-gateway:8080/api/alert/infra"
- name: "app-channel"
webhook_configs:
- url: "http://alert-gateway:8080/api/alert/app"
# 告警抑制规则:节点宕机时抑制该节点上的所有告警
inhibit_rules:
- source_match:
alertname: NodeDown
target_match:
severity: warning
equal: ["node"]
3.4 应用埋点规范(Python 示例)
from prometheus_client import Counter, Histogram, Gauge, generate_latest
from functools import wraps
import time
# 请求计数器
http_requests_total = Counter(
"http_requests_total",
"HTTP 请求总数",
["method", "endpoint", "status"]
)
# 请求延迟直方图
http_request_duration_seconds = Histogram(
"http_request_duration_seconds",
"HTTP 请求延迟",
["method", "endpoint"],
buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]
)
# 业务指标:活跃连接数
active_connections = Gauge(
"active_connections",
"当前活跃连接数",
["service"]
)
def monitor_request(endpoint: str):
"""请求监控装饰器,自动记录请求计数和延迟"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
status = "200"
try:
result = func(*args, **kwargs)
return result
except Exception as e:
status = "500"
raise e
finally:
duration = time.time() - start
http_requests_total.labels(
method="GET", endpoint=endpoint, status=status
).inc()
http_request_duration_seconds.labels(
method="GET", endpoint=endpoint
).observe(duration)
return wrapper
return decorator
四、监控方案的架构代价与适用边界
Pull 模式的网络限制:Prometheus 的 Pull 模式要求 Server 能访问所有 Target。在跨网络、跨集群场景下,需要额外部署 Pushgateway 或使用 Thanos 的 Sidecar 模式。Pushgateway 适合短生命周期任务,但不适合长期运行的指标推送。
存储成本与查询性能:Prometheus 本地存储(TSDB)默认保留 15 天数据。长期存储需要接入 Thanos 或 VictoriaMetrics。高基数指标(如每个用户一条时间线)会导致存储膨胀和查询超时,必须严格控制标签基数。
告警规则的维护成本:随着业务增长,告警规则会不断膨胀。缺乏统一管理的规则容易出现冲突和冗余。建议将告警规则代码化,纳入 Git 管理,通过 CI/CD 自动同步到 Prometheus。
Grafana 面板的碎片化:不同团队各自创建面板,缺乏统一规范,导致面板重复且难以维护。建议建立面板模板库,统一命名和布局规范。
联邦架构的查询延迟:全局 Prometheus 通过联邦采集下级数据时,查询延迟会随分片数量增加而上升。对于大规模集群,建议直接查询 Thanos Query,利用 Store Gateway 并行查询。
五、总结
构建云原生可观测性体系,核心是建立"指标采集 → 告警触发 → 面板展示"的完整闭环。技术选型上,Prometheus + Grafana 是当前最成熟的组合,但需要关注存储成本和查询性能的长期演进。
落地路线建议:第一步,部署 Prometheus + Node Exporter + cAdvisor,覆盖基础设施监控;第二步,接入 kube-state-metrics 和中间件 Exporter,补齐平台层监控;第三步,推动应用埋点,覆盖业务指标;第四步,完善告警规则和路由策略,实现分级告警;第五步,接入 Thanos 实现长期存储,建立全局视图。每一步都要以"能发现问题"为验收标准,避免监控数据堆砌而告警能力不足。

1060

被折叠的 条评论
为什么被折叠?



