3. Prometheus 基础:架构设计、数据模型、Pull vs Push 模式
好,咱们进入监控体系的核心环节——Prometheus。说实话,在云原生时代,Prometheus 几乎成了监控的事实标准。我最早接触它是在 2017 年,当时还在用 Zabbix 和 Open-Falcon,第一次看到 Prometheus 的 Pull 模型,心里想:这玩意儿能行吗?后来真香了。
3.1 整体架构:一张图看懂 Prometheus
先看整体架构。Prometheus 不是一个大而全的“全家桶”,它更像一个生态。核心组件就那么几个,但配合起来非常灵活。
核心思想:Prometheus 主动去“拉”数据,而不是等数据“推”过来。这个设计决策,影响了整个监控体系的构建方式。
你看这个图,Prometheus Server 是的核心。它负责三件事:拉数据、存数据、算告警。左侧是各种 exporter,也就是被监控的目标。右侧是消费端,Alertmanager 管告警分发,Grafana 管可视化。
3.2 数据模型:时间序列是核心
Prometheus 的数据模型,说白了就是“带标签的时间序列”。这个概念非常重要,你理解了这个,后面写 PromQL 就顺了。
每条数据长这样:
<metric_name>{<label_name>=<label_value>, ...} value timestamp
举个例子:
http_requests_total{method="GET", endpoint="/api/v1/users", status="200"} 1024 1700000000
这里 http_requests_total 是指标名,花括号里是标签,后面是值和时间戳。我刚开始用的时候,总觉得标签就是“可选的元数据”。后来踩了坑才明白——标签决定了时间序列的唯一性。
我曾经踩过的坑:标签值不要用高基数(high cardinality)的数据,比如 user_id、request_id。每个不同的标签值都会产生一条新的时间序列,如果用户 ID 有 100 万,你的 Prometheus 内存就炸了。我见过有人把 session_id 当标签,结果 10 分钟就把 32G 内存打满了。
Prometheus 的数据模型有四种指标类型:
| 类型 | 说明 | 典型场景 |
|---|---|---|
| Counter | 只增不减的计数器 | 请求总数、错误总数、CPU 时间 |
| Gauge | 可增可减的测量值 | 内存使用率、当前连接数、温度 |
| Histogram | 分桶直方图,统计分布 | 请求延迟分布、响应大小分布 |
| Summary | 类似 Histogram,但计算分位数 | 请求延迟的 p99、p95 |
个人建议:能用 Counter 就别用 Gauge。Counter 的语义更清晰,而且可以计算速率(rate),这是监控中最常用的操作。我习惯把所有“累计值”都用 Counter 表示,比如 http_requests_total、db_queries_total。
3.3 Pull vs Push:为什么 Prometheus 选择了 Pull?
这个问题,面试经常问,实际选型也经常纠结。我聊聊我的理解。
Pull 模式:Prometheus Server 主动去目标地址拉取指标。目标只需要暴露一个 HTTP 端点(通常是 /metrics)。
Push 模式:目标主动把指标推送到中心收集器。比如 Graphite、OpenTSDB、InfluxDB 都支持 Push。
为什么 Prometheus 选了 Pull?
- 健康检查更自然:拉不到数据,说明目标挂了。Push 模式下,收不到数据可能是网络问题,也可能是目标挂了,你分不清。
- 控制权在服务端:你可以控制拉取频率,避免被突发的 Push 流量冲垮。我在项目中遇到过,某个业务模块突然疯狂 Push 数据,直接把收集器打挂了。
- 更容易做安全控制:只需要在服务端配置认证,不需要每个目标都配。
- 天然支持静态发现:配置文件里写死目标地址,简单粗暴有效。
但 Pull 模式也有短板:
- 无法穿透 NAT/防火墙:如果目标在私有网络里,Prometheus 拉不到。这时候需要 Pushgateway 做中转。
- 不适合短生命周期任务:比如批处理任务、CronJob,跑完就没了,Prometheus 还没拉到数据呢。
我的经验:80% 的场景用 Pull 就够了。剩下的 20%,用 Pushgateway 或者 Prometheus 的 remote write 来解决。别一上来就全上 Push,那是给自己找麻烦。
3.4 服务发现:动态环境下的必备能力
在 Kubernetes 里,Pod 的 IP 是动态的。你不可能手动写死每个 Pod 的地址。这时候就需要服务发现。
Prometheus 支持多种服务发现机制:
| 发现方式 | 适用场景 | 配置复杂度 |
|---|---|---|
| 静态配置 | 小规模、固定目标 | 低 |
| Kubernetes SD | K8s 集群 | 中 |
| Consul SD | 服务注册中心 | 中 |
| DNS SD | 基于 DNS 的服务发现 | 低 |
| 文件 SD | 自定义、灵活 | 中 |
我个人最常用的是 Kubernetes SD。配置起来其实不复杂:
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
action: keep
regex: my-app
这段配置的意思是:发现所有 K8s Pod,只保留标签 app=my-app 的 Pod 作为抓取目标。嗯,这里要注意,relabel_configs 是 Prometheus 里非常强大的功能,你可以用它来过滤、修改、增加标签。
避坑指南:我曾经在配置 Kubernetes SD 时,忘了设置 __metrics_path__,结果 Prometheus 一直去抓 /metrics,但我的应用暴露在 /actuator/prometheus。折腾了半天才发现。记得检查默认路径。
3.5 存储与数据保留
Prometheus 的本地存储是自研的 TSDB,设计得非常高效。它按 2 小时为一个 block 存储数据,每个 block 包含多个文件。
存储配置很简单:
--storage.tsdb.path=/data/prometheus
--storage.tsdb.retention.time=15d
--storage.tsdb.retention.size=50GB
这里我建议两个参数都设上。只设时间,万一数据量暴增,磁盘可能撑爆。只设大小,可能数据保留时间不够。两个一起设,谁先到就按谁执行。
注意:Prometheus 本地存储是单机的,不适合做长期存储。如果你需要保留 30 天以上的数据,建议用 Thanos 或 VictoriaMetrics 做远端存储。我一般把 Prometheus 本地存 7 天,远端存 6 个月。
3.6 小结
Prometheus 的架构设计,核心就是“主动拉取 + 标签化时间序列”。这个设计让它非常适合云原生环境。Pull 模式给了你控制权,标签模型给了你灵活性,服务发现解决了动态性问题。