PromSL详解

PromQL(Prometheus Query Language)是Prometheus监控系统的核心查询语言,专门用于处理时间序列数据。下面通过一个表格快速了解其核心概念: 

 

特性分类

核心概念

说明

​数据模型​

时间序列 (Time Series)

由指标名称(Metric Name)和一组标签(Label)唯一标识的数据点序列,格式为 <metric_name>{<label_name>=<label_value>, ...}

 

指标类型 (Metric Types)

主要包括:
- ​Counter(计数器)​​:只增不减的累积指标,如请求总数

- ​Gauge(仪表盘)​​:可任意变化的瞬时指标,如CPU使用率
- ​Histogram(直方图)​​ & ​Summary(摘要)​​:用于统计和分析数据的分布情况

​查询操作​

即时向量 (Instant Vector)

每个时间序列只包含单个最新数据点的查询结果

 

范围向量 (Range Vector)

包含一个时间范围内所有数据点的查询结果

 

匹配模式

支持完全匹配(=, !=)和正则匹配(=~, !~)来过滤时间序列

​功能与应用​

聚合运算 (Aggregation)

支持使用 sum, avg, count, max, min等函数对数据进行聚合计算

 

应用场景

用于临时数据查询与调试、Grafana等工具中的数据可视化、以及定义告警规则

 

一. 核心概念

理解 PromQL 前,需要先了解其数据模型和基本数据类型

 

1.数据模型:Prometheus 的数据由时间序列(Time Series)​​ 组成,每条序列由指标名称(Metric Name)​、标签(Label)​、以及一系列的样本(Sample)​​(即 (timestamp, value) 数据点)构成。其格式通常为 <metric_name>{<label_name>=<label_value>, ...},例如 http_requests_total{method="GET", status="200", instance="localhost:9090"}

 

2.指标类型:

  • Counter(计数器):只增不减的累积指标,如 HTTP 请求总数、CPU 使用时间。适用于统计累计值和计算速率。
  • Gauge(仪表盘):可任意变化的瞬时指标,如内存使用量、CPU 使用率、温度。适用于反映当前状态。
  • Histogram(直方图)& Summary(摘要):用于统计和分析数据的分布情况,如请求延迟。

 

3.数据类型:PromQL 表达式操作或计算后,主要会产生以下几种类型的结果:

  • Instant Vector(瞬时向量):同一时间戳下的一组时间序列,每个序列包含最新的一个样本值。例如 http_requests_total
  • Range vector(范围向量):一段时间范围内的一组时间序列,每个序列包含多个样本值。例如 http_requests_total[5m]。范围向量不能直接图表化,需借助函数处理。
  • Scalar(标量):一个简单的浮点数值,如 10。
  • String(字符串):简单的字符串值(在 PromQL 中较少使用)

 

二. 查询操作

PromQL 提供了强大的选择器和操作符来查询和操作时间序列数据

 

1.时间序列选择器

  • 瞬时向量选择器:直接使用指标名称或通过 {}和标签进行过滤。
http_requests_total                     # 查询所有时间序列
http_requests_total{method="GET"}       # 完全匹配标签
http_requests_total{status=~"5.."}      # 正则匹配标签:状态码为5xx的请求
http_requests_total{environment=""}     # 匹配缺少该标签的时间序列
  • 范围向量选择器:在瞬时向量选择器后附加 [<时长>]来查询一段时间内的数据。
http_requests_total[5m]                  # 过去5分钟的所有样本
node_cpu_seconds_total{mode="idle"}[1h]   # 过去1小时CPU空闲时间

# 支持的时间单位:s(秒), m(分钟), h(小时), d(天), w(周),y(年)
  • 偏移修饰符(Offset):使用 offset关键字查询历史数据
http_requests_total offset 5m            # 查询5分钟前的瞬时数据
http_requests_total[1d] offset 1d        # 查询昨天一天的数据

 

2.操作符

PromQL 支持丰富的操作符来对数据进行运算和比较。

  • 算术运算符:+, -, *, /, %, ^(幂运算)
# 计算内存使用率
(node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / node_memory_MemTotal_bytes * 100
  • 比较运算符:==, !=, >, <, >=, <=
up == 1  # 筛选状态为 "up" 的实例
  • 逻辑/集合运算符:and, or, unless
# 找出请求量高且错误率也高的实例
rate(http_requests_total[5m]) > 100 and rate(http_errors_total[5m]) > 1
  • 聚合运算符:sum, min, max, avg, stddev, stdvar, count, group。常与 bywithout结合使用,以指定根据哪些标签进行分组聚合或排除哪些标签进行聚合。
# 按 job 分组计算请求总量
sum by(job) (http_requests_total)
# 计算所有实例的请求总量,忽略 instance 标签
sum without(instance) (http_requests_total)

 

三. 常用函数

PromQL 提供了大量内置函数来处理时间序列数据。

函数类型

函数名

说明

示例

​速率计算​

rate(v range_vector)

计算范围向量中时间序列的平均每秒增长率,自动处理计数器重置

rate(http_requests_total[5m])

 

irate(v range_vector)

计算范围向量中时间序列的瞬时每秒增长率​(基于最后两个样本),对变化更敏感

irate(http_requests_total[1m])

 

increase(v range_vector)

计算范围向量中时间序列的指定时间范围内的总增量,自动处理计数器重置

increase(http_requests_total[1h])

​聚合函数​

sum()

对时间序列的值求和

sum(rate(http_requests_total[5m])) by (job)

 

avg()

对时间序列的值求平均值

avg(rate(http_requests_total[5m])) by (method)

 

max()/ min()

找出一组时间序列中的最大值或最小值

max(rate(http_requests_total[5m]))

 

count()

统计时间序列的数量

count(up)

 

topk(k, instant_vector)

返回样本值最大的 k 条时间序列

topk(3, http_requests_total)

​时间聚合​

avg_over_time()

计算指定时间范围内每个时间序列的平均值

avg_over_time(node_memory_MemFree_bytes[5m])

​分位数计算​

histogram_quantile(φ, instant_vector)

根据直方图指标计算分位数 (φ ∈ [0,1])

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

​数据处理​

absent()

如果具有指定名称和标签的时间序列不存在,则返回空向量,常用于检测指标是否存在

absent(up{instance="nonexistent"})

​预测​

predict_linear()

基于历史数据预测时间序列未来的值

predict_linear(node_filesystem_free_bytes[1h], 4 * 3600)# 预测4小时后磁盘剩余空间

 

四. 实战示例

1.计算CPU使用率

100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# rate(node_cpu_seconds_total{mode="idle"}[5m])计算每个实例过去5分钟的平均空闲率,avg by(instance)按实例聚合,最后用 100 - ... * 100得到使用率百分比

2.计算HTTP请求错误率(5xx)

sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) * 100

