05. Prometheus - PromQL

PromQL

PromQL 是 Prometheus 内置的数据查询语言,其提供对时间序列数据丰富的查询,聚合以及逻辑运算能力的支持。并被广泛应用在 Prometheus 的日常数据查询、可视化、告警处理当中。

可以这么说,PromQL 是 Prometheus 所有应用场景的基础,理解和掌握 PromQL 是 Prometheus 入门的第一课。

如果把 Prometheus 和常见的关系型数据库 MySQL 对比着看。每个指标就相当于 MySQL 中的表,PromQL 就类似于 MySQL 中的 Select 语句,标签筛选就类似于 Select 中加入了 Where 条件限制。

标签筛选

用户可以直接通过指标名称获取到 exporter 采集到的样本数据:

prometheus_http_requests_total

如图所示:

image


这样采集的数据可能会包含多个拥有不同标签的指标,为了更精确的获取到想要的指标数据,就需要进行标签筛选:

prometheus_http_requests_total{handler=~"/api.*|/metrics", code="200"}

如图所示:

image

PromQL 支持两种对于标签的匹配模式:

  • 完全匹配:= 和 !=
  • 正则匹配:=~ 和 !~

PromQL 合法性

所有的 PromQL 表达式都必须至少包含一个指标名称,或一个不会匹配到空字符串的标签过滤器。

合法的表达式

# 只有指标名称
prometheus_http_requests_total

# 标签为空为指标
prometheus_http_requests_total{}

# 普通的标签筛选
prometheus_http_requests_total{code="200"}

# 正则的标签筛选
prometheus_http_requests_total{handler=~"/api.*|/metrics", code="200"}

# 只有标签的筛选
{code="200"}

# 使用名称的筛选
{__name__="prometheus_http_requests_total"}

不合法的表达式

# 都是能匹配到空,所以不合法
{job=~".*"}
{job=""}

瞬时向量和区间向量

通过 PromQL 查询到的数据可以分为两类:

  • 瞬时向量:最新的值,常用于监控告警。
  • 区间向量:某一时间段范围的值,常用于数据分析。

瞬时向量

如果 PromQL 表达式中如果没有使用 时间范围选择器 [] 的,那么这个向量就是瞬时向量。

node_memory_MemFree_bytes

如图所示:

image


区间向量

node_memory_MemFree_bytes[1m]

如图所示:

image

显示画图:

image

特别说明:

  1. 由于采集间隔为 15s,所以获取 1 分钟的数据会返回 4 个值。
  2. 绘图只能使用瞬时向量,因为一般的绘图都会自带一个时间选择器,如果使用区间向量则时间范围重复,出现报错。
  3. 时间范围选择器支持 s(秒),m(分钟),h(小时),d(天),w(周),y(年)等单位,但是不能使用 1.5h,只能是 1h30m。

时间偏移

前面查询到的数据都是从当前时间作为截止时间获取的,有时候也需要获取历史某个时间的值,此时就需要使用到时间偏移。

# 获取 5 分钟前 1 分钟内的数据
node_memory_MemFree_bytes[1m] offset 5m

如图所示:

image

数学运算符 / 算术运算符

某些监控指标获取到的值有些时候是不好直接拿来使用的,需要进行一定的计算,于是便需要使用到算术运算符。

常见的数学运算符包含以下:

  • +:加法
  • -:减法
  • *:乘法
  • /:除法
  • %:求余
  • ^:幂运算

使用示例:

# 获取可用内存为多少 M
(node_memory_MemFree_bytes + node_memory_Cached_bytes + node_memory_Buffers_bytes) / 1024 / 1024

如图所示:

image

布尔运算符 / 比较运算符

在监控告警的时候,需要对采集到的值进行判断,此时就需要使用到布尔运算符。

常见的布尔运算符包含以下:

  • ==:相等
  • !=:不相等
  • >:大于
  • <:小于
  • >=:大于等于
  • <=:小于等于

使用实例:

# 获取内存使用率大于 10% 的数据
(1 - ((node_memory_MemFree_bytes + node_memory_Cached_bytes + node_memory_Buffers_bytes) / node_memory_MemTotal_bytes)) * 100 > 10

如图所示:

image

在某些场景下并不是为了筛选,而是想要获取布尔值(true 为 1,false 为 0):

