2. Prometheus 数据模型基础:Metric、Label、Sample、Time Series 的概念与关系
在深入容量规划建模之前,必须牢固掌握 Prometheus 的核心数据模型。该模型是理解长周期数据存储、查询效率以及集群资源消耗的基石。Prometheus 的数据模型可以概括为:一个 Metric 名称加上一组 Label 唯一标识一条 Time Series,而 Time Series 由一系列有序的 Sample 组成。
2.1 四大核心概念定义
| 概念 | 英文 | 定义与说明 | 容量规划关注点 |
|---|---|---|---|
| 指标 | Metric | 被监控对象的量化描述,如 http_requests_total、node_cpu_seconds_total。它定义了“测量什么”。 |
指标基数(Metric Cardinality)直接影响存储和内存开销。 |
| 标签 | Label | 键值对(Key-Value),用于对 Metric 进行多维度的特征描述,如 method="GET"、status="200"、instance="10.0.0.1:9090"。 |
标签的基数(Label Cardinality)是爆炸性增长的根源,是容量规划的核心风险点。 |
| 样本 | Sample | 时间序列中某个时间点的具体数值。由两部分组成:时间戳(Timestamp)和值(Value)。 | 样本的采集频率和大小决定了数据写入吞吐量和磁盘空间占用。 |
| 时间序列 | Time Series | 同一组 Metric + Label 组合下,按时间排序的 Sample 流。它是 Prometheus 存储和查询的基本单元。 | 时间序列的总数(Active Series)是衡量 Prometheus 实例负载的最关键指标。 |
SRE 经验提示: 在集群升级前的容量评估中,活跃时间序列数(Active Series)是比 CPU 或内存更敏感的指标。一旦 Series 数量超过阈值,Prometheus 的查询响应会急剧恶化,甚至触发 OOM。务必在升级前通过
prometheus_tsdb_head_series 等指标监控当前水位。
2.2 概念关系与数据模型结构
下图展示了 Metric、Label、Sample 与 Time Series 之间的层级关系。一个 Metric 名称可以衍生出无数条 Time Series,区别仅在于 Label 组合的不同。
2.3 数据模型在存储层的映射
Prometheus 的本地存储(TSDB)将上述概念转化为物理存储结构。理解这种映射关系,有助于我们估算磁盘空间和 I/O 压力。
- Metric 名称:在 TSDB 中被编码为
__name__这个特殊的 Label。 - Label 对:所有 Label(包括
__name__)被排序后,通过哈希映射到一个唯一的 Series ID。 - Sample:按照时间窗口(Block)组织,每个 Block 内包含该时间窗口内所有 Series 的样本数据。样本数据采用 delta-of-delta 和 XOR 压缩算法,大幅降低存储开销。
容量规划公式(简化版):
其中,压缩比 通常在 1.3 ~ 3.0 bytes/sample 之间,取决于数据波动程度。波动越小,压缩比越高。
单节点磁盘占用 ≈ Active Series × 样本大小 × 采集间隔 × 保留时长 × 压缩比其中,压缩比 通常在 1.3 ~ 3.0 bytes/sample 之间,取决于数据波动程度。波动越小,压缩比越高。
2.4 高基数(High Cardinality)陷阱
这是 SRE 在容量规划中最常遇到的“隐形杀手”。当 Label 的取值组合过多时,Time Series 数量会爆炸式增长。
| 场景 | Label 示例 | Series 数量估算 | 对 Prometheus 的影响 |
|---|---|---|---|
| 正常 HTTP 监控 | method (4种), status (10种), endpoint (20个) |
4 × 10 × 20 = 800 | 可接受,资源消耗低 |
引入 user_id |
method (4), status (10), endpoint (20), user_id (10000) |
4 × 10 × 20 × 10000 = 8,000,000 | 灾难性!TSDB 写入放大,查询超时,OOM 风险极高 |
| 容器化环境(Pod IP) | container (10), pod (500), namespace (5) |
10 × 500 × 5 = 25,000 | 中等规模,需关注 Pod 重建导致的 Series 抖动 |
升级前必查项: 使用
topk(10, count by (__name__) ({__name__=~".+"})) 查询当前 Prometheus 中 Series 数量最多的 Top 10 指标。如果发现某个指标拥有数百万 Series,且其 Label 包含 user_id、ip、email 等无限增长的维度,必须在升级前进行 Relabel 丢弃 或 Recording Rule 聚合,否则升级后的查询负载会压垮新实例。
2.5 数据模型与查询语言(PromQL)的关联
PromQL 的向量匹配逻辑直接基于数据模型:
- Instant Vector:在某个时间点,查询所有 Time Series 的最新 Sample。
- Range Vector:在某个时间范围内,查询一组 Time Series 的多个 Sample。
- 聚合操作(如
sum by (method)):先按 Label 分组,再对组内的 Series 进行聚合,这依赖于 Label 的维度。
在容量规划建模中,我们经常使用 rate() 和 increase() 函数处理 Counter 类型指标,这些函数需要读取 Range Vector,即需要从磁盘读取多个 Sample。Series 基数越高,Range 查询的 I/O 放大效应越明显。
# 示例:计算集群升级期间,每秒请求数的变化趋势
# 该查询需要遍历所有 method/status/endpoint 组合的 Series
rate(http_requests_total{job="my-app"}[5m])