3、Prometheus基础:架构、数据模型与PromQL入门

聊到运维监控,Prometheus 现在几乎是绕不开的选项。我个人从 Zabbix 迁移到 Prometheus 那会儿,最大的感受就是——它把「指标」这件事想得特别清楚。今天我们就来拆解一下它的核心设计。

3.1 Prometheus 架构:拉模式与时间序列

先看整体架构。Prometheus 最核心的设计理念,说白了就是「主动去拉」。它不像传统监控那样等着 agent 推数据,而是定期去目标端点抓取指标。

核心组件:

  • Prometheus Server:负责抓取、存储、查询数据
  • Exporter:暴露指标的代理程序(比如 node_exporter)
  • Pushgateway:处理短生命周期任务的指标推送
  • Alertmanager:告警路由与去重

我画了一张架构图,帮你把数据流理清楚:

Prometheus 核心架构与数据流 被监控目标 (应用/服务器) Exporter (暴露 /metrics) Pushgateway (短任务推送) Prometheus Server 抓取 → 存储 → 查询 (TSDB + PromQL) 拉取 (pull) 推送 (push) Alertmanager 告警路由/去重 Grafana 可视化 本地 TSDB (默认保留15天)

嗯,这里要注意:Prometheus 默认是拉模式,但有些场景(比如批处理任务)任务跑完就结束了,来不及等它来拉。这时候 Pushgateway 就派上用场了。我在项目中遇到过用 Pushgateway 收集 Jenkins 构建结果,效果还不错。

3.2 数据模型:Metric、Label、Sample

Prometheus 的数据模型,我建议你把它理解成一张「带标签的时序表」。每个指标由三部分组成:

概念 说明 示例
Metric 指标名称,描述监控什么 http_requests_total
Label 标签,描述指标的维度 method="GET", status="200"
Sample 样本值 + 时间戳 1024 @ 1700000000

举个例子,一条完整的时序数据长这样:

http_requests_total{method="POST", handler="/api/v1/order", instance="10.0.0.1:8080"} 2048 1700000000

拆开来看:

  • http_requests_total 是指标名
  • {method="POST", handler="/api/v1/order", instance="10.0.0.1:8080"} 是标签组合
  • 2048 是当前值
  • 1700000000 是时间戳

我的习惯:标签设计是 Prometheus 使用中最容易踩坑的地方。我建议标签的基数(cardinality)不要太高,比如把用户ID、订单ID这种高基数数据放进标签,会导致 TSDB 性能急剧下降。我曾经见过一个团队把 request_id 当标签,结果 Prometheus 直接 OOM 了。

3.3 PromQL 入门:三种核心指标类型

PromQL 是 Prometheus 的查询语言。你不需要一开始就背所有函数,先把三种指标类型搞明白,后面就顺了。

3.4 Gauge:可增可减的瞬时值

Gauge 是最直观的指标类型。它表示一个可以上下波动的值,比如 CPU 使用率、内存占用、当前连接数。

# 查询当前内存使用率
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100

# 查询当前 TCP 连接数
node_netstat_Tcp_CurrEstab

Gauge 的典型用法就是看「现在是多少」。我在排查线上问题时,经常用 Gauge 配合 avg_over_time 函数看一段时间内的平均值,比单点值更可靠。

3.5 Counter:只增不减的计数器

Counter 只能增加,不能减少。它适合统计累计值,比如请求总数、错误总数、CPU 时间片总数。

你想想看,如果直接查 Counter 的原始值,得到的是一个不断增大的数字,意义不大。我们通常用 rate()increase() 函数计算变化率:

# 过去5分钟的每秒请求数
rate(http_requests_total[5m])

# 过去1小时的总请求增量
increase(http_requests_total[1h])

避坑指南:我曾经遇到过一个问题——Counter 在进程重启后会归零。如果你用 increase() 函数,Prometheus 会自动处理重置逻辑,但如果你自己写脚本计算差值,一定要考虑重置场景,否则数据会突然出现负值。

3.6 Histogram:分布统计的利器

Histogram 是三种类型里最复杂的,但也是最有价值的。它不仅能统计请求的耗时,还能计算分位数(P50、P99)。

一个 Histogram 指标实际上会生成多个时序:

# 示例:http_request_duration_seconds
http_request_duration_seconds_bucket{le="0.1"}  100   # ≤0.1秒的请求数
http_request_duration_seconds_bucket{le="0.5"}  300   # ≤0.5秒的请求数
http_request_duration_seconds_bucket{le="1"}    450   # ≤1秒的请求数
http_request_duration_seconds_bucket{le="+Inf"} 500   # 总请求数
http_request_duration_seconds_count              500   # 总请求数
http_request_duration_seconds_sum               120.5 # 总耗时(秒)

用 PromQL 计算分位数:

# 计算 P99 延迟
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

我的经验:Histogram 的 bucket 设计很关键。bucket 太粗,分位数不准;bucket 太细,存储开销大。我一般会按业务场景来:对于 API 接口,常用 bucket 是 [0.01, 0.05, 0.1, 0.5, 1, 2, 5, 10](单位秒)。这样既能覆盖大部分场景,又不会浪费存储。

3.7 三种指标类型对比

类型 特点 常用函数 典型场景
Gauge 可增可减 avg_over_time, max_over_time CPU、内存、连接数
Counter 只增不减 rate, increase 请求数、错误数
Histogram 分布统计 histogram_quantile 延迟、响应大小

最后说一句:Prometheus 的学习曲线其实不算陡,关键是理解它的数据模型。你把 Metric、Label、Sample 这三个概念吃透了,后面写 PromQL 就是查文档的事。我在团队里带新人时,发现他们最容易犯的错误就是标签设计不合理,导致查询性能差或者存储爆炸。所以,设计标签时多想想——这个标签的取值会不会超过 1000 种?如果会,那就别放进去。

好了,这一章的内容就到这里。记住:架构是骨架,数据模型是血肉,PromQL 是灵魂。三者缺一不可。


专注资料整理