# 获取 bool 值
(1 - ((node_memory_MemFree_bytes + node_memory_Cached_bytes + node_memory_Buffers_bytes) / node_memory_MemTotal_bytes)) * 100 > bool 10

如图所示:

image

集合运算符

集合运算符更多的还是用于数据的筛选。

常见的集合运算符包含以下:

  • and:并且
  • or:或者
  • unless:排除

使用示例:

# 多条件筛选,并列条件,取交集
prometheus_http_requests_total{code!="400"} and prometheus_http_requests_total{handler!~"/api.*"}

# 多条件筛选,并列条件,取并集
prometheus_http_requests_total{code="400"} or prometheus_http_requests_total{handler!~"/api.*"}

# 多条件筛选,从结果中排除
prometheus_http_requests_total unless prometheus_http_requests_total{code="200"}

如图所示:

image

操作符优先级

对于复杂的 PromQL 表达式一般都会包含多种运算符,同种运算符,不同运算符之间都是由执行优先级的,具体先后顺序如下:

  • ^
  • *, /, %
  • +, -
  • ==, !=, <=, <, >=, >
  • and, unless
  • or

内置函数 / absent(取布尔值)

以瞬时向量做参数,判断该瞬时向量是否有值:

  • 如果有值,则返回空向量。
  • 如果没有值,则返回不带标签的名称时间序列,值为 1。

使用示例:

# 有值返回空
absent(prometheus_http_requests_total)

# 没值返回 1
absent(prometheus_http_requests_totalxxx)

有效的:

image

无效的:

image

该方法可以用于判断给定的 PromQL 不存在。

内置函数 / abs(绝对值)

用于返回绝对值,将负数转换成正数。

abs(node_memory_MemFree_bytes - node_memory_MemTotal_bytes)

如图所示:

image

内置函数 / round(四舍五入取整)

返回结果四舍五入取整:

round((node_memory_MemFree_bytes / node_memory_MemTotal_bytes) * 100)

如图所示:

image

内置函数 / clamp_max(对比取值)

clamp_max 用于比较瞬时向量和传入的值,谁小返回谁。clamp_min 反之。

clamp_max(node_memory_MemFree_bytes / node_memory_MemTotal_bytes, 1)

如图所示:

image

内置函数 / label_join(新增标签)

新增标签,但值来源于原来的标签的值的组合。

label_join(prometheus_http_requests_total{handler="/metrics"}, "url", "==", "instance", "handler")

结果如图:

image

新标签名称第一个参数为分隔符,后面的就是各种需要组合的标签,每个组合的值中间都有一个分隔带。

内置函数 / label_replace(标签替换)

将筛选的标签值进行替换:

label_replace(prometheus_http_requests_total{code="200"}, "code", "$1", "instance", "(.*):.*")

如图所示:

image

内置函数 / predict_linear(预测)

该方法常用于监控告警中,用于预测未来发生故障的时间。

# 根据 10 分钟的磁盘空闲情况推测 12 小时后磁盘空闲情况
predict_linear(node_filesystem_free_bytes{mountpoint="/"}[10m], 12*3600) / 1024 / 1024 / 1024

如图所示:

image

内置函数 / rate(区间增长率)

通过区间向量计算平均增长速率,该函数返回结果不带度量指标。

# 以 5 分钟为基准计算请求的每秒增长率
rate(prometheus_http_requests_total{handler="/metrics"}[1m])

如图所示:

image

内置函数 / irate(瞬时增长率)

通 rate 类似,用于计算区间向量的增长率,但与 rate 不同的是他是用于计算瞬时向量的增长率,通过区间向量中最后两个样本数据来计算区间向量的增长速率。

irate(prometheus_http_requests_total{handler="/metrics"}[1m])

如图所示:

image

特别说明:

irate 只能用于绘制快速变化的计数器,在长期趋势分析或者告警中更推荐使用 rate 函数。因为使用 irate 函数时,速率的简短变化会重置 FOR 语句,形成的图形有很多波峰,难以阅读。

内置函数 / sort(升序排序)

将多组数据按照升序排序,相反则使用 sort_desc。

sort(prometheus_http_requests_total{handler=~"/api/.*"})

如图所示:

image

内置函数 / delta(计算差值)

用于计算一段时间的变化值。

