PromQL (Prometheus Query Language)是 Prometheus 监控系统内置的一种查询语言,PromQL 允许你以灵活的方式选择、聚合等其他方式转换和计算时间序列数据,帮助用户快速地查询和分析监控数据,并生成有意义的报告和图表。
原理
PromQL基于时间序列模型,即将数据按时间序列进行存储和查询。Prometheus将所有时间序列数据存储为样本值(即某个指标在某个时间点的值),每个时间序列都由一个唯一的标识符(即指标名称和一组标签)来标识。PromQL通过使用这些标识符来查询和聚合时间序列数据。
PromQL提供了一些基本的查询操作,如过滤器、聚合器、函数等,可以帮助用户快速地查询和分析数据。其中,过滤器可以根据指标名称和标签对时间序列进行筛选;聚合器可以对时间序列数据进行汇总、计数、平均值等操作;函数可以对时间序列数据进行操作,如计算增长率、求导数等。
Prometheus 的数据模型
时间序列
Prometheus 会将所有采集到的样本数据以时间序列的方式保存在内存数据库中,并且定时保存到硬盘。时间序列是Prometheus数据模型的核心概念,它由一组标识符和一系列时间戳-值对组成。每个时间序列都由一个唯一的标识符来标识,这个标识符由两部分组成:指标名称和一组标签。指标名称用于表示被测量的对象,标签用于区分不同的实例或维度。例如,指标名称可以是http_requests_total,标签可以是job=five_munite_sre和status_code=200。
可以看到:
时序的名字由 ASCII 字符,数字,下划线,以及冒号组成,它必须满足正则表达式 [a-zA-Z_:][a-zA-Z0-9_:]*, 其名字应该具有语义化,一般表示一个可以度量的指标,例如: http_requests_total, 可以表示 http 请求的总数。
时序的标签可以使 Prometheus 的数据更加丰富,能够区分具体不同的实例,例如 http_requests_total{method="POST"} 可以表示所有 http 中的 POST 请求。
时序数据可以被理解为一个以时间为轴的矩阵。在这个矩阵中,每一行代表一个时间戳,每一列代表一个时间序列,矩阵中的每个单元格则表示一个特定时间戳下某个时间序列的值。
假设有以下两个时间序列:
代码语言:javascript复制http_requests_total{job="five_munite_sre", status_code="200"} 100
http_requests_total{job="five_munite_sre", status_code="500"} 10
这两个时间序列表示了job为five_munite_sre,状态码为200和500的http请求总数。假设这两个时间序列在5分钟内每分钟采集一次数据,则它们的时间戳序列可以表示为:
代码语言:javascript复制t0 t1 t2 t3 t4
其中,t0-t4表示采样时间点,例如t0表示开始采样的时间点,t1表示第一次采样的时间点,以此类推。这里我们假设每个时间点的时间戳是相同的,这是为了简化示例,实际上时间戳可能会有微小的差异。
将这两个时间序列表示为矩阵,则可以得到以下矩阵:
这个矩阵的每一列表示一个时间序列,每一行表示一个时间点。矩阵中的每个单元格表示了对应时间序列在对应时间点的值。例如,第一行的第一个单元格表示了http_requests_total{job="five_munite_sre", status_code="200"}在t0时的值为100。
PromQL的查询结果也可以表示为一个时间序列矩阵,例如以下查询:
代码语言:javascript复制http_requests_total{job="five_munite_sre"}
这个查询表示要获取所有job为five_munite_sre的http请求总数。查询结果可以表示为以下时间序列矩阵:
这个矩阵表示了所有job为five_munite_sre的http请求总数在不同时间点的值,其中每一列表示一个时间序列,每一行表示一个时间点。
每一个点称为一个样本(sample),样本由三部分组成。
代码语言:javascript复制指标(metric):metric name 和描述当前样本特征的 labelsets。
时间戳(timestamp):一个精确到毫秒的时间戳。
值(value):表示该时间样本的值。
PromQL 就是对这样一批样本数据做查询和计算操作。
指标类型
在Prometheus中,所有的上报的数据都以时间序列保存在prometheus内存的时序数据库,从存储上看所有监控指标的metric都是一样的,但是不用场景下又会存在一些差异,比如我们之前安装的node-exporter 采集到的数据中的指标:node_load1 与node_cpu_seconds_total,node_load1指标是当前系统的负载情况,随时间的变化指标的数据是不断变化的,node_cpu_seconds_total指标是CPU累计的使用时间,随着时间的变化只要不重启,这个值是一直变大的。
为此Prometheus定义了四种不同的指标类型(metric type),可以让我们更好的理解不同监控指标之间的差异。分别是:
代码语言:javascript复制Counter(计数器)
Gauge(仪表盘)
Histogram(直方图)
Summary(摘要)
Counter
Counter是一个计数器,它累加自己在一段时间内发生的事件次数。Counter从不减少,只有增加。在PromQL中,可以使用增量操作符来查询Counter的值。常见的监控指标,如 http_requests_total、node_cpu_seconds_total 都是 Counter 类型的监控指标。
例如,下面的查询将返回一个Counter的当前值:
代码语言:javascript复制my_counter_total
Gauge
Gauge是一个可以增加或减少的指标,表示某个值的瞬时状态,例如CPU使用率或内存使用情况。Gauge的值可以随时间而变化,类型的指标侧重于反应系统的当前状态。在PromQL中,可以使用标准的算术操作符来查询Gauge的值。常见指标如 node_memory_MemFree_bytes(当前主机空闲的内存大小)、node_memory_MemAvailable_bytes(可用内存大小)都是 Gauge 类型的监控指标
例如,下面的查询将返回一个Gauge的当前值:
代码语言:javascript复制my_gauge
代码语言:javascript复制Histogram
Histogram是用于测量和记录数据集中值的分布情况的指标。Histogram将数据集划分为桶(buckets),并记录每个桶中的数据点数量。在PromQL中,可以使用桶操作符来查询Histogram的值。
例如,下面的查询将返回一个Histogram的值:
代码语言:javascript复制my_histogram_bucket{le="0.5"}
Summary
Summary是Histogram的一种变体,它记录了所有观测值的总数和它们的总和,并且可以计算出给定百分比的观测值的排名。在PromQL中,可以使用标准的算术操作符和percentile函数来查询Summary的值。
例如,下面的查询将返回一个Summary的值:
代码语言:javascript复制my_summary{quantile="0.5"}
表达式语言数据类型
PromQL是Prometheus的查询语言,它支持多种数据类型。在PromQL中,表达式是由函数、操作符、常量和变量组成的。一个表达式或子表达式可以计算为以下四种类型之一:
代码语言:javascript复制instant vector(瞬时/即时向量):一组时间序列,每个时间序列包含一个样本,所有数据样本共享相同的时间戳。
Range vector(范围向量):一组时间序列,其中包含每个时间序列随时间变化的一系列数据点
Scalar(标量):一个简单的数字浮点值
String(字符串):一个简单的字符串值。目前未使用
字符串和数字
字符串
在查询语句中,字符串往往作为查询条件 labels 的值,和 Golang 字符串语法一致,可以使用 "", '', 或者 ``, 但是在反引号内不处理转义字符,与 Go 不同,Prometheus 不会丢弃反引号中的换行符。格式如:
代码语言:javascript复制"this is a string"
'these are unescaped: n \ t'
`these are not unescaped: n ' " t`
正数,浮点数
表达式中可以使用正数或浮点数,标量浮点值可以表示为[-](digits)[.(digits)]形式
例如:
代码语言:javascript复制3
-2.4
查询条件
即时向量选择器
瞬时向量选择器允许在给定时间戳(瞬时)上选择一组时间序列和每个样本的当个采样值:在最简单的形式中,仅指定度量名称。这会生成包含具有该数据指标名称的所有时间序列的元素的即时向量。
一个简单的查询相当于是对各种标签的筛选,例如:
代码语言:javascript复制http_requests_total{code="200"} // 表示查询名字为 http_requests_total,code 为 "200" 的数据
也可以反向匹配标签值,或将标签值与正则表达式匹配。标签匹配操作符如下所示:
代码语言:javascript复制
=: 选择与提供的字符串完全相同的标签(精确匹配)
!=: 选择不等于提供的字符串的标签(反向匹配)
=~: 选择与提供的字符串进行正则表达式匹配的标签(正则表达式匹配)
!~: 选择正则表达式不匹配提供的字符串的标签(反向正则表达式匹配)
例如:
代码语言:javascript复制http_requests_total{environment=~"dev|uat",method!="POST"} //选择所有`dev`, `uat`,环境且 HTTP 请求方法不是`POST`的`http_requests_total`时间序列
http_requests_total{code!~"2.."} // 表示查询 code 不为 "2xx" 的数据
需要注意的是,metric name 也是一个非常重要的过滤条件,可以写到大括号里,比如我想同时查看zone="sz"的 load1、load5、load15 三个指标,可以对 name,也就是 metric 名字做正则过滤。
代码语言:javascript复制{__name__=~"node_load.*", zone="sz"}
范围向量选择器
范围向量选择器的用法跟瞬时向量选择器基本相同,唯一的不同是在时间点加上时间区间变成时间段,用法就是在结尾加上[],以指定为每个范围向量元素提取多久的时间值。
持续时间指定为数字,紧随其后的是以下单位之一:
代码语言:javascript复制s - 秒
m - 分钟
h - 小时
d - 天
w - 周
y - 年
例如:
代码语言:javascript复制http_requests_total{environment=~"dev|uat",method!="POST"}[10h] //选择10小时内所有`dev`, `uat`,环境且 HTTP 请求方法不是`POST`的`http_requests_total`时间序列
http_requests_total{code!~"2.."}[10m] // 表示查询10分钟内 code 不为 "2xx" 的数据
偏移量
偏移量(Offset)是指从当前时间向前或向后移动的时间段。使用偏移量可以对Prometheus中的时间序列数据进行相对时间的计算,从而可以实现更灵活的数据查询和分析。偏移量的时间表达式跟上面的选择器一样。
PromQL中的偏移量使用offset关键字进行定义,其语法格式为:
代码语言:javascript复制<query_expression> offset <duration> //query_expression是查询表达式,duration是时间段,可以使用golang时间格式或Prometheus持续时间格式进行指定。复制
例如:
代码语言:javascript复制http_requests_total{method="GET"} offset 5m //过去5分钟内名称为http_requests_total且标签method="GET"的时间序列数据
http_requests_total{method="GET"} offset 1h // 向过去移动1小时
http_requests_total{method="GET"} offset -1d // 向未来移动1天
除了使用固定的时间段之外,还可以使用相对时间段进行偏移量计算。相对时间段使用以下格式进行指定:
代码语言:javascript复制<duration> <direction> //duration是持续时间,direction是方向,可以使用now、after、before三个关键字进行指定
代码语言:javascript复制例如:
代码语言:javascript复制http_requests_total{method="GET"} offset 30m after now //返回从现在起未来30分钟内的数据
这个篇章我们主要先了解下PromQL的入门概念,下一篇我们继续PromQL的运算符,函数与聚合等功能操作的讲解。
可以查看原文:
https://mp.weixin.qq.com/s?__biz=MzA5NTgwNzY1NA==&mid=2247484019&idx=2&sn=48943480f439d5072bfe6f19d61c0f53&chksm=90b8f3baa7cf7aac077f477c022bf4d2d9e7c413258c74161e360c1616481f6be3298886cd2e&token=889147174&lang=zh_CN#rd
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!