Prometheus(三)—— PromQL从入门到精通:掌握Prometheus数据查询的核心技术
文章目录
- 前言
- 一、PromQL简介
- 1.1 什么是PromQL
- 1.2 PromQL的核心作用
- 二、Prometheus数据模型
- 2.1 数据模型的核心构成
- 2.1.1 指标名称(Metric Name)
- 2.1.2 标签(Label)
- 2.2 时间序列的唯一标识规则
- 2.3 指标名称及标签使用注意事项
- 三、样本数据格式
- 3.1 样本数据的组成
- 3.2 样本数据示例解析
- 四、PromQL的数据类型
- 4.1 即时向量(Instant Vector)
- 4.2 区间向量(Range Vector)
- 4.3 标量数据(Scalar)
- 4.4 字符串(String)
- 五、时间序列选择器
- 5.1 选择器的作用与分类
- 5.2 即时向量选择器
- 5.2.1 选择器的组成
- 5.2.2 三种常见组合方式
- 5.2.3 标签匹配器(4种操作符)
- 5.2.4 注意事项
- 5.3 区间向量选择器
- 5.3.1 定义与语法
- 5.3.2 时间单位说明
- 5.3.3 示例解析
- 六、偏移向量选择器
- 6.1 偏移选择器的作用
- 6.2 语法与示例
- 6.2.1 即时向量+偏移
- 6.2.2 区间向量+偏移
- 6.3 向量表达式使用要点
- 七、PromQL的指标类型
- 7.1 Counter(计数器)
- 7.1.1 定义与特性
- 7.1.2 常用函数与示例
- 7.2 Gauge(仪表盘)
- 7.2.1 定义与特性
- 7.2.2 常用函数与示例
- 7.3 Histogram(累积直方图)
- 7.3.1 定义与核心特性
- 7.3.2 生成的时间序列
- 7.3.3 示例解析
- 7.3.4 分位数计算(histogram_quantile)
- 7.4 Summary(摘要)
- 7.4.1 定义与特性
- 7.4.2 生成的时间序列
- 7.4.3 示例解析
- 7.4.4 Histogram与Summary的异同
- 八、Prometheus的聚合函数
- 8.1 聚合函数的作用
- 8.2 内置11种聚合函数详解
- 8.3 聚合函数的使用场景
- 九、PromQL的聚合表达式
- 9.1 聚合表达式的语法格式
- 9.2 by与without子句的区别
- 9.3 聚合表达式实战示例
- 9.3.1 示例1:每台主机CPU最近5分钟的平均使用率
- 9.3.2 示例2:查询1分钟负载(load1)是否超过CPU核心数的2倍
- 9.3.3 示例3:计算主机内存使用率
- 9.3.4 示例4:统计所有node节点的容器总计内存(单位:GB)
- 9.3.5 示例5:计算node01节点最近1分钟所有容器的CPU使用率
- 9.3.6 示例6:计算最近5分钟每个容器的CPU使用变化率
- 9.3.7 示例7:查询K8S集群最近1分钟每个Pod的CPU使用变化率
- 总结
前言
在监控领域,Prometheus凭借其灵活的时序数据存储、强大的指标采集能力,成为云原生时代最主流的监控系统之一。而要充分发挥Prometheus的价值,PromQL(Prometheus Query Language) 作为其内置的数据查询语言,是绕不开的核心技能。无论是实时查看系统指标、生成可视化图表,还是配置告警规则、分析性能瓶颈,都需要通过PromQL实现。
本文将从PromQL的基础概念出发,逐步深入数据模型、选择器、指标类型、聚合函数等核心模块,结合实战示例解析关键用法,帮助读者系统掌握PromQL的使用技巧,真正将Prometheus的监控能力落地到实际业务场景中。
一、PromQL简介
1.1 什么是PromQL
PromQL(Prometheus Query Language)是Prometheus专为时序数据设计的查询语言,支持实时数据查询、聚合计算、多维度过滤等操作。它的核心目标是让用户能够从Prometheus存储的时序数据中,快速提取出有价值的信息。
与传统的SQL不同,PromQL针对时序数据的特性做了优化,能够轻松处理时间序列+多维度标签的数据结构,满足监控场景下的各类分析需求(如计算指标增长率、统计分位数、按维度分组聚合等)。
1.2 PromQL的核心作用
1、多维度数据过滤:基于指标名称和标签,精准筛选目标时间序列(如筛选“job=prometheus”且“code=200”的HTTP请求指标);
2、实时数据计算:支持算术运算、函数计算(如rate计算增长率、delta计算差值),生成衍生指标;
3、聚合统计分析:通过sum、avg、quantile等聚合函数,实现多时间序列的汇总、均值、分位数等统计;
4、时序数据可视化与告警:为Grafana等可视化工具提供数据来源,同时作为Prometheus告警规则的核心判断条件。
二、Prometheus数据模型
Prometheus的核心是时序数据(Time Series),而数据模型则定义了时序数据的组织方式。理解这一模型是学好PromQL的基础。
2.1 数据模型的核心构成
Prometheus中,每一条时间序列由“指标名称(Metric Name)”和“标签集(Label Set)”共同标识,格式如下:
<metric_name>{<label_name>=<label_value>, ...}
指标名称代表着监控目标上某类可测量属性的基本特征标识标签则是这个基本特征上再次细分的多个可测量维度
2.1.1 指标名称(Metric Name)
- 作用:描述监控目标的“基本特征”,即“监控什么”(如HTTP请求总数、CPU空闲时间);
- 命名规范:通常采用“业务域_指标类型_单位”的格式(如
prometheus_http_requests_total,表示“Prometheus的HTTP请求总数”,total表示计数器类型); - 示例:
node_cpu_seconds_total表示“节点CPU的总占用时间(秒)”,node_memory_MemFree_bytes表示“节点空闲内存(字节)”。
2.1.2 标签(Label)
- 作用:对指标的“维度细分”,即“从哪个角度监控”(如按实例、状态、接口区分指标);
- 特性:键值对结构,可选配置,但合理的标签设计能极大提升查询灵活性;
- 分类:
1、用户自定义标签:用户在指标采集时配置(如job=prometheus、instance=localhost:9090);
2、系统默认标签:Prometheus自动添加,不显示在/metrics页面,需在target页面鼠标悬浮到label字段查看,常见默认标签如下:__address__:目标实例的地址(格式<host>:<port>,如localhost:9090);__scheme__:采集指标使用的协议(http或https);__metrics_path__:采集指标的URI路径(默认/metrics);__param_<name>:URL参数中名称为<name>的参数值(如__param_token=123);__name__:标识指标名称的预留标签,可通过它过滤指标名称(如__name__=~".*_total"匹配所有计数器指标)。
2.2 时间序列的唯一标识规则
- 规则1:指标名称相同,但标签不同 → 不同时间序列(如
prometheus_http_requests_total{code="200"}和prometheus_http_requests_total{code="302"}是两条独立时序); - 规则2:指标名称不同 → 不同时间序列(无论标签是否相同);
- 规则3:标签的增删改 → 生成新时间序列(如给
prometheus_http_requests_total添加handler="/metrics"标签,会创建一条新时序)。
2.3 指标名称及标签使用注意事项
1、保持标签稳定性:频繁增删改标签会导致时序数据“碎片化”,不仅增加存储压力,还会使基于旧标签的图表、告警规则失效;
2、避免空标签值滥用:标签值为空时,未定义该标签的时序也会被匹配(如prometheus_http_requests_total{handler=""}会匹配所有未设置handler标签的该指标时序);
3、标签命名规范:建议使用小写字母、数字、下划线,避免特殊字符,确保可读性和兼容性。
三、样本数据格式
时间序列的本质是按时间排序的样本集合,而每个样本则是PromQL查询的最小数据单元。
3.1 样本数据的组成
每个样本包含两部分:
1、时间戳:毫秒级精度(格式为Unix时间戳,如1434317560885表示对应时间点);
2、样本值:float64格式的数值(支持整数、小数,如28、35.5)。
3.2 样本数据示例解析
以下是prometheus_http_requests_total指标的一组样本数据,我们标注各部分含义以帮助理解:
prometheus_http_requests_total{code="200", handler="/targets", instance="localhost:9090", job="prometheus"} @1434317560885 28
|-------------------------- 指标名称 -------------------------| |------------------ 标签 ------------------| |---- 时间戳 ----| |-- 样本值 --|prometheus_http_requests_total{code="200", handler="/targets", instance="localhost:9090", job="prometheus"} @1434317561483 35
prometheus_http_requests_total{code="200", handler="/targets", instance="localhost:9090", job="prometheus"} @1434317562589 42
上述样本表示:在localhost:9090实例的prometheus任务中,访问/targets接口且返回码为200的HTTP请求,在不同时间点的累计次数分别为28、35、42。
四、PromQL的数据类型
PromQL表达式的返回值分为4种数据类型,不同类型适用于不同的场景(如绘图、告警、函数参数)。
4.1 即时向量(Instant Vector)
- 定义:特定或全部的时间序列集合上,具有
相同时间戳的一组样本值; - 核心特征:“同一时间点的多时序样本”,是可视化图表(如
Grafana)的主要数据来源; - 示例:
prometheus_http_requests_total{code="200"}→ 返回所有code=200的prometheus_http_requests_total时序在“当前时间”的样本值。
4.2 区间向量(Range Vector)
- 定义:特定或全部的时间序列集合上,在指定的同一时间范围内的所有样本值;
- 核心特征:“时间范围内的多时序样本”,仅用于作为函数参数(如rate、irate),不能直接用于绘图;
- 示例:
prometheus_http_requests_total{code="200"}[5m]→ 返回所有code=200的时序在“过去5分钟”内的所有样本。
4.3 标量数据(Scalar)
- 定义:一个单独的
float64数值,无时间序列和标签信息; - 核心特征:“无维度的单一数值”,常用于算术运算或作为函数返回值;
- 示例:
100、3.14→ 直接表示一个数值;也可通过表达式生成,如count(prometheus_http_requests_total)→ 返回该指标的时序数量(一个标量)。
4.4 字符串(String)
- 定义:一个文本字符串,支持单引号或双引号包裹;
- 核心特征:“无数值意义的文本”,主要用于标注或函数参数(如
label_replace函数中的替换文本); - 示例:
"prometheus"、'http_requests'→ 直接表示一个字符串。
五、时间序列选择器
选择器是PromQL的“数据筛选工具”,用于从海量时序中挑选出目标数据。根据返回数据类型,分为即时向量选择器和区间向量选择器。
5.1 选择器的作用与分类
- 作用:定义“筛选哪些时序”和“筛选哪个时间范围的样本”,是构建PromQL表达式的第一步;
- 分类:
1、即时向量选择器:筛选“特定时间点”的样本,返回即时向量;
2、区间向量选择器:筛选“指定时间范围”的样本,返回区间向量。
5.2 即时向量选择器
5.2.1 选择器的组成
即时向量选择器由两部分组成(至少包含其一):
1、指标名称:筛选指定指标下的时序(可选);
2、标签选择器:筛选符合标签条件的时序(定义在{}中,可选)。
5.2.2 三种常见组合方式
1、仅指标名称:返回该指标下的所有时序;
- 示例:
prometheus_http_requests_total→ 等同于prometheus_http_requests_total{},返回所有该指标的时序;
2、仅标签选择器:返回符合标签条件的所有时序(无论指标名称);
- 示例:
{code="200", job="prometheus"}→ 返回所有code=200且job=prometheus的时序;
3、指标名称+标签选择器:返回指定指标下符合标签条件的时序(最常用);
- 示例:
prometheus_http_requests_total{code="200", job="prometheus"}→ 返回prometheus_http_requests_total指标中code=200且job=prometheus的时序。
5.2.3 标签匹配器(4种操作符)
标签选择器通过“匹配器”定义筛选条件,支持4种操作符:
| 操作符 | 作用 | 示例 |
|---|---|---|
= | 完全相等 | code="200" → 筛选code为200的时序 |
!= | 不相等 | code!="500" → 筛选code不为500的时序 |
=~ | 正则表达式匹配 | `handler=~"/targets |
!~ | 正则表达式不匹配 | instance!~"localhost:.*" → 排除instance以localhost:开头的时序 |
5.2.4 注意事项
1、空标签值的匹配规则:若标签选择器的标签值为空(如handler=""),则未定义该标签的时序也会被匹配;
- 示例:
prometheus_http_requests_total{handler=""}→ 包含所有未设置handler标签的该指标时序;
2、正则表达式的完全锚定:正则匹配需“完全覆盖标签值”,而非部分匹配;
- 示例:
code=~"2.."→ 可匹配code=200、code=201,但不能匹配code=1200(因1200超出2..的完全匹配范围);
3、非法选择器的规避:选择器必须包含“非空的指标名称”或“不会匹配空字符串的标签选择器”;
- 错误示例:
{job=""}→ 标签值为空,且无指标名称,属于非法选择器; - 正确示例:
{__name__=~".*_total"}→ 通过__name__标签筛选指标名称,合法。
5.3 区间向量选择器
5.3.1 定义与语法
区间向量选择器是在“即时向量选择器”的基础上,添加“时间范围”(用[]包裹),语法如下:
<即时向量选择器>[<时间范围>]
- 时间范围:以“当前时间”为基准,指向过去的特定时长(如
[5m]表示过去5分钟)。
5.3.2 时间单位说明
支持的时间单位及含义如下,且需使用整数,可组合多个单位(按“大单位→小单位”顺序):
| 单位 | 含义 | 示例组合 |
|---|---|---|
ms | 毫秒 | - |
s | 秒 | - |
m | 分钟 | [1h30m](1小时30分钟) |
h | 小时 | - |
d | 天(24小时) | - |
w | 周(7天) | - |
y | 年(365天) | - |
- 注意:不支持小数单位(如
[1.5h]非法,需改为[1h30m])。
5.3.3 示例解析
- 示例1:
prometheus_http_requests_total{code="200"}[10m]→ 返回code=200的该指标时序在“过去10分钟”内的所有样本; - 示例2:
{job="node"}[1d]→ 返回job=node的所有时序在“过去1天”内的所有样本。
六、偏移向量选择器
默认情况下,选择器以“当前时间”为基准筛选数据;而偏移选择器可调整基准时间,实现“查询历史数据”的需求。
6.1 偏移选择器的作用
- 核心作用:将选择器的基准时间“向前偏移指定时长”,而非使用当前时间;
- 适用场景:对比历史同期数据(如查询“昨天此时的CPU使用率”)、回溯历史异常数据。
6.2 语法与示例
偏移选择器通过offset关键字指定偏移时长,紧跟在选择器之后,语法如下:
<选择器> offset <偏移时长>
6.2.1 即时向量+偏移
- 示例:
prometheus_http_requests_total offset 5m→ 查询“5分钟前”的prometheus_http_requests_total指标所有时序的样本; - 解析:基准时间从“当前”改为“5分钟前”,返回该时间点的即时向量。
6.2.2 区间向量+偏移
- 示例:
prometheus_http_requests_total[5m] offset 1d→ 查询“1天前的5分钟内”的该指标所有时序的样本; - 解析:先将基准时间偏移1天(即“昨天此时”),再筛选该基准时间过去5分钟的样本,返回区间向量。
6.3 向量表达式使用要点
1、返回类型的场景限制:
- 绘图场景(如Grafana):仅支持即时向量;
- 速率函数(如rate、irate):仅支持区间向量作为参数;
2、区间向量的使用限制:区间向量不能直接用于绘图,必须先通过函数(如rate)转换为即时向量;
- 错误示例:直接在Grafana中使用
prometheus_http_requests_total[5m]→ 无法绘图; - 正确示例:
rate(prometheus_http_requests_total[5m])→ 转换为即时向量后可绘图。
七、PromQL的指标类型
PromQL将指标分为4种类型,每种类型对应不同的业务场景,需结合特定函数使用。
7.1 Counter(计数器)
7.1.1 定义与特性
- 定义:用于存储单调递增的指标数据(仅增不减,重启后重置为0);
- 适用场景:统计累计类指标(如HTTP请求总数、错误次数、接口调用次数);
- 核心特性:数值非负,仅支持递增(如
prometheus_http_requests_total随请求增加而增大)。
7.1.2 常用函数与示例
Counter的“总数”通常无直接意义,需通过函数计算“变化率”或“排名”:
1、topk(n, 指标):返回指标下数值最大的前n条时序;
- 示例:
topk(3, prometheus_http_requests_total)→ 返回HTTP请求总数排名前3的时序;
2、rate(指标[时间范围]):计算指标在时间范围内的“平均增长率”(适用于长期趋势分析);
- 示例:
rate(prometheus_http_requests_total[1h])→ 计算过去1小时内HTTP请求的平均每秒增长率;
3、irate(指标[时间范围]):计算指标在时间范围内的“瞬时增长率”(基于最后两个样本,适用于短期波动分析);
- 示例:
irate(prometheus_http_requests_total[5m])→ 计算过去5分钟内HTTP请求的瞬时每秒增长率。
7.2 Gauge(仪表盘)
7.2.1 定义与特性
- 定义:用于存储可增可减的指标数据(数值可正可负,重启后重置);
- 适用场景:统计波动类指标(如CPU使用率、内存空闲大小、磁盘使用率、温度);
- 核心特性:数值随时间波动(如内存空闲大小会随进程占用而增减)。
7.2.2 常用函数与示例
Gauge常用于计算“差值”“预测值”或进行聚合(求和、均值):
1、delta(指标[时间范围]):计算指标在时间范围内的“首尾样本差值”;
- 示例:
delta(cpu_temp_celsius{host="node01"}[2h])→ 返回node01节点CPU温度与2小时前的差值;
2、predict_linear(指标[时间范围], t):通过线性回归预测指标在t秒后的数值;
- 示例:
predict_linear(node_filesystem_free{job="node"}[2h], 4*3600)→ 基于过去2小时的空闲磁盘数据,预测4小时后的空闲磁盘大小;
3、聚合函数(sum/avg/min/max):对指标进行多时序聚合;
- 示例:
avg(node_memory_MemFree_bytes{job="node"})→ 计算所有node节点的平均空闲内存。
7.3 Histogram(累积直方图)
7.3.1 定义与核心特性
- 定义:Histogram 会在一段时间范围内对数据进行采样(通常是请求持续时长或响应大小等),并将其计入可配置的 bucket(存储桶)中 ,后续可通过指定区间筛选样本,也可以统计样本总数,最后一般将数据展示为直方图。;
- 适用场景:分析数据分布(如HTTP响应时间、请求大小),解决“长尾问题”(如大部分请求快,但个别请求极慢导致平均值失真);
- 核心特性:采用“累积区间机制”(每个bucket包含前面所有bucket的样本)。
7.3.2 生成的时间序列
Histogram指标会以<basename>为前缀,生成3类时序:
1、<basename>_sum:所有样本值的总和;
2、<basename>_count:样本总数(本质是Counter类型);
3、<basename>_bucket{le="<上边界>"}:样本值≤上边界的样本数(le="+Inf"表示所有样本)。
7.3.3 示例解析
以“HTTP响应时间”指标prometheus_http_request_duration_seconds为例,其Histogram时序如下:
# 响应时间≤0.005秒的样本数:10
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="0.005"} 10
# 响应时间≤0.01秒的样本数:15(包含前10个样本)
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="0.01"} 15
# 响应时间≤5.0秒的样本数:20
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="5.0"} 20
# 所有样本的总响应时间:10.107670803秒
prometheus_http_request_duration_seconds_sum{handler="/metrics"} 10.107670803000001
# 样本总数:20(与le="+Inf"的bucket值一致)
prometheus_http_request_duration_seconds_count{handler="/metrics"} 20
7.3.4 分位数计算(histogram_quantile)
通过histogram_quantile(分位数, bucket指标)函数,可基于Histogram计算分位数(即“某比例的样本落在该值以下”):
- 定义:分位数范围为0~1(如0.9表示90%的样本值≤该结果);
- 示例:
histogram_quantile(0.9, prometheus_http_request_duration_seconds_bucket{handler="/metrics"})→ 计算90%的HTTP请求响应时间≤多少秒; - 注意:函数假设每个bucket内的样本“线性分布”,结果为预估值,准确度取决于bucket划分的粒度(粒度越细,准确度越高)。
7.4 Summary(摘要)
7.4.1 定义与特性
- 定义:与Histogram类似,用于存储“样本分布”,但分位数在“客户端计算并上报”,Prometheus Server直接抓取结果;
- 适用场景:与Histogram一致(如响应时间分布),但更适合“客户端资源充足”的场景;
- 核心特性:分位数在客户端预计算,Server无需再处理,减少Server压力。
7.4.2 生成的时间序列
Summary指标以<basename>为前缀,生成3类时序:
1、<basename>_sum:所有样本值的总和;
2、<basename>_count:样本总数;
3、<basename>{quantile="x"}:预计算的分位数(x为0~1的数值)。
7.4.3 示例解析
以“Prometheus的wal_fsync操作耗时”指标prometheus_tsdb_wal_fsync_duration_seconds为例:
# 50分位数(中位数):0.012352463秒
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.012352463
# 90分位数:0.014458005秒
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.014458005
# 99分位数:0.017316173秒
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.017316173
# 所有操作的总耗时:2.888716127秒
prometheus_tsdb_wal_fsync_duration_seconds_sum 2.888716127000002
# 操作总数:216次
prometheus_tsdb_wal_fsync_duration_seconds_count 216
解析:该指标表示Prometheus的wal_fsync操作共执行216次,总耗时约2.89秒,其中50%的操作耗时≤0.012秒,99%的操作耗时≤0.017秒。
7.4.4 Histogram与Summary的异同
| 对比维度 | Histogram | Summary |
|---|---|---|
| 相同点 | 1、均包含<basename>_sum和<basename>_count;2、均用于分析样本分布,解决长尾问题; | 1、均包含<basename>_sum和<basename>_count;2、均用于分析样本分布,解决长尾问题; |
| 不同点-分位数计算 | 分位数在Server端基于bucket估算(需histogram_quantile函数) | 分位数在客户端预计算,Server直接抓取; |
| 不同点-存储内容 | 存储bucket的样本数(需配置bucket区间) | 存储预计算的分位数(无需配置区间) |
| 不同点-准确度 | 准确度依赖bucket粒度(粒度越细越准) | 准确度由客户端计算逻辑决定(通常更准) |
| 不同点-资源消耗 | Server端计算分位数消耗资源 | 客户端计算分位数消耗资源 |
八、Prometheus的聚合函数
聚合函数用于对“多时间序列的样本”进行统计计算,生成具有汇总意义的结果。
8.1 聚合函数的作用
- 核心作用:将“多个时序的样本”按规则汇总为“单个或分组的样本”,实现“分组统计、全局汇总”等需求;
- 常见场景:统计所有节点的CPU平均使用率、按实例分组统计内存使用总和、计算分位数分布等。
8.2 内置11种聚合函数详解
Prometheus内置11种聚合函数,各函数的功能与适用场景如下:
| 函数名 | 功能描述 | 示例 |
|---|---|---|
sum() | 对样本值求和 | sum(node_memory_MemFree_bytes) → 所有节点空闲内存总和 |
min() | 求取样本值中的最小值 | min(cpu_temp_celsius) → 所有节点CPU最低温度 |
max() | 求取样本值中的最大值 | max(node_cpu_seconds_total{mode="idle"}) → 空闲CPU时间最长的时序 |
avg() | 对样本值求平均值 | avg(node_load1) → 所有节点1分钟负载的平均值 |
count() | 统计分组内的时间序列数量 | count(prometheus_http_requests_total) → 该指标的时序总数 |
stddev() | 对样本值求标准差(反映数据波动程度) | stddev(node_load5) → 所有节点5分钟负载的标准差 |
stdvar() | 对样本值求方差(标准差的平方,中间计算结果) | stdvar(node_load5) → 所有节点5分钟负载的方差 |
topk(n, 指标) | 返回分组内样本值最大的前n条时序 | topk(2, node_memory_MemUsed_bytes) → 内存使用最大的前2个节点 |
bottomk(n, 指标) | 返回分组内样本值最小的前n条时序 | bottomk(2, node_memory_MemFree_bytes) → 空闲内存最小的前2个节点 |
quantile(x, 指标) | 计算分组内样本的x分位数(x∈[0,1]) | quantile(0.5, node_load1) → 所有节点1分钟负载的中位数 |
count_values("标签名", 指标) | 统计样本值的分布,生成“值→数量”的时序(标签名为统计结果的标签键) | count_values("request_count", prometheus_http_requests_total) → 按请求数分组统计时序数量 |
8.3 聚合函数的使用场景
1、全局汇总:对所有时序进行统计(如sum(node_cpu_seconds_total{mode="used"}) → 所有节点CPU总使用时间);
2、分组统计:按标签分组后统计(如sum(node_memory_MemUsed_bytes) by (instance) → 按实例分组统计内存使用总和);
3、异常分析:通过分位数、标准差识别异常(如quantile(0.99, http_request_duration_seconds) → 99%的请求响应时间阈值,超过则视为异常)。
九、PromQL的聚合表达式
聚合表达式是“聚合函数+分组子句(by/without)”的组合,用于实现“按标签分组聚合”。
9.1 聚合表达式的语法格式
支持两种等价的语法格式(推荐第一种,可读性更高):
1、<聚合函数>(向量表达式) by|without (标签列表);
2、<聚合函数> by|without (标签列表) (向量表达式)。
9.2 by与without子句的区别
- by (标签列表):仅保留“标签列表中的标签”作为分组依据,其他标签被忽略;
- 作用:显式指定分组维度,保留关键上下文(如job、instance);
- 示例:
sum(node_memory_MemUsed_bytes) by (instance, job)→ 按instance和job分组,统计每组的内存使用总和;
- without (标签列表):从结果中“删除标签列表中的标签”,剩余标签作为分组依据;
- 作用:排除无关标签,简化结果;
- 示例:
sum(node_memory_MemUsed_bytes) without (cpu)→ 排除cpu标签,按其他标签分组统计内存使用总和。
9.3 聚合表达式实战示例
以下示例覆盖服务器、容器、K8S等常见监控场景,帮助读者理解实际用法:
9.3.1 示例1:每台主机CPU最近5分钟的平均使用率
(1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance)) * 100
- 解析:
1、node_cpu_seconds_total{mode="idle"}→ 筛选CPU空闲时间的指标;
2、rate(...)→ 计算过去5分钟内空闲CPU的平均增长率;
3、avg(...) by (instance)→ 按实例分组,计算每组的平均空闲增长率;
4、1 - ...→ 用1减去空闲率,得到使用率;
5、*100→ 转换为百分比。

9.3.2 示例2:查询1分钟负载(load1)是否超过CPU核心数的2倍
node_load1 > on (instance) 2 * count(node_cpu_seconds_total{mode="idle"}) by (instance)
- 解析:
1、node_load1→ 节点1分钟负载;
2、count(node_cpu_seconds_total{mode="idle"}) by (instance)→ 按实例分组,统计CPU核心数(每个核心对应一条idle时序);
3、2 * ...→ CPU核心数的2倍;
4、> on (instance)→ 按instance标签对齐,筛选负载超过2倍核心数的实例。
9.3.3 示例3:计算主机内存使用率
(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) / node_memory_MemTotal_bytes * 100
- 解析:
1、可用内存 = 空闲内存(MemFree)+ 缓存(Buffers + Cached);
2、已用内存 = 总内存(MemTotal)- 可用内存;
3、使用率 = 已用内存 / 总内存 * 100(百分比)。

9.3.4 示例4:统计所有node节点的容器总计内存(单位:GB)
sum by (instance) (container_memory_usage_bytes{instance=~"node*"}) / 1024 / 1024 / 1024
- 解析:
1、container_memory_usage_bytes{instance=~"node*"}→ 筛选node节点的容器内存使用指标;
2、sum by (instance)→ 按实例分组,统计每组容器内存总和;
3、/1024/1024/1024→ 将字节(Bytes)转换为GB。
9.3.5 示例5:计算node01节点最近1分钟所有容器的CPU使用率
sum(rate(container_cpu_usage_seconds_total{instance="node01"}[1m])) / sum(machine_cpu_cores{instance="node01"}) * 100
- 解析:
1、rate(container_cpu_usage_seconds_total{instance="node01"}[1m])→ 计算node01节点容器CPU的每秒增长率;
2、sum(...)→ 求和得到所有容器的总CPU使用率;
3、sum(machine_cpu_cores{instance="node01"})→ 得到node01节点的CPU总核心数;
4、/ ... *100→ 计算容器总CPU使用率占节点核心数的百分比。
9.3.6 示例6:计算最近5分钟每个容器的CPU使用变化率
sum(rate(container_cpu_usage_seconds_total[5m])) by (container_name)
- 解析:
1、rate(...)→ 计算容器CPU的每秒增长率;
2、sum(...) by (container_name)→ 按容器名分组,统计每个容器的CPU总增长率。
9.3.7 示例7:查询K8S集群最近1分钟每个Pod的CPU使用变化率
sum(rate(container_cpu_usage_seconds_total{image!="", pod_name!=""}[1m])) by (pod_name)
- 解析:
1、container_cpu_usage_seconds_total{image!="", pod_name!=""}→ 筛选有镜像和Pod名的容器(排除无关容器);
2、rate(...)→ 计算CPU每秒增长率;
3、sum(...) by (pod_name)→ 按Pod名分组,统计每个Pod的总CPU增长率(一个Pod包含多个容器,需求和)。
总结
PromQL作为Prometheus的核心查询语言,其知识点环环相扣:从“数据模型(指标+标签)”到“选择器(筛选时序)”,再到“指标类型(Counter/Gauge等)”和“聚合函数(统计分析)”,每个模块都是构建复杂查询的基础。
学习PromQL的关键在于“理解原理+多练实战”:
1、原理层面:明确时间序列的唯一标识规则、不同指标类型的适用场景、聚合函数的分组逻辑;
2、实战层面:结合Grafana可视化、Prometheus告警规则,尝试编写CPU、内存、容器、K8S等场景的查询表达式,逐步积累经验。
掌握PromQL后,你将能轻松从Prometheus的时序数据中提取有价值的信息,为系统监控、性能分析、故障排查提供有力支撑。后续可进一步深入PromQL的高级特性(如向量匹配、函数嵌套),不断提升查询能力。