# 计算过去 1 小时磁盘使用了多少 M
abs(delta(node_filesystem_free_bytes{mountpoint="/"}[1h]) / 1024 / 1024)

如图所示:

image

聚合查询

通过获取一个即时向量并聚合它的元素,从而得到一个新的瞬时向量。

常用的聚合函数包含以下:

  • sum:求和
  • min:最小值
  • max:最大值
  • avg:平均值
  • count:元素个数
  • count_values:等于某值的元素个数
  • bottomk:最小的 k 个元素
  • topk:最大的 k 个元素

语法格式如下:

<聚合函数>([parameter,] <指标查询语句>) [without|by (<label list>)]

其中参数 without ⽤于从计算结果中移除列举的标签,by 则相反,结果向量中只保留列出的标签。

只有 count_values , quantile , topk , bottomk ⽀持参数 parameter。

聚合函数 / sum(求和)

使用实例:

# 计算所有请求数量
sum(prometheus_http_requests_total)

如图所示:

image


结合 by 使用:

# by 通过指定的标签分组
sum(prometheus_http_requests_total) by (code)

如图所示:

image


结合 without 使用:

# without 剔除指定的标签后分组
sum(prometheus_http_requests_total) without (handler)

如图所示:

image

聚合函数 / max、min(最大最小值)

使用示例:

# 最大值
max(prometheus_http_requests_total)

# 最小值
min(prometheus_http_requests_total)

如图所示:

image

聚合函数 / avg(平均值)

使用示例:

# 计算 CPU 平均信息
avg(node_cpu_seconds_total{instance="192.168.200.101:9100"}) by (mode)

如图所示:

image

聚合函数 / count(数量统计)

使用实例:

# 统计指标下时间序列的数量
count(prometheus_http_requests_total)

如图所示:

image

聚合函数 / count_values(值出现次数)

# 根据值进行分类统计并自定义标签,标签的值为指标的值
count_values("request_times", prometheus_http_requests_total)

如图所示:

image

聚合函数 / topk、bottomk(前后 k 个)

使用示例:

# 请求前 3
topk(3, prometheus_http_requests_total)

# 请求后 3
bottomk(3, prometheus_http_requests_total)

如图所示:

image

子查询

常用的子查询有以下四个:

  • avg_over_time:指定间隔内所有样本数据的平均值。
  • min_over_time:指定间隔内所有样本数据的最小值。
  • max_over_time:指定间隔内所有样本数据的最大值。
  • sum_over_time:指定间隔内所有样本数据的总和。

使用示例:

avg_over_time(node_memory_MemFree_bytes[1d]) / 1024 / 1024 / 1024
min_over_time(node_memory_MemFree_bytes[1d]) / 1024 / 1024 / 1024
max_over_time(node_memory_MemFree_bytes[1d]) / 1024 / 1024 / 1024
sum_over_time(node_memory_MemFree_bytes[1d]) / 1024 / 1024 / 1024

综合查询示例

查看 CPU 平均使用率

# CPU 平均使用率
(1 - avg(irate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance)) * 100

查看 CPU 负载

# 1 分钟
node_load1
# 5 分钟
node_load5
# 15 分钟
node_load15

计算 CPU 数量

count(node_cpu_seconds_total{mode="idle"}) by (instance)

查询负载是 CPU 值的两倍的数据用于告警

node_load1 > on (instance) count(node_cpu_seconds_total{mode="idle"}) by (instance) * 2

内存使用率

(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) / node_memory_MemTotal_bytes * 100

磁盘使用率

(1 - node_filesystem_free_bytes{mountpoint!~"/boot|/run.*"} / node_filesystem_size_bytes{mountpoint!~"/boot|/run.*"}) * 100

特别说明:df 看到的值比监控的值一般会大 1%,原因在于 Linux 本身会预留一部分给 root,避免磁盘写满 root 无法操作。而 exporter 获取到的不包含那部分。


磁盘空间预测

# 预测 12 小时后磁盘使用率
(1 - (predict_linear(node_filesystem_free_bytes{mountpoint="/"}[1h], 3600 * 12) / node_filesystem_size_bytes)) * 100

节点状态查询

up{job="node-exporter"}
posted @ 2022-08-21 11:14  不知名换皮工程师  阅读(1427)  评论(0编辑  收藏  举报