4. Prometheus 核心概念:数据模型与 Metric 类型

聊到 Prometheus,很多人第一反应就是「抓指标、存时序、出告警」。但真正用好它,你得先理解它的数据模型。说白了,Prometheus 的一切都建立在 Metric(指标)、Label(标签)、Sample(样本) 这三个核心概念上。我刚开始接触时也觉得这有啥好学的,直到有一次排查一个诡异的数据抖动,才发现自己对 Label 的理解不够深——嗯,那次折腾了我整整一个下午。

4.1 数据模型:Metric、Label、Sample

我们先拆开来看。

Metric 就是指标的名字,比如 http_requests_total、cpu_usage_ratio。它描述的是「我要监控什么」。命名上我建议用下划线风格,语义清晰,比如 node_memory_MemAvailable_bytes。

Label 是键值对,用来给指标打标签。比如 method="GET"、status="200"、instance="192.168.1.1:9090"。Label 的作用是区分同一个指标的不同维度。你想想看,如果没有 Label,http_requests_total 就只能是一个总数,你根本不知道是哪个接口、哪个方法、哪个状态码的请求。

Sample 是实际的数据点,包含一个时间戳和一个值。比如 http_requests_total{method="GET"} 1024 @ 1700000000。这就是一条完整的时序数据。

这三者组合起来,就构成了 Prometheus 的时序序列。每个时序由 Metric Name + Label 集合唯一标识,每个时间点对应一个 Sample。

核心公式:

时间序列 = Metric Name + Label Set

数据点 = 时间戳 + 值

举个例子:

http_requests_total{method="POST", handler="/api/v1/order", status="200"} 2048 @ 1700000000
http_requests_total{method="POST", handler="/api/v1/order", status="500"} 3 @ 1700000000

这两个时序的 Metric Name 都是 http_requests_total,但 Label 不同,所以它们是两个独立的时序。查询时你可以用 Label 做过滤、聚合,非常灵活。

注意:Label 的基数(Cardinality)是 Prometheus 性能的关键。我曾经见过一个团队把用户 ID 作为 Label,结果时序数量爆炸,Prometheus 直接 OOM。Label 的值不要用高基数数据,比如用户 ID、请求 ID、IP 地址。一般建议 Label 的取值数量控制在几千以内。

4.2 四种 Metric 类型

Prometheus 的客户端库提供了四种 Metric 类型。每种类型对应不同的监控场景。我按使用频率从高到低给你捋一遍。

4.2.1 Counter(计数器)

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

它的特点是:只能增加,重启后会归零。你可能会问:「那重启后数据不就断了吗?」没错,所以查询时一般用 rate() 或 increase() 函数计算变化率,而不是直接看原始值。

# 统计 HTTP 请求总数
http_requests_total{method="GET"} 1000

# 查询每秒请求速率(过去5分钟)
rate(http_requests_total[5m])

我在项目中遇到过一个问题:有人用 Counter 统计在线用户数,结果发现值一直在涨,从不下降。这就是用错了类型。在线用户数应该用 Gauge。

4.2.2 Gauge(仪表盘)

Gauge 可增可减,适合测量瞬时值。比如内存使用量、CPU 使用率、当前连接数、温度。

它的值可以上升也可以下降,重启后归零。查询时常用 avg()、max()、min() 等聚合函数。

# 当前内存使用量(字节)
node_memory_MemAvailable_bytes 8388608000

# 查询过去5分钟的平均内存使用率
avg(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100)

小技巧:Gauge 配合 predict_linear() 函数可以做简单的趋势预测。比如预测磁盘空间还能撑多久。我经常用这个来做容量规划。

4.2.3 Histogram(直方图)

Histogram 用来统计数据的分布情况。比如请求延迟的分布、响应大小的分布。它会自动把数据分到不同的桶(Bucket)里。

举个例子,你配置了延迟桶为 {0.1, 0.5, 1, 2, 5} 秒,那么 Histogram 会统计落在每个桶里的请求数量。