# 先计算状态码为5xx的请求速率和总请求速率,相除后乘以100得到错误率百分比

3.计算P99请求延迟

histogram_quantile(0.99, sum by(le) (rate(http_request_duration_seconds_bucket[5m])))

# 对直方图指标 http_request_duration_seconds_bucket在5分钟内的增长率按 le(桶边界) 分组求和,然后计算99分位数

4.检查实例是否存活

up == 1

# up指标为1表示实例健康,为0表示不健康

5.预测磁盘空间耗尽时间

predict_linear(node_filesystem_free_bytes{device="/dev/sda1"}[6h], 3600) / (1024 * 1024)

# 基于过去6小时的数据,预测1小时后的磁盘剩余空间(MB)

 

五. 补充概念

1. 分位数quantile

分位数类型

含义

常见应用场景

​中位数 (Median)​​

将数据分为两等份的点,即50%的数据低于此值。

代表数据的“一般水平”,比平均值更能抵抗极端值的干扰。例如,居民收入中位数。

​四分位数 (Quartile)​​

将数据分为四等份的三个点,包括下四分位数 (Q1, 25%)​、中位数 (Q2, 50%)​​ 和上四分位数 (Q3, 75%)​​

用于绘制箱线图,直观展示数据分布范围和中位数,并识别异常值。

​百分位数 (Percentile)​​

将数据分为一百等份的点,例如第5百分位数表示有5%的数据低于此值。

用于评估排名,如考试成绩的百分位数可以反映你在全体考生中的位置。

 

2. 时间序列(Time Series) & 时间序列标识符 & 样本(Sample)

在时间序列的标识符(即 <metric_name>{<label_name>=<label_value>, ...}这个格式)中,确实不包含时间戳。这个格式定义的是一条唯一的时间序列,而时间维度体现在这条序列所包含的一系列样本(Sample)​​ 上。

概念要素

角色与内容

类比理解

​时间序列标识符​
http_requests_total{method="GET", status="200"}

​定义“谁”​​:
通过指标名称和一组标签,唯一确定一条监控曲线。它回答的是“这是什么数据?”的问题。

就像一个人的身份证号或姓名+住址,它唯一地确定了这个人,但这个身份信息本身不包含这个人随时间变化的动态信息(如身高、体重)。

​样本(Sample)​​
(timestamp, value)

​记录“何时”与“何值”​​:
每个样本是一个数据点,包含一个毫秒级精度的时间戳(timestamp)和当时的测量值(value)。

就像为这个人建立的成长记录,例如 (2020年, 身高120cm), (2021年, 身高130cm)。每个记录都对应一个具体时间和状态。

​时间序列(Time Series)​​

​完整的“生命轨迹”​​:
由同一个标识符对应的所有样本按时间顺序排列而成,形成一条数据流。

​身份 + 全部历史记录​ 就构成了这个人完整的、随时间变化的生命轨迹。

 

如下是一个具体例子

假设我们监控一个服务的HTTP请求,有一条时间序列的标识符是:

http_requests_total{job="api-server", method="GET", status="200"}

这条序列在时间线上可能会有一系列样本点,例如:

  • (...上面相同的标识符...) => 1024 (t₀)// 在 t₀ 时刻,总请求数是1024

  • (...上面相同的标识符...) => 1025 (t₁)// 在 t₁ 时刻,总请求数增长到1025

  • (...上面相同的标识符...) => 1026 (t₂)// 在 t₂ 时刻,总请求数增长到1026

这里的 t₀, t₁, t₂就是具体的时间戳。标识符 http_requests_total{...}定义了这条数据线的“身份”,而一系列带时间戳的样本点 (t₀, 1024), (t₁, 1025), (t₂, 1026)则共同描绘出这条数据线随时间变化的轨迹

 

Prometheus的存储视角

从Prometheus数据库(TSDB)的内部来看,它的存储结构也清晰地反映了这种关系:

  1. ​索引(Index)​​:主要用于快速查找。它记录了“哪组标签(即时间序列标识符)对应哪个内部ID”。

  2. ​数据块(Chunks)​​:实际存储样本点的地方。每个数据块包含了一段时间范围内某条时间序列的所有 (timestamp, value)对。

所以,当您查询 http_requests_total{job="api-server"}过去5分钟的数据时,Prometheus会先通过索引找到所有匹配的序列ID,然后去对应的数据块中读取这些序列在最近5分钟内的所有样本值

 

posted on 2025-10-09 12:06  Karlkiller  阅读(19)  评论(0)    收藏  举报

导航