# Histogram 指标示例
http_request_duration_seconds_bucket{le="0.1"} 500
http_request_duration_seconds_bucket{le="0.5"} 800
http_request_duration_seconds_bucket{le="1"} 950
http_request_duration_seconds_bucket{le="2"} 990
http_request_duration_seconds_bucket{le="5"} 1000
http_request_duration_seconds_bucket{le="+Inf"} 1000
http_request_duration_seconds_count 1000
http_request_duration_seconds_sum 450

你可以用 histogram_quantile() 函数计算百分位数,比如 P99 延迟:

histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

避坑指南:我曾经在配置 Histogram 桶时,把桶的范围设得太宽,导致大部分请求都落在同一个桶里,P99 计算完全失真。桶的边界要根据实际数据分布来设置,一般建议覆盖 90% 以上的数据范围,并且在关键区域(比如 P99 附近)加密桶。

4.2.4 Summary(摘要)

Summary 和 Histogram 类似,也是用来计算百分位数的。但区别在于:Summary 在客户端计算百分位数,Histogram 在服务端计算。

Summary 会直接暴露 quantile 标签,比如:

# Summary 指标示例
http_request_duration_seconds{quantile="0.5"} 0.2
http_request_duration_seconds{quantile="0.9"} 0.8
http_request_duration_seconds{quantile="0.99"} 2.5
http_request_duration_seconds_count 1000
http_request_duration_seconds_sum 450

Summary 的优点是查询简单,直接读值就行。缺点是:

  • 你无法对多个 Summary 做聚合计算(比如跨实例求 P99)
  • 百分位数的精度在客户端固定,无法事后调整

而 Histogram 可以在服务端灵活计算任意百分位数,也支持跨实例聚合。所以我个人更推荐用 Histogram,除非你有特殊需求。

4.3 四种类型对比

类型 特点 适用场景 常用函数
Counter 只增不减 请求总数、错误数、CPU 时间 rate(), increase()
Gauge 可增可减 内存、CPU、连接数、温度 avg(), max(), min()
Histogram 服务端计算分位数 延迟分布、响应大小分布 histogram_quantile()
Summary 客户端计算分位数 已知分位数、无需聚合 直接读取 quantile 标签

4.4 作业与实例

光说不练假把式。我给你留个小作业,也是我当年入门时练过的。

作业:用 Prometheus 客户端(比如 Python 的 prometheus_client)写一个简单的 HTTP 服务,暴露以下指标:

  1. 一个 Counter,统计总请求数,带上 method 和 endpoint 标签
  2. 一个 Gauge,统计当前活跃连接数
  3. 一个 Histogram,统计请求延迟,桶设为 [0.1, 0.5, 1, 2, 5]

然后启动 Prometheus 抓取这个服务,用 PromQL 查询:

  • 过去5分钟的平均请求速率
  • 当前活跃连接数的最大值
  • P99 延迟

这个作业做完,你对数据模型和 Metric 类型的理解就扎实了。

我的建议:刚开始不要追求完美,先跑通一个最简单的例子。我当年就是先写了一个 Counter,看到数据在 Prometheus 里跳动了,那种成就感比看十篇文档都强。

4.5 知识体系图

下面这张图帮你梳理本章的核心逻辑:

Prometheus 数据模型与 Metric 类型 数据模型 Metric Label Sample 四种 Metric 类型 Counter Gauge Histogram Summary 核心要点: • 时序 = Metric Name + Label Set,Label 基数控制是性能关键 • Counter 只增不减,用 rate() 看速率;Gauge 可增可减,看瞬时值 • Histogram 服务端算分位数,灵活可聚合;Summary 客户端算,简单但不可聚合

这张图把数据模型和 Metric 类型的关系画清楚了。左边是数据模型的三个要素,右边是四种 Metric 类型。你记住一个原则:先选对类型,再配好 Label,监控数据就不会乱。