[TOC]

0x00 PromQL 介绍

1.基础简述

Q: 什么是PromQL?

答: PromQL (Prometheus Query Language) 函数式查询语言 是 Prometheus 自己开发的数据查询 DSL 语言,可以让用户实时选择和聚合时间序列数据。

它类似于 SQL 的语言,但是PromQL表现力非常丰富,并且内置函数很多,在日常数据可视化以及 rule 告警中都会使用到它。

Tips: 我们把每个查询对象得名字叫做Metrics度量值。

Tips: 标签是PromQL的关键部分,不仅可以使用它们进行任意聚合,还可以将不同的指标连接在一起,以对其进行算术运算。

Q: 如果进行Prometheus采集的数据查询?

答: 在Prometheus Server的后台里面输入指标名称(会自动补齐), 如最近一个时间间隔(采集周期)下的值prometheus_prometheus_http_requests_total;

Q: 如何使用 PromQL 语句通过内置表达式浏览器进行查询?

  • (1) 使用Prometheus的内置表达式浏览器,利用PromQL语句进行查询我们监控的指标。

例如: Prometheus 服务器已服务的/metrics请求的总数指标: promhttp_metric_handler_requests_total

1
2
3
4
5
6
// 请求`/metrics`返回`code=200`为条件进行查询
promhttp_metric_handler_requests_total{code="200"}
// promhttp_metric_handler_requests_total{code="200", instance="aiserver", job="Prod"} 80619

// 计算返回的请求为200的总数指标时间序列总数
count(promhttp_metric_handler_requests_total{code="200"}) // {} 34

  • (2) 使用Graph选项卡,展示查询到的数据
    例如,输入以下表达式来绘制在自我抓取的Prometheus中发生的返回状态代码200的每秒HTTP请求率:
    1
    2
    rate(promhttp_metric_handler_requests_total{code="200",job="LocalServer"}[5m])
    # {code="200", instance="localhost:9090", job="LocalServer"} 0.016666666666666666
    您可以尝试图形范围参数和其他设置。

WeiyiGeek.Graph


2.基础标准

2.1 时间单位:
描述: Prometheus 中的持续时间被用于 PromQL配置文件中,它支持的单位如下:

单位 含义
ms 毫秒
s 秒, 等于 1000 ms
m 分钟, 等于 60 s
h 小时, 等于 60 min
d 天, 等于 24h
w 周, 等于 7d
y 年, 等于 365d

以下是一些有效持续时间的示例:

1
2
3
4
5h
1h30m
5m
10s

Tips : 你可以使用一个整数带一个单位,例如90m是有效的,而1h30m1.5h不是有效的。
Tips : 并且闰年和闰秒都是被忽略的,1y 总是 (60 * 60 * 24 * 365s)


2.2 文字
(1) 字符串文字: 字符串可以在单引号、双引号或反引号中指定为文字。
PromQL 遵循与Go相同的转义规则。在单引号或双引号中,反斜杠开始一个转义序列,后面可以跟a, b, f, n, r, t,v或\。可以使用八进制 (\nnn) 或十六进制 (\xnn,\unnnn和\Unnnnnnnn)提供特定字符。

Tips : 非常注意的是与 Go 不同,Prometheus 不会丢弃反引号内的换行符(反引号内不处理转义)。

例子:

1
2
3
"this is a string"
'these are unescaped: \n \\ \t'
`these are not unescaped: \n ' " \t`

(2) 浮动文字: 标量浮点值可以按以下格式写成文字整数或浮点数(仅包含空格以提高可读性)。

1
2
3
4
5
6
[-+]?(
[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?
| 0[xX][0-9a-fA-F]+
| [nN][aA][nN]
| [iI][nN][fF]
)

例子:

1
2
3
4
5
6
23
-2.43
3.4e-9
0x8f
-Inf
NaN


3.数据类型

描述: 在 Prometheus 的表达式语言中,表达式或子表达式可以计算为以下四种类型之一:

瞬时数据 (Instant vector)

即时时向量选择器: 查询评估时间之前返回最近样本的瞬时向量,即零个或者多个时间序列的列表,每个时间序列包含一个样本,所有时间序列都共享相同的时间戳。并且当你使用瞬时向量选择器时,不会返回已过时的时间序列。

示例说明:

1
2
3
# (1) 包含一组时序,每个时序只有一个点,例如:`prometheus_prometheus_http_requests_total`
node_timex_status[2m]
# node_timex_status{instance="aiserver", job="Prod"} 8193 @1629298587.604

Tips: 例如返回即时向量的表达式是唯一可以直接绘制的类型。


区间数据 (Range vector)

范围向量选择器: 与每个时间序列返回一个样本的瞬时向量选择器不同,范围选择器为每个时间序列返回多个样本(包含一组时序,每个时序有多个点)即(包含每个时间序列随时间变化的数据点范围),并且范围向量总是与rate、avg_over_time函数联合使用。

示例说明:

1
2
3
4
5
6
7
8
9
# (1) 查询执行时间为准按照分钟粒度返回与选择器匹配的所有时间序列
process_cpu_seconds_total{instance="aiserver"}[1m]

54969.1 @1629292827.605
54969.3 @1629292837.605
process_cpu_seconds_total{instance="aiserver", job="Prod"} 54969.1 @1629292847.605
54969.2 @1629292857.605
54969.2 @1629292867.605
54969.1 @1629292877.605

Tips : 上述示例结果中每个时间序列的样本恰好相差10s,这与Prometheus配置的抓取时间相关一致,但两个时间序列时间戳不会相互对齐。


纯量数据 (Scalar)

标量: 纯量只有一个数字,没有时序,例如:count(prometheus_prometheus_http_requests_total)执行结果为:{} 20

示例说明:

1
2
3
# (1) 纯量只有一个数字,没有时序
prometheus_prometheus_http_requests_total{code="200",}
# prometheus_prometheus_http_requests_total{code="200", handler="/metrics", instance="localhost:9090", job="LocalServer"} 82016

Tips : 在采用Graph进行展示时,查询的表达式类型”range vector”是无效可导致执行查询时出错,必须是标量或即时向量。

字符串数据 (String)

描述: 一个简单的字符串值;目前未使用。


4.选择器 - (Selector)

描述:在 Prometheus 浏览器表达式中选择器非常重要,它可以缩小我们查询或者要处理的时间序列范围。通过在花括号 ( {}) 中附加逗号分隔的标签匹配器列表来进一步过滤这些时间序列。

例如: job=”node” 被称为匹配器,并且你可以在一个选择器利用多个匹配器串在一起。

1
2
go_info{BusinessType="jszg",env="prod"}
# go_info{BusinessType="jszg", instance="192.168.1.69:9100", job="Win", version="go1.15.6"} 1


5.匹配器 - (Matcher)

描述: 常用的匹配器解析说明。

= (等式匹配器) : 最是常用的匹配器,通过此操作,你可以指定返回的时间系列包含一个具有特定值的标签。

  • 例如: job="node"作为一个空值标签和没有该标签一样, 你可以使用 foo="" 来指定 foo 标签不存在的指标。
    1
    2
    3
    // (1) 查询标签 instance 为 aiserver 以及 不存在 env 标签的 go_info 的目标 go_info 指标项。
    go_info{env="",instance="aiserver"}
    // go_info{instance="aiserver", job="K8S-Prod", version="go1.15.8"} 1

!=(否定的等式匹配器) : 通过此操作,你可以指定返回的时间系列没有包含特定值的标签。

  • 例如: job != "node"
    1
    2
    3
    // (1) 查询标签 BusinessType 为 zk 以及 version 不等于 go1.15.8 的目标 go_info 指标项。
    go_info{version!="go1.15.8",BusinessType="zk"}
    // go_info{env="prod", instance="192.168.10.67:9100", job="K8S-Prod", version="go1.15.6"} 1

=~(正则表示式匹配器) : 通过此操作,它可以定标签的值与正则表达式相匹配。表达式语法可以在百度中进行查询。

  • 例如: job =~ "n.*"
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // (1) 查询标签 instance 匹配的 "ai.*" 正则表达式匹配的目标 go_info 指标项。
    go_info{instance=~"ai.*"}
    // go_info{instance="aiserver", job="K8S-Prod", version="go1.15.8"} 1

    // (2) 注意点,向量选择器必须指定一个名称或至少一个与空字符串不匹配的标签匹配器。
    {job=~".*"} # Bad!
    // 相反,这些表达式是有效的,因为它们都有一个不匹配空标签值的选择器。
    {job=~".+"} # Good!
    {job=~".*",method="get"} # Good!

    // (3) 例如,标签匹配器也可以通过与内部__name__标签匹配来应用于度量名称, 表达式 prometheus_http_requests_total 等效于 {__name__="prometheus_http_requests_total"}。
    {__name__=~"job:.*"} // 选择名称以job开头的所有指标

!~(正则表示式反匹配器) : 通过此操作, 它可以定标签的值与正则表达式不相匹配。

  • 例如: job !~ "n.*"
    1
    2
    3
    // (1) 查询标签 env 不匹配的 "p.*" 为值的目标 go_info 指标项。
    go_info{env!~"p.*",instance="aiserver"}
    // go_info{instance="aiserver", job="K8S-Prod", version="go1.15.8"} 1

Tips : Prometheus 中的所有正则表达式都使用RE2 语法(https://github.com/google/re2/wiki/Syntax)。


示例演示:

1
2
3
4
5
6
7
8
9
# (1) 在选择器中使用具有相同标签名称的多个匹配器,查找 job 为 Linux, 标签 device 不为 `tmpfs|shm`, 标签 mountpoint 为 / 根的所以文件系统的大小。
node_filesystem_size_bytes{job=~"L.*", device!~"tmpfs|shm",mountpoint=~"/$"} / 1024^3
# { device="/dev/mapper/ubuntu--vg-lv--0", fstype="ext4", instance="192.168.1.12:9100", job="Linux", mountpoint="/"} 96.94237518310547

# (2) 在选择器中至少一个匹配器的值不能与空字符串相匹配。如 {foo="", foo!=""} 和 {foo =~ ".*"} 将返回错误,而{foo="", bar="x"} 或 {foo=~".+"} 是正常的。
node_filesystem_size_bytes{job=~"Linux", mountpoint=~"/$"} / 1024^3
# { device="/dev/mapper/ubuntu--vg-lv--0", fstype="ext4", instance="192.168.1.12:9100", job="Linux", mountpoint="/"} 96.94237518310547

# (3) 此选择所有prometheus_http_requests_total的时间序列staging, testing以及development环境和HTTP除开GET的其他方法。


6.偏移修改器 - (Offset)

描述: 该修饰符可以适用于任意类型的向量选择器,它可以让你获取查询执行时间,并在每个选择器的当前基础上将其回退到过去的这个时间上, 即可以改变时间为查询中的个别时刻和范围矢量偏移。。

Tips: 请注意 offset 修饰符总是需要立即跟随选择器

示例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 例如,以下表达式返回 prometheus_http_requests_total过去 5 分钟相对于当前查询评估时间的值:
prometheus_http_requests_total offset 5m
sum(prometheus_http_requests_total{method="GET"} offset 5m) // GOOD.

// 查询 localhost:9090 执行的内存使用情况
process_resident_memory_bytes{instance="localhost:9090"} // 731750400

// 查询 localhost:9090 执行时间前一个小时的内存使用情况
process_resident_memory_bytes{instance="localhost:9090"} offset 1h // 748228608

// 例如,同样适用于范围向量, 查询在过去的1h内导出器暴露使用的cpu变化请求(适用于范围变量)
rate(process_cpu_seconds_total{instance="localhost:9090"}[5m])
-
rate(process_cpu_seconds_total{instance="localhost:9090"}[5m] offset 1h) // -0.006089652962922479


7.修饰符 - @

描述: 所述@改性剂允许改变评价时间为查询中的个别时刻和范围的载体。提供给@修饰符的时间是一个 unix 时间戳并用浮点文字描述。

Tips : 请注意,@修饰符总是需要立即跟随选择器。
Tips : 默认情况下禁用此修饰符, 此功能通过设置 --enable-feature=promql-at-modifier 标志启用。


示例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 例如,以下表达式返回 prometheus_prometheus_http_requests_total的值 2021-01-04T07:40:00+00:00:
prometheus_prometheus_http_requests_total{handler="/metrics"} @ 1609746000

// 例如,@修饰符总是需要立即跟随选择器
sum(prometheus_prometheus_http_requests_total{handler="/metrics"} @ 1609746000) // GOOD.

// 例如,适用于范围向量,将返回5分钟的速度 prometheus_prometheus_http_requests_total 曾在2021-01-04T07:40:00+00:00:
rate(prometheus_prometheus_http_requests_total{handler="/metrics"}[5m] @ 1609746000)

// 例如,@修饰符与offset修改器一起使用,其中偏移是相对于 @ 修改器时间应用的,而不管哪个修改器首先被写入
# offset after @
prometheus_prometheus_http_requests_total @ 1609746000 offset 5m
# offset before @
prometheus_prometheus_http_requests_total offset 5m @ 1609746000

Tips : start() 并且 end() 还可以用作值@修正为特殊值,

  • 对于即时查询,start() 与 end() 都有的评估时间。
  • 对于范围查询, 它们分别解析为范围查询的开始和结束,并在所有步骤中保持不变。
    1
    2
    prometheus_prometheus_http_requests_total @ start()
    rate(prometheus_prometheus_http_requests_total[5m] @ end())
    method:prometheus_prometheus_http_requests_total:rate5m{method=”get”}


8.子查询

描述: 子查询允许您对给定的范围和分辨率运行即时查询。

Tips : 子查询的结果是一个范围向量

格式定义:

1
2
// <resolution>是可选的。默认为全局评估区间。
<instant_query> '[' <range> ':' [<resolution>] ']' [ @ <float_literal> ] [ offset <duration> ]


9.查询类型

Counter 类型

描述: 它是使用最频繁的数据类型,其记录的是事件的数量或者大小,通常用来跟踪某个特定代码路径被执行的频率,此类型其根本的的意义是计数器随着时间的推移而增加的速度。

Tips : 对于PromQL而言必须确保Counter变量是递增的,只有这样才能保证rate或者其它函数不会把counter的减少误当做应用重启后Counter置零操作。

1
2
3
4
5
6
# (1) 计算每秒接收的网络流量
rate(node_network_receive_bytes_total{job="Linux"}[5m])

# (2) [5m]表示平均5min数据的比率其返回值将过去5min的每秒平均值。
sum without(device)(rate(node_network_receive_bytes_total{job="Linux"}[5m]))
# { instance="192.168.1.12:9100", job="Linux"} 575.2595748148149

Tips : 标签没有顺序或层次结构,允许你可以根据需求聚合尽可能多的标签。


Gauge 类型

描述: 存储的是当前状态的快照,其关心的是数值本身,因此此类型的数据类型的值可升可降。例如: 使用Gauge数据类型的例子包括队列中元素个数、缓存的内存使用率,活跃的线程数,最后一分钟时间里没秒的平均请求数。

Tips : Gauge 提供三种主要的方法供你使用inc(增加)、dec(减少)或者set方法,并且可以将负值传递给Gauge类型的inc方法。

  • 查询计算每台计算机上文件系统的总大小。

    1
    2
    sum without(device,fstype,mountpoint)(node_filesystem_size_bytes{job="weiyigeek-Linux"}) / 1024^3
    # {env="prod",instance="192.168.1.12:9100", job="weiyigeek-Linux"} 201.34028244018555
  • 查询每台机器上最大的挂载文件系统的大小。

    1
    2
    3
    max without(device,fstype,mountpoint)(node_filesystem_size_bytes{job="weiyigeek-Linux"}) / 1024^3

    # {env="prod", instance="192.168.1.12:9100", job="weiyigeek-Linux"} 100
  • 查询每台机器上挂载点平均的文件系统的大小。

    1
    2
    3
    avg without(device,fstype,mountpoint)(node_filesystem_size_bytes{job="weiyigeek-Linux"}) / 1024^3

    # {env="prod", instance="192.168.1.12:9100", job="weiyigeek-Linux"} 18.303662040016867


Summary 类型

描述: 该数据类型最常用的方法是observe可以通过该方法传递事件的大小(注意必须是非负数)即跟踪延迟。

Tips: 该类型也可能包括了分为数,此外就CPU使用率而言,客户端分位数与其它测控相比是代价昂贵的(慢一百倍也不罕见)。

例如: 利用 prometheus_http_response_size_bytes_count 指标 可以 跟踪API请求的数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# (1) 查询并返回提供每秒的总请求数
sum without(handler)(rate(prometheus_http_response_size_bytes_count[5m]))
# {instance="localhost:9090", job="LocalServer"} 0.015740740740740743

# (2)查询并返回每个Handler返回的字节数
sum without(handler)(rate(prometheus_http_response_size_bytes_sum[5m]))
# {instance="localhost:9090", job="LocalServer"} 156.97563272222223

# (3) 你将_sum 除以 _count(在执行rate后)来获得一段时间内的平均值,例如下面过去 5min 的平均响应大小为值。
sum without(handler)(rate(prometheus_http_response_size_bytes_sum[5m]))
/
sum without(handler)(rate(prometheus_http_response_size_bytes_count[5m]))
# {instance="localhost:9090", job="LocalServer"} 13236

# (4) 如果要获得一个任务的所有实例平均响应字节大小
sum without(instance) (
sum without(handler)(rate(prometheus_http_response_size_bytes_sum[5m]))
)
/
sum without(instance) (
sum without(handler)(rate(prometheus_http_response_size_bytes_count[5m]))
)
# {instance="localhost:9090", job="LocalServer"} 13236


Histogram 类型

描述: 该类型指标允许你跟踪事件大小的分布(提供平均延迟数据),允许你用它们来计算分位数,分位数可以告诉你低于某个值的事件个数,例如: 0.95分位数为300ms则代表95%的请求耗时小于300ms。

Tips : 分位数和百分位我们说的95%是0.95分位数,由于更喜欢基本单位所以通常使用分位数,而在比例的时候优先使用百分位。

Tips : Histogram 类型是有标签的。

桶(Buckets)说明
描述: 默认的涵盖从1ms~10s范围内的延迟,我们可以定义指标的时候覆盖他们并提供自己的桶。建议保持在10个左右才能保证足够的准确率,该数字看起来很小的数字,但是存储桶是需要成本,并且每个桶都是一个额外的时序存储。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 用于跟踪时序数据库压缩所需的秒数 : prometheus_tsdb_compaction_duration_seconds

# (1) 在0.90分位数将用于跟踪时序数据库压缩所需的秒数, 表明压缩的第90个百分位延约为 3.2s。
histogram_quantile(
0.90,
sum without(instance)(rate(prometheus_tsdb_compaction_duration_seconds_bucket[1d]))
)
# {job="LocalServer"} 3.2

# (2) 计算事件平均大小例如压缩平均持续时间。
sum without(instance)(rate(prometheus_tsdb_compaction_duration_seconds_sum[1d]))
/
sum without(instance)(rate(prometheus_tsdb_compaction_duration_seconds_count[1d]))
# {job="LocalServer"} 2.317425352000015

Tips : 通常使用5~10 min的间隔来进行直方图 rate 函数计算,所有桶中的时间序列将根据任何标签进行结合,并且rate范围越长,就会有更多的数据样本需要处理,所以我们要警惕使用小时(hour)或者天数(Days)范围的PromQL表达式, 因此它们的计算成本相对较高。


10.API查询指标数据

描述: Prometheus 提供了许多HTTP API, 它们允许你输入PromQL语句,并返回数据使得可以用在仪表板工具或自定义报告脚本中。

Query

描述: 在给定的时间执行PromQL表达式并返回结果,注意其支持带入标签进行查询过滤的。

示例1:使用当前时间进行指标查询

1
2
3
4
5
6
7
8
9
10
curl http://10.0.0.107:30090/api/v1/query?query=go_info{job="Server"}

#// 返回结果:
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"go_info","instance":"localhost:9090","job":"Server","version":"go1.16.2"},"value":[1629539549.827,"1"]}]}}

#// 结果说明:
status 字段 : success (查询有效) | error (查询有误)。
resultType 字段 : 结果类型是一个是个瞬时向量。
metric 字段 : 存放该指标的相关关联标签。
value 字段 : 第一个值为样本时间戳,第二个为其值


示例2:指定时间进行查询指标
描述: 我们可以传入Unix格式的时间或者RFC 3339标准的时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
curl http://10.0.0.107:30090/api/v1/query?query=node_memory_Active_bytes{instance="10.0.0.107:9100"}&time=1629539549  # 2021-08-21 17:52:29

# 返回结果:
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"__name__": "node_memory_Active_bytes",
"env": "prod",
"instance": "10.0.0.107:9100",
"job": "linux_exporter",
"nodeType": "master"
},
"value": [
1629539549,
"5097132032"
]
}
]
}
}


示例3: 支持范围向量进行查询(但一般都采用query_range 而非 query)

1
2
3
4
curl http://10.0.0.107:30090/api/v1/query?query=prometheus_http_requests_total{handler="/metrics",instance="localhost:9090"}[5m]

# 返回结果:
{"status":"success","data":{"resultType":"matrix","result":[{"metric":{"__name__":"prometheus_http_requests_total","code":"200","handler":"/metrics","instance":"localhost:9090","job":"Server"},"values":[[1629540385.147,"8"],[1629540505.147,"9"]]}]}}


示例4.利用标量进行查询,其没有标签只是数字
描述: 与 {} 不同,后者是一个没标签的时间序列标识符。

1
2
3
4
curl http://10.0.0.107:30090/api/v1/query?query=1

# 执行结果
{"status":"success","data":{"resultType":"scalar","result":[1629540849.286,"1"]}}


Query_range

描述: 主要采用其api进行查询查询并返回范围向量的指标结果,其除了查询指标参数外,还有提供start、end、step参数。

Tips : 将来自不同执行的所有瞬时向量组合成范围向量并返回。

例如: 查询前15分钟内请求prometheus的/metric次数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# start [2021-08-21 18:00:00 ==> 1629540000]
# end [2021-08-21 18:15:00 ==> 1629540900]
# step 60

curl http://10.0.0.107:30090/api/v1/query?query=prometheus_http_requests_total{handler=%22/metrics%22,instance=%22localhost:9090%22}[5m]&start=1629540000&end=1629541800&step=60

# 返回结果
{
"status": "success",
"data": {
"resultType": "matrix",
"result": [
{
"metric": {
"__name__": "prometheus_http_requests_total",
"code": "200",
"handler": "/metrics",
"instance": "localhost:9090",
"job": "Server"
},
"values": [
[1629541465.147,"17"],
[1629541585.147,"18"]
]
}
]
}
}


0x01 表达式语言运算符

描述: Prometheus 支持许多二元和聚合运算符。


1.二元运算符

描述: Prometheus 的查询语言支持基本的逻辑和算术运算符。对于两个瞬时向量之间的操作,可以修改匹配行为。

  • 1.1 二元算术运算符
    描述: 二元算术运算符定义在标量/标量向量/标量向量/向量值对之间。
    1
    2
    3
    4
    5
    +,-,*,/,%(模数),^(幂/幂)

    # 简单示例:
    5 % 1.5 # ==> scalar 0.5
    5 ^ 2 # ==> scalar 25

Tips : 描述: 标量是没有维度的单个数字,是除了瞬时与范围向量之外,被称为标量类型的值。
例如, 0 是标量它的值为零。
例如, {} 0 是包含单个样本且没有标签且值为零的瞬时向量。


  • 1.2 比较二元运算符
    描述:在PromQL中比较运算符是过滤的
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 比较判断
    ==,!=,>,<,>=,<=,

    # 正则匹配 以及 正则不匹配 的情况下
    =~ , !~

    # 简单示例:
    # 1.打开的文件描述符数量大于10的时间序列
    process_open_fds > 10
    10 < process_open_fds # 当比较标量和瞬时向量时,哪个在那一侧并不重要。
    # process_open_fds{instance="localhost:9090", job="Server"} 49
    # process_open_fds{app_kubernetes_io_name="kube-state-metrics", app_kubernetes_io_version="2.0.0", instance="172.16.182.233:8081", job="k8s-endpoint-discover", kubernetes_namespace="monitor", service_name="kube-state-metrics"} 11

    # 1.打开的文件描述符数量大于10且小于48的时间序列
    10 < process_open_fds < 48
    process_open_fds < 48 > 10


  • 1.3 Bool 修饰符
    描述: 过滤主要用于告警规则,而bool是进行比较的一些方法而不是过滤。

示例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1.该修饰符是比较标量的唯一方法
# 1024 >= 42 会报如下: Error executing query: invalid parameter "query": 1:6: parse error: comparisons between scalars must use BOOL modifier 错误
1024 >= bool 42 # scalar 1

# 2.获得打开十个以上文件描述符的每个任务的进程数
sort_desc(sum without(instance)(process_open_fds >= bool 10))
# {job="Server"} 1 # 该 job 主机满足
# {job="linux_exporter"} 0 # 该 job 主机无满足

# 3.查找具有四个以上的磁盘设备计算机的比例
avg without(instance)(count without(device)(node_disk_io_now) > bool 4)
# {job="linux_exporter"} 0
# {job="linux_exporter", nodeType="work"} 0.6666666666666667


  • 1.4 逻辑二元运算符
    描述: 逻辑/集合二元运算符仅在即时向量之间定义
    1
    2
    3
    4
    5
    6
    7
    and , or, unless 

    - or 操作符:每组左侧的组如都有样本则返回他们,否则返回右侧组中的样本。
    - unless 操作符:根据右和左操作数中是否为空进行判断,除非右侧有成员,否则unless运算符返回左侧组。
    - and 操作符: 与unless相反,仅当匹配的右侧有样本时,它才从左侧操作符返回一个组,否则他不返回该匹配的样本。你可将其视为if运算符。
    # 说明:
    vector1 unless vector2 : 产生一个向量,该向量 vector1 不匹配 vector2 完全匹配标签集的元素组成。

示例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# or 操作符示例
# 1.每组左侧的组都有样本然后返回他们,否则返回右侧组中的样本。
node_hwmon_temp_celsius or ignoring(label) (node_hwmon_sensor_label * 0 + 1)
# node_hwmon_temp_celsius{chip="platform_coretemp_0", instance="10.0.0.223:9100", job="linux_exporter", sensor="temp10"} 30
node_hwmon_temp_celsius * ignoring(label) group_left(label) (node_hwmon_sensor_celsius or ignoring(lable)(node_hwmon_temp_celsius * 0 + 1))
# {chip="platform_coretemp_0", instance="10.0.0.223:9100", job="linux_exporter",sensor="temp10"} 28

# 2.将两者的指标都输出,但针对于up指标的值全部设置为0
node_uname_info or up{job="Server"} * 0
# node_uname_info{ instance="10.0.0.225:9100", job="linux_exporter", machine="x86_64", nodename="weiyigeek-255", release="5.4.0-42-generic", sysname="Linux", version="#46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020"} 1
# {instance="localhost:9090", job="Server"}


# unless 操作符示例
# 1.除了使用少于100MB驻留内存进程外的其他进程平均CPU使用率,可以使用以下表达式。
rate(process_cpu_seconds_total[5m]) unless process_resident_memory_bytes < 1024^2 * 100
# {instance="localhost:9090", job="Server"} 0.0016149975000000613
# 2.用于发现目标中缺少的指标。
up{instance="localhost:9090"} == 1 unless node_custom

# 3.及时组的右操作数有多个样本,unless也可以在多对多匹配中使用。
up == 1 unless on (job,instance) node_custom
# up{instance="localhost:9090", job="Server"}


# and 操作符示例
# 1.希望在延迟时间很长并且用户请求较多时返回。处理程序超过一秒,并且每秒只有一个请求。
(rate(prometheus_http_request_duration_seconds_sum[5m])
/
rate(prometheus_http_request_duration_seconds_count[5m]))
> 10^6
and rate(prometheus_http_request_duration_seconds_count[5m]) > 1
and on() hour() > 9 < 17

Tips : x * 0 + 1会将瞬时向量的所有值都更改为1。


2.修饰运算符

描述: 向量之间的操作尝试为左侧的每个条目在右侧向量中找到匹配元素。

Tips : 向量匹配是将两个瞬时向量之间使用运算符进行过滤或者查询。

Tips : 向量匹配行为有两种基本类型一对一多对一/一对多

  • 2.1 一对一向量匹配
    描述: 一对一从操作的每一侧找到一对唯一的条目。如果两个条目具有完全相同的一组标签和相应的值,则它们匹配.
    1
    2
    3
    4
    5
    6
    // 语法
    <vector expr> <bin-op> ignoring(<label list>) <vector expr>
    <vector expr> <bin-op> on(<label list>) <vector expr>

    // 语法示例:返回一个结果向量,其中包含在过去 5 分钟内测量的每种方法的状态代码为 500 的 HTTP 请求的比例
    method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m

具体示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 1.查询目标机器已使用的进程打开的文件标识符占比(在两个时间序列标签匹配时)
process_open_fds{instance="localhost:9090"} / process_max_fds{instance="localhost:9090"}
// {instance="localhost:9090", job="Server"} 0.00004863739013671875

// 2.匹配两个标签不完美匹配的瞬时变量。
// 每个实例CPU在idle模式下所占用的时间比例,使用ignoring(mode)时,将向量在分组时node标签将被丢弃,并匹配成功。
sum without(cpu) (rate(node_cpu_seconds_total{mode="idle"}[5m])) /ignoring(mode) sum without(mode,cpu) (rate(node_cpu_seconds_total[5m]))
// {instance="10.0.0.107:9100", job="linux_exporter"} 0.9783266498445258
// {instance="10.0.0.108:9100", job="linux_exporter"} 0.9760616305723038
// {instance="10.0.0.109:9100", job="linux_exporter"} 0.9807213018617855

// 3.指定保留标签的时间序列进行操作(示例中这样使用比较多余)
sum by(cpu) (rate(node_cpu_seconds_total{mode="idle"}[5m])) / on(mode) sum by(mode,cpu) (rate(node_cpu_seconds_total[5m]))

Tips : 当具有完全相同标签的样本将被匹配(组合)在一起。
Tips : 如果期望结果时返回为空的瞬时向量,则可能因为操作数的样本标签不匹配。


  • 2.2 多对一和一对多向量匹配
    描述: 多对一和一对多匹配是指“一”端的每个向量元素可以与“多”端的多个元素匹配的情况。必须使用group_left or group_right修饰符明确请求,其中左/右确定哪个向量具有更高的基数。
    1
    2
    3
    4
    5
    6
    7
    8
    // 语法格式
    <vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>
    <vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>
    <vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
    <vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>

    // 示例查询:分组修饰符只能用于 比较和 算术。默认情况下and,操作 asunless和 or操作与正确向量中的所有可能条目匹配。
    method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m

实际案例:

1
2
3
4
5
6
7
// # 1.允许你指定左侧操作数组中可以有多个匹配样本。(多对n-1)
sum without(cpu)(rate(node_cpu_seconds_total[5m])) / ignoring(mode) group_left sum without(mode,cpu)(rate(node_cpu_seconds_total[5m]))
// {instance="10.0.0.225:9100", job="linux_exporter", mode="user"} 0.015867011327565222
// { instance="10.0.0.225:9100", job="linux_exporter", mode="system"} 0.0027793624511104906

// # 2.允许你指定右侧操作数组中可以有多个匹配样本。(多对n-1)
sum without(mode,cpu)(rate(node_cpu_seconds_total[5m])) / ignoring(mode) group_right sum without(cpu)(rate(node_cpu_seconds_total[5m]))

Tips : 多对一和一对多匹配是应该仔细考虑的高级用例。通常正确可使用ignoring(<labels>)提供所需的结果。


ignoring 修饰符

描述: 在匹配时忽略某些标签(类似于聚合操作中的without方式

on 修饰符

描述: 在匹配时允许减少该组被认为标签来提供的列表(类似于聚合操作中的by方式)

group_left 修饰符

描述: 该修饰符有两个功能,一是指定左侧操作数组中可以有多个匹配样本(始终从左侧操作数的样本中获取所有标签)确保保留左侧需要进行多对一向量匹配的额外标签,二是将信息指标中的标签添加到一个目标的其它指标中。

简单示例:

1
2
3
4
5
6
7
8
9
# (1) 说明: 将Python_info中的version标签添加到up表达式匹配到所有的指标内。
# 即我们可以通过乘法运算符或者group_left修饰符连接到其它任何指标。
up * on (instance,job) group_left (version) python_info
# 输出结果
{instance="10.20.172.103:8000", job="control", version="3.7.3"}

# (2) 目标设备的温度传感器
node_hwmon_temp_celsius * ignoring(label) group_left(label) node_hwmon_sensor_label
# {env="prod", instance="10.0.0.224:9100", job="linux_exporter", label="package_id_0", sensor="temp1"} 33

Tips: 可使用任何运算符来连接指标,当信息指标的值为1时时候,乘法不会更改其他指标的值。

group_right 修饰符

描述: 其工作方式与group_left相同,只是将操作对象从左换到右,但是通常使用group_left因为任何标签都是从左向右复制的,为了保证一致性以及方便人员理解所以推荐。

简单示例:

1
2
3
// 1.将左侧prometheus_build_info指标中的version,revision标签复制到右侧up指标中进行展示。
prometheus_build_info * on (instance) group_right(version,revision) up
// {instance="localhost:9090", job="Server", revision="3cafc58827d1ebd1a67749f88be4218f0bab3d8d", version="2.26.0"} 1


3.聚合运算符

描述: Prometheus 支持以下内置聚合运算符,可用于聚合单个即时向量的元素,从而生成具有聚合值的更少元素的新向量。

分组

描述: 在学习聚合运算符之前,需要了解实践序列的分组方式。

(1) Without 指定要删除的标签

1
2
3
4
5
6
7
8
9
# 1.将指标的device,mountpoint标签取消,并进行其它不同标签分组并求值只和
sum without(device,mountpoint)(node_filesystem_size_bytes{instance="10.0.0.107:9100"})
# {fstype="ext4", instance="10.0.0.107:9100", job="linux_exporter"} 105114386432
# {fstype="nfs", instance="10.0.0.107:9100", job="linux_exporter"} 2998958817280
# {fstype="tmpfs", instance="10.0.0.107:9100", job="linux_exporter"} 52056260608


# 2.当不为 without 提供标签时,输出效果与 node_filesystem_size_bytes 一致
sum without()(node_filesystem_size_bytes{instance="10.0.0.107:9100"})


(2) By 指定要保留的标签

Tips : 何时用Without ,何时用By?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 下述两种情况使用By可能更有用。
# 1.与without不同的是它不会自动删除`__name__`标签
sort_desc(count by(__name__)({__name__=~"node_filesystem.+"}))
# node_filesystem_files{} 116
# node_filesystem_files_free{} 116
# node_filesystem_free_bytes{} 116
# node_filesystem_readonly{} 116
# node_filesystem_size_bytes{} 116
# node_filesystem_avail_bytes{} 116
# node_filesystem_device_error{} 116

# 2.删除任何你不知道的标签。
count by(release)(node_uname_info)
# {release="5.4.0-70-generic"} 1
# {release="5.4.0-60-generic"} 2
# {release="5.4.0-42-generic"} 3

# 3.可以使用sum和一个空的by,甚至可以忽略by,例如
sum by()(node_uname_info) # ==>> sum(node_uname_info)
# {} 6 # 单一时间序列,该时间序列没有标签。


聚合

描述: 聚合运算符寄仅适用于瞬时向量,也输出瞬时向量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 聚合运算符列表
sum (计算维度的总和)
min (选择最小尺寸)
max (选择最大尺寸)
avg (计算维度上的平均值)
group (结果向量中的所有值都是 1)
stddev (计算维度上的总体标准偏差)
stdvar (计算维度上的总体标准方差)
count (计算向量中元素的数量)
count_values (计算具有相同值的元素数)
bottomk (样本值的最小 k 个元素)
topk (样本值最大的 k 个元素)
quantile (在维度上计算 φ-分位数 (0 ≤ φ ≤ 1))

# 语法格式:
<aggr-op> [without|by (<label list>)] ([parameter,] <vector expression>)
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]

# 参数说明:
- <label list> : 是加引号的标签,可以包括后面的逗号.
- without : 从结果向量中删除列出的标签,而所有其他标签都保留在输出中.
- by : 执行相反的操作并删除by子句中未列出的标签,即使它们的标签值在向量的所有元素之间都相同。
- parameter : 取值 count_values,quantile,topk和 bottomk。

实例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1.通过以下方式计算每个应用程序和组在所有实例上看到的 HTTP 请求总数
sum without (instance) (prometheus_prometheus_http_requests_total)
// {code="200", handler="/alerts", job="LocalServer"} 10
sum by (code, handler) (prometheus_prometheus_http_requests_total)
// {code="200", handler="/metrics"} 83458

// 2.计算运行每个构建版本的二进制文件的数量,
count_values("version", go_info) //{version="1"} 62

// 3.要在所有实例中获得 5 个最大的 HTTP 请求数,
topk(5, prometheus_prometheus_http_requests_total)
// {code="200", handler="/metrics", instance="localhost:9090", job="LocalServer"} 83467
// {code="200", handler="/api/v1/query_range", instance="localhost:9090", job="LocalServer"} 6283
// {code="200", handler="/api/v1/query", instance="localhost:9090", job="LocalServer"} 5095
// {code="200", handler="/api/v1/series", instance="localhost:9090", job="LocalServer"} 460
// {code="200", handler="/api/v1/label/:name/values", instance="localhost:9090", job="LocalServer"} 186

Tips :运算符既可用于聚合所有标签维度,也可通过包含withoutorby子句来保留不同的维度


4.运算符优先级

描述:下面的列表显示了 Prometheus 中二元运算符的优先级,从高到低。

1
2
3
4
5
6
^
*, /,%
+, -
==, !=, <=, <, >=,>
and, unless
or

Tips :相同优先级的运算符是左结合的。例如2 * 3 % 2相当于(2 * 3) % 2, 然而^是右结合的,所以 2 ^ 3 ^ 2等价于2 ^ (3 ^ 2)


0x02 PromQL 内置函数介绍

Prometheus 提供了其它大量的内置函数,可以对时序数据进行丰富的处理。某些函数有默认的参数,例如:year(v=vector(time()) instant-vector)。其中参数 v 是一个瞬时向量,如果不提供该参数,将使用默认值 vector(time()), instant-vector 表示参数类型 {} : 1626661808.684

官方参考: https://prometheus.io/docs/prometheus/latest/querying/functions/


1.聚合函数

sum 函数

描述: 我们可以根据path标签进行聚合操作,sum函数可以对样本进行做求和操作。

分组:

  • without 字句: 表示要移除的标签。
  • by 字句: 表示只显示的标签。

  • 1) PromQL: sum by(path)(rate(http_requested_total[2m])), 说明: 聚合求和操作只显示指定标签的键、值

    1
    2
    3
    {path="/"} 0
    {path="/api/"} 0.03333333333333333
    {path="/favicon.ico"} 0.04444444444444444
  • 2) PromQL: sum without(path)(rate(http_requested_total[2m])), 说明: 聚合求和操作除了指定标签的包括其它标签的键、值。

    1
    {instance="10.20.172.103:8000", job="control", method="GET"} 0.040740740740740744


avg() 函数

描述: 将返回组中时间序列所以值的平均数来作为组的值。

示例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// (1) 返回每个节点实例每种CPU模式的平均使用情况
avg without(cpu)(node_cpu_seconds_total{instance="10.0.0.107:9100"})
// 与下面效果一致
// sum without(cpu)(node_cpu_seconds_total{instance="10.0.0.107:9100"})
// /
// count without(cpu)(node_cpu_seconds_total{instance="10.0.0.107:9100"})
// 输出结果:
{ instance="10.0.0.107:9100", job="linux_exporter", mode="steal"} 0
{ instance="10.0.0.107:9100", job="linux_exporter", mode="system"} 80513.27249999999
{ instance="10.0.0.107:9100", job="linux_exporter", mode="user"} 162807.48375
{ instance="10.0.0.107:9100", job="linux_exporter", mode="idle"} 12163467.506250001
{ instance="10.0.0.107:9100", job="linux_exporter", mode="iowait"} 8603.5525
{ instance="10.0.0.107:9100", job="linux_exporter", mode="irq"} 0
{ instance="10.0.0.107:9100", job="linux_exporter", mode="nice"} 212.6525
{ instance="10.0.0.107:9100", job="linux_exporter", mode="softirq"} 4911.07375

TIPS : 有时你会发现输入中存在NaN时都会导致整个结果变为NaN(任何涉及NaN的浮点数运算都会产生NaN),并且 1 / 0 时也会输出NaN。


count() 函数

描述: count 集合将计算并返回分组中的时间序列数。

示例演示:

1
2
3
4
5
6
7
8
9
10
11
// 1.返回机器包含的磁盘设备数量
count without(device)(node_disk_read_bytes_total{device=~"sd.+",instance="10.0.0.107:9100"})
// {instance="10.0.0.107:9100", job="linux_exporter"} 1

// 2.计数标签有多少个不同的值例如返回该目标的实例的CPU数量
count without(cpu)(count without(mode)(node_cpu_seconds_total{instance="10.0.0.107:9100"}))
// {instance="10.0.0.107:9100", job="linux_exporter"} 8 // 8 核

// 3.生成没有标签的单个样本。
count(count without(cpu)(node_cpu_seconds_total{instance="10.0.0.107:9100"}))
// {} 8


count_values() 函数

描述: 该函数可以从一个组中返回多个时间序列。并按照组中的时间序列值建立频率直方图,每个值的计数作为输出时间序列的值,原始值作为新标签。

示例演示:

1
2
3
4
5
6
7
8
9
10
11
# 1.查询目标系统中有几个的内核版本数
count_values("kernelVersion",count without(instance,version,nodename,nodeType)(node_uname_info))
# {kernelVersion="1"} 1
# {kernelVersion="2"} 1
# {kernelVersion="3"} 1

# 2.查询机器数和磁盘设备数
count_values without(instance)("devices",count without(device)(node_disk_io_now))
count_values without(instance)("devices",count without(device)(node_disk_io_now{device=~"sd.+"}))
# 表示有三台机器只有一块物理硬盘
# {devices="1", env="prod", job="linux_exporter"} 3

Tips: count_values 可与count 结合使用,来计算给定的聚合组的唯一值的数量。


min() 函数

max() 函数

描述: 两个聚合函数分别求取组内最小或最大值作为组的返回值。

示例演示:

1
2
3
4
5
min without(device,fstype,mountpoint)(node_filesystem_size_bytes)
// {instance="10.0.0.224:9100", job="linux_exporter"} 5242880

max without(device,fstype,mountpoint)(node_filesystem_size_bytes)
// {instance="10.0.0.223:9100", job="linux_exporter"} 2998958817280

Tips : 如果组中的值存在是NaN,则结果也仅仅返回NaN


stddev() 函数

stdvar() 函数

描述: 标准差是对一组数字的离散程度进行统计测量。在监控中标准差的主要用于检测异常值。
例如, 你有数字{2,4,6}和{3,4,5}其平均值都是4,前者的标准差为 1.633,后者标准差为0.816

例如,两组数的集合{0,5,9,14}和{5,6,8,9}其平均值都是7,但第二个集合具有较小的标准差。

1
2
3
4
5
6
7
平均数: 0 + 5 + 9 + 14 / 4 = 7
# 此处样本数量较少所以直接采用 n (样本个数)
方差: ((0-7)^2 + (5-7)^2 + (9-7)^2 + (14-7)^2) / 4 = (49 + 4 + 4 + 49) / 4 = 106 / 4 = 26.5
标准差: sqrt(方差) = sqrt(26.5) = 5.1478150704935
# go 语言中
# fmt.Println(float64(106) / float64(4))
# fmt.Println(math.Sqrt(float64(106) / float64(4)))

示例演示:

1
2
3
4
5
6
7
# 例如,可以使用以下表达式找到比平均值至少高出2两个标准差的实例
some_gauge_metrics > ingnoring (instance)(some_gauge_metrics)
(
avg without (instance) (some_gauge_metrics)
+
2 * stddev without (instance) (some_gauge_metrics)
)

Tips: 标准方差是标准差的平方。
Tips: 因为有两个定义,用在不同的场合如是总体,标准差公式根号内除以n,如是样本,标准差公式根号内除以(n-1),因为我们大量接触的是样本,所以普遍使用根号内除以(n-1),


topk() 函数

bottomk() 函数

描述: 该函数与其它聚合函数三个不同的地方,第一,它们返回的是时间序列的标签而非分组标签,第二,每组可以返回多个时间序列,第三,它们采用额外的参数。

  • topk() 函数: 返回分组中最大的k个时间序列。
  • tottomk() 函数: 返回分组中最小的k个时间序列。

示例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// (1) 返回值最大的2个时间序列,并且每组最多返回两个时间序列。
topk without(device,fstype,mountpoint)(2,node_filesystem_size_bytes{instance="10.0.0.107:9100"})
// node_filesystem_size_bytes{ device="192.168.1.3:/nask8sapp", fstype="nfs", instance="10.0.0.107:9100", job="linux_exporter", mountpoint="/nfsdisk-31"} 2998958817280
// node_filesystem_size_bytes{ device="/dev/mapper/ubuntu--vg-lv--0", fstype="ext4", instance="10.0.0.107:9100", job="linux_exporter", mountpoint="/"} 104091082752


// (2) 返回值最小的2个时间序列,并且每组最多返回两个时间序列。
bottomk without(device,fstype,mountpoint)(2,node_filesystem_size_bytes{instance="10.0.0.107:9100"}) / 1024^3 // 使用运算符时会删除__name__标签。
// {device="tmpfs", fstype="tmpfs", instance="10.0.0.107:9100", job="linux_exporter", mountpoint="/run/lock"} 0.0048828125
// {device="/dev/sda2", fstype="ext4", instance="10.0.0.107:9100", job="linux_exporter", mountpoint="/boot"} 0.9530258178710938

// (3) 计算过去一个小时内的最大时间序列返回前5
topk(5,avg_over_time(prometheus_http_requests_total[1h]))
// {code="200", handler="/metrics", instance="localhost:9090", job="Server"} 518.5
// {code="200", handler="/api/v1/query", instance="localhost:9090", job="Server"} 69.30000000000001
// {code="200", handler="/static/*filepath", instance="localhost:9090", job="Server"} 6
// {code="400", handler="/api/v1/query", instance="localhost:9090", job="Server"} 3.933333333333333
// {code="200", handler="/api/v1/label/:name/values", instance="localhost:9090", job="Server"} 3

Tips: 该topk聚合函数不会删除__name__标签,但是如果针对其数据进行运算时或者包含其它函数时会删除__name__标签(看上述两个示例),它们会在结果中展示。


quantile() 函数

描述: 该聚合函数指定分位数的值作为组的返回值,适用于对瞬时向量做跨聚合组查询,并且与topk类似分位数使用一个参数。

  • 例如1, 查询不同目标机器中CPU系统模式使用率的第90百分位是多少。

    1
    2
    3
    4
    // 意味着在90%的CPU每秒至少有0.007秒处于系统模式。
    quantile without(cpu) (0.9,rate(node_cpu_seconds_total{mode="system"}[5m]))
    // {instance="10.0.0.224:9100", job="linux_exporter", mode="system"} 0.007323449333398858
    // {instance="10.0.0.225:9100", job="linux_exporter", mode="system"} 0.0032833333333352737
  • 例如2,使用分位数来显示图表中的中位数,第25百分位数和第75百分位数。

    1
    2
    3
    4
    5
    quantile without(instance) (0.75,rate(process_cpu_seconds_total[5m]))
    // {job="Server"} 0.0024166666666666004

    quantile without(instance) (0.25,rate(process_cpu_seconds_total[5m]))
    // {job="Server"} 0.0024166666666666004


2.类型函数

vector() 函数

描述: vector(s scalar) 函数将标量 s 作为没有标签的向量返回,即返回结果为:key: value= {}, s, 将其转换为一个无标签的瞬时向量的样本并给予定值。

例如,vector(1024) 返回 {} 1024
例如, sum(node_not_metrics) or vector(1024) 返回 {} 1024, 不存在的指标也始终返回一个样本。


scalar() 函数

描述: scalar(v instant-vector) 函数的参数是一个单元素的瞬时向量, 它返回其唯一的时间序列的值作为一个标量。

Tips:如果度量指标的样本数量大于 1 或者等于 0, 则返回 NaN,它在处理标量常量时非常有用。

示例演示:

1
2
3
4
5
6
7
8
# 1.处理标量常量且仅仅适用于瞬时向量的数学函数
scalar(sqrt(vector(4))) # >> scalar 2

# 2.与时间函数连用
scalar(year()) # >> scalar 2021

# 3.为你提供计算机CPU非空闲的时间比例(使用scalar会丢失所有的标签)
sum(rate(node_cpu_seconds_total{mode!="idle"}[5m])) / scalar(count(node_cpu_seconds_total{mode="idle"})) # {} 0.017490234375018142


3.数学函数

描述: 数学函数对瞬时向量执行标准数学计算。并且瞬时向量中的每个样本都独立处理,返回值将删除指标名称。

abs() 函数

描述: abs(v instant-vector) 返回输入向量的所有样本的绝对值。

1
abs(vector(time()))  # {} 1626662058.627


ln() 函数

描述: ln(v instant-vector) 计算瞬时向量 v 中所有样本数据的自然对数。特殊情况:

1
2
3
4
ln(+Inf) = +Inf
ln(0) = -Inf
ln(x < 0) = NaN
ln(NaN) = NaN


log2() 函数

描述: log2(v instant-vector) 函数计算瞬时向量 v 中所有样本数据的二进制对数。特殊情况同上。

1
log2(vector(2)) # {}	1


log10() 函数

描述: log10(v instant-vector) 计算瞬时向量 v 中所有样本数据的十进制对数。特殊情况同上。

1
log2(vector(10)) # {}	1


exp() 函数

描述: exp(v instant-vector) 函数,输入一个瞬时向量,返回各个样本值的 e 的指数值,即 e 的 N 次方。当 N 的值足够大时会返回 +Inf。

Tips : exp 函数提供自然对数,与ln函数相反。

特殊情况为:

1
2
3
Exp(+Inf) = +Inf
Exp(NaN) = NaN
exp(vector(1)) # {} 2.718281828459045 欧拉数字e


sqrt() 函数

描述: sqrt(v instant-vector) 函数计算向量 v 中所有元素的平方根。

1
2
3
4
5
6
7
sqrt(vector(9)) # {} 3

# sqrt 早于指数运算符^,例如
vector(9) ^ 0.5 # {} 3

# 同样如果你需要其它方根,例如
vector(9) ^ (1/3) # {} 2.080083823051904


ceil() 函数

描述: ceil (v instant-vector)将 v 中所有元素的样本值向上四舍五入到最接近的整数。例如:

1
2
node_load5{instance="192.168.1.75:9100"}       # 结果为 2.79
ceil(node_load5{instance="192.168.1.75:9100"}) # 结果为 3


floor() 函数

描述: floor(v instant-vector) 函数与 ceil() 函数相反,将 v 中所有元素的样本值向下四舍五入到最接近的整数。


round() 函数

描述: round(v instant-vector, to_nearest=1 scalar) 函数与 ceil 和 floor 函数类似,返回向量中所有样本值的最接近的整数。to_nearest 参数是可选的, 默认为 1 表示样本返回的是最接近 1 的整数倍的值。你也可以将该参数指定为任意值(也可以是小数),表示样本返回的是最接近它的整数倍的值。

实例演示:

1
2
3
4
5
6
ceil(vector(6.5))  # 7

floor(vector(6.5)) # 6

round(vector(6.5)) # 7
round(vector(6.4)) # 6


clamp() 函数

描述: clamp(v instant-vector, min scalar, max scalar) 将所有元素的样本值钳制在v下限为min和上限为max

特殊情况: - 返回空向量 if min > max - 返回NaNifminmaxisNaN


clamp_max() 函数

描述: clamp_max(v instant-vector, max scalar)函数,输入一个瞬时向量和最大值,样本数据值若大于 max,则改为 max,否则不变。例如:

1
2
node_load5{instance="192.168.1.75:9100"}               # 结果为 2.79
clamp_max(node_load5{instance="192.168.1.75:9100"}, 2) # 结果为 2


clamp_min() 函数

描述: clamp_min(v instant-vector, min scalar) 函数,输入一个瞬时向量和最小值,样本数据值若小于 min,则改为 min 否则不变。

例如:

1
2
3
4
5
6
7
node_load5{instance="192.168.1.75:9100"} # 结果为 2.79
clamp_min(node_load5{instance="192.168.1.75:9100"}, 3) # 结果为 3

# 那些目标进程使用最少是10个打开文件描述符(min < 值 < max)
clamp_min(process_open_fds,10)
# {instance="192.168.1.225:9100", job="linux_exporter"} 9
# {instance="localhost:9090", job="Server"} 10


4.时间函数

描述: Prometheus提供几个处理时间的函数,注意其完全使用UTC并没有时区的概念。

time() 函数

描述: time() 函数返回从 1970-01-01 到现在的秒数。注意:它不是直接返回当前时间而是时间戳.

1
2
3
4
5
# 返回当前时间UTC格式
time() # scalar 1626675614.185

# 节点开机时间
time() - process_start_time_seconds # {instance="localhost:9090", job="Server"} 243129.00699996948


minute() 函数

描述: minute(v=vector(time()) instant-vector) 函数返回给定 UTC 时间当前小时的第多少分钟。结果范围:0~59。

1
minute(vector(time()))  #  50 分钟


hour() 函数

hour(v=vector(time()) instant-vector)以 UTC 格式返回每个给定时间的一天中的小时。返回值从 0 到 23。


month() 函数

描述: month(v=vector(time()) instant-vector) 函数返回给定 UTC 时间当前属于第几个月,结果范围:0~12。

1
month(vector(time()))   # 7 分钟


year() 函数

描述: year(v=vector(time()) instant-vector) 函数返回被给定 UTC 时间的当前年份。

注意: 即使区间向量内的值分布不均匀,它们在聚合时的权重也是相同的。

实例演示:

1
2
3
4
5
6
7
8
9
10
# 1.查看进程是哪一年开始运行
year(process_start_time_seconds) # {instance="localhost:9090", job="Server"} 2021

# 2.计算本月启动的进程的时间序列
year(process_start_time_seconds) == bool scalar(year()) * (month(process_start_time_seconds) == bool scalar(month()))
# {instance="localhost:9090", job="Server"} 1
# {instance="192.168.1.225:9100", job="linux_exporter"} 0

# 2.计算本月启动的进程的时间序列个数
sum(year(process_start_time_seconds) == bool scalar(year()) * (month(process_start_time_seconds) == bool scalar(month()))) # {} 1

Tips : 乘法运算符在布尔值使用时就像运算符一样值1表示真,否则为假。


day_of_month() 函数

描述: day_of_month(v=vector(time()) instant-vector) 函数,返回被给定 UTC 时间所在月的第几天。返回值范围:1~31。

1
day_of_month(vector(time())) # 19 号


day_of_week() 函数

描述: day_of_week(v=vector(time()) instant-vector) 函数,返回被给定 UTC 时间所在周的第几天。返回值范围:0~6,0 表示星期天。

1
day_of_week(vector(time())) # 1 星期天


days_in_month() 函数

描述: days_in_month(v=vector(time()) instant-vector) 函数,返回当月一共有多少天。返回值范围:28~31。

1
days_in_month(vector(time())) # 31 当月31天


timestamp() 函数

描述:timestamp(v instant-vector) 函数返回向量 v 中的每个样本的时间戳(从 1970-01-01 到现在的秒数)。

该函数从 Prometheus 2.0 版本开始引入, 与其它时间函数不同的是,它查看瞬时向量中的样本的时间戳而不是值。

1
2
3
4
5
6
7
8
# 实例1.
timestamp(vector(time())) # {} 1629783662.714

# 实例2.可以看到每个目标的最后异常抓取的开始时间。
timestamp(up) # {instance="localhost:9090", job="Server"} 1629783745.147

# 实例3.返回Prometheus启动节点导出器抓取时间与节点导出器认为的当前实践的差值。
node_time_seconds - timestamp(node_time_seconds) # {instance="192.168.1.107:9100", job="linux_exporter"} 0.0025420188903808594


5.标签函数

label_join() 函数

描述: 该函数允许你将标签纸连接在用,类似于在重新标记时处理souce_lables方法,同样该函数也不会删除指标名称。

语法格式: label_join(v instant-vector, dst_label string, separator string, src_label_1 string, src_label_2 string, ...)

Tips: 该函数可以将时间序列 v 中多个标签 src_label 的值,通过 separator 作为连接符写入到一个新的标签 dst_label 中,注意可以有多个 src_label 标签。

例如,以下表达式返回的时间序列多了一个 foo 标签,标签值为 etcd,etcd-k8s

1
2
3
4
up{instance="192.168.1.8:2379",job="etcd",service="etcd-k8s"} => 
# up{endpoint="api",instance="192.168.1.8:2379",job="etcd",service="etcd-k8s"} 1
label_join(up{instance="192.168.1.8:2379",job="etcd",service="etcd-k8s"}, "foo", ",", "job", "service") =>
# up{endpoint="api",foo="etcd,etcd-k8s",instance="192.168.13.248:2379",job="etcd",namespace="monitoring",service="etcd-k8s"} 1

例如, 一个简单例子

1
2
3
4
5
go_info{job="LocalServer"}  
# ==> go_info{instance="localhost:9090", job="LocalServer", version="go1.16.4"} 1

label_join(go_info{job="LocalServer"},"newlable",'|',"job","version")
# ==> go_info{instance="localhost:9090", job="LocalServer", newlable="LocalServer|go1.16.4", version="go1.16.4"} 1


label_replace() 函数

描述: 该函数允许你对标签值进行正则表达式替换。与大多数函数不同的是,该函数不会删除指标名称。

Tips: 为了能够让客户端的图标更具有可读性,可以通过 label_replace 函数为时间序列添加额外的标签。

label_replace 的具体格式参数:label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string)

例如: 该函数会依次对 v 中的每一条时间序列进行处理,通过 regex 匹配 src_label 的值,并将匹配部分 relacement 写入到 dst_label 标签中。如下所示:

1
2
label_replace(up, "host", "$1", "instance",  "(.*):.*")
label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")

函数处理后,时间序列将包含一个 host 标签,host 标签的值为 Exporter 实例的 IP 地址:

1
2
3
up{host="localhost",instance="localhost:8080",job="cadvisor"}   1
up{host="localhost",instance="localhost:9090",job="prometheus"} 1
up{host="localhost",instance="localhost:9100",job="node"} 1

例如: 更简单的例子

1
2
3
4
5
up{job="LocalServer"} 
# ==> up{instance="localhost:9090", job="LocalServer"}

label_replace(up{job="LocalServer"}, "instance", "$1:9200", "job", "(.*)")
# ==> up{instance="LocalServer:9200", job="LocalServer"}


6.缺失与排序函数

absent() 函数

描述: absent(v instant-vector) 该函数在多对多逻辑运算符中所述,该函数扮演not运算符的角色。

即如果传递给它的向量参数具有样本数据,则返回空向量;如果传递的向量参数没有样本数据,则返回不带度量指标名称且带有标签的时间序列且样本值为1。

Tips: 当监控度量指标时, 如果获取到的样本数据是空的, 使用 absent 方法对告警是非常有用的。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 0.如果参数是瞬时向量选择器,它使用来自任何相等匹配器的标签。
absent(up) # 空的瞬时矢量
absent(up_not_existent) # {} 1
absent(up_not_existent) # {} 1

# 1.提供的向量样本数据演示
go_gc_duration_seconds_sum{job="LocalServer"} ==>> 4.2270563150000005
absent(go_gc_duration_seconds_sum{job="LocalServer"}) ==>> Empty query result

# 2.提供的向量无样本数据演示
prometheus_http_requests_total{method="get"} # Empty query result
absent(prometheus_http_requests_total{method="get"}) => 1 # 返回不带度量指标名称

# 3.由于不存在度量指标 nonexistent,所以返回不带度量指标名称且带有标签的时间序列,且样本值为1
absent(nonexistent{job="myjob"}) => {job="myjob"} => 1
# 正则匹配的 instance 不作为返回 labels 中的一部分
absent(nonexistent{job="myjob",instance=~".*"}) => {job="myjob"} => 1

# 4.sum函数返回的时间序列不带有标签且没有样本数据
absent(sum(nonexistent{job="myjob"})) => {} => 1

Tips: 对于检测整个任务是从服务发现丢失中是有效的。


histogram_quantile() 函数

描述: histogram_quantile(φ float, b instant-vector) 从 bucket 类型的向量 b 中计算 φ (0 ≤ φ ≤ 1) 分位数(百分位数的一般形式)的样本的最大值。该函数适用于在瞬时向量中针对单个histogram类型子项的不同桶进行查询。

Tips :(有关 φ 分位数的详细说明以及直方图指标类型的使用,请参阅直方图和摘要)。向量 b 中的样本是每个 bucket 的采样点数量。每个样本的 labels 中必须要有 le 这个 label 来表示每个 bucket 的上边界,没有 le 标签的样本会被忽略。直方图指标类型自动提供带有 _bucket 后缀和相应标签的时间序列。

  • 例如,一个直方图指标名称为 employee_age_bucket_bucket,要计算过去 10 分钟内 第 90 个百分位数,请使用以下表达式:
    1
    2
    3
    histogram_quantile(0.9, rate(employee_age_bucket_bucket[10m]))
    # 返回:
    # {instance="10.0.86.71:8080",job="prometheus"} 35.714285714285715
    这表示最近 10 分钟之内 90% 的样本的最大值为 35.714285714285715。

Tips : 这个计算结果是每组标签组合成一个时间序列。我们可能不会对所有这些维度(如 job、instance 和 method)感兴趣,并希望将其中的一些维度进行聚合,则可以使用 sum() 函数

  • 例如,以下表达式根据 job 标签来对第 90 个百分位数进行聚合:
    1
    2
    3
    4
    5
    # histogram_quantile() 函数必须包含 le 标签
    histogram_quantile(0.9, sum(rate(employee_age_bucket_bucket[10m])) by (job, le))

    # 如果要聚合所有的标签,则使用如下表达式:
    histogram_quantile(0.9,sum(rate(employee_age_bucket_bucket[10m])) by (le))

Tips: 可以使用 rate() 函数来指定分位数计算的时间窗口。

注意: histogram_quantile 这个函数是根据假定每个区间内的样本分布是线性分布来计算结果值的(也就是说它的结果未必准确),最高的 bucket 必须是 le="+Inf" (否则就返回 NaN)。如果分位数位于最高的 bucket(+Inf) 中,则返回第二个最高的 bucket 的上边界。如果该 bucket 的上边界大于 0,则假设最低的 bucket 的的下边界为 0,这种情况下在该 bucket 内使用常规的线性插值。如果分位数位于最低的 bucket 中,则返回最低 bucket 的上边界。

注意: 如果 b 含有少于 2 个 buckets,那么会返回 NaN,如果 φ < 0 会返回 -Inf,如果 φ > 1 会返回 +Inf。


sort() 函数

描述: sort(v instant-vector) 函数对向量按元素的值进行升序排序,返回结果:key: value = 度量指标:样本值[升序排列]

1
sort(node_load5{})      # 正序


sort_desc() 函数

描述: sort(v instant-vector) 函数对向量按元素的值进行降序排序,返回结果:key: value = 度量指标:样本值[降序排列]

1
sort_desc(node_load5{}) # 反序


7.计数器

描述: 计数器包括 counter 类型、summary 类型和histogram类型指定中的_sum,_count,_bucket的时间序列。

Tips: 计数器的值只升不降,当应用重新启动后,计数器初始化为0.

rate 函数

描述: rate(v range-vector) 函数可以直接计算区间向量 v 在时间窗口内平均增长速率,即返回计数器在传入给它的范围向量中的每个时间序列每秒增加速率。它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。

Tips:

  • 1.该函数的返回结果不带有度量指标,只有标签列表。
  • 2.该函数可求得某一时间内的平均率( 次数 / 指定时间秒 ),而且自动处理由进程重启导致得计数器重置对其得问题。
  • 3.建议使用的范围向量的范围至少是抓取间隔的四倍,例如对于1min的抓取间隔,你可以使用4min的rate,但是通常会使用5min,rate(x_total[5m])。


示例演示:

  • 1) PromQL: rate(http_requested_total[5m]), 说明: 求得最后5分钟的平均每秒的请求率。

    1
    2
    3
    {instance="10.20.172.103:8000", job="control", method="GET", path="/"}  0.003508771929824561
    {instance="10.20.172.103:8000", job="control", method="GET", path="/api/"} 0.021052631578947368
    {instance="10.20.172.103:8000", job="control", method="GET", path="/favicon.ico"} 0.03508771929824561
  • 2) PromQL: rate(prometheus_http_requests_total[5m]), 例如以下表达式返回区间向量中每个时间序列过去 5 分钟内 HTTP 请求数的每秒增长率:

    1
    2
    3
    {code="200",handler="label_values",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
    {code="200",handler="query_range",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
    {code="200",handler="prometheus",instance="120.77.65.193:9090",job="prometheus",method="get"} 0.2

Tips : rate() 函数返回值类型只能用计数器,在长期趋势分析或者告警中推荐使用这个函数。

注意: 当将 rate() 函数与聚合运算符(例如 sum())或随时间聚合的函数(任何以 _over_time 结尾的函数)一起使用时,必须先执行 rate 函数,然后再进行sum聚合操作,否则当采样目标重新启动时 rate() 无法检测到计数器是否被重置。


increase() 函数

描述: increase(v range-vector) 函数是rate函数上的语法糖,例如 increase(x_total[5m]) 等同于 rate(x_total[5m] * 300) 的结果乘以范围向量的时间范围其它逻辑相同。

Tips: 该函数获取区间向量中的第一个和最后一个样本并返回其增长量, 它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。由于这个值被外推到指定的整个时间范围,所以即使样本值都是整数,你仍然可能会得到一个非整数值。

1
2
3
4
5
6
# 1.该函数的鲁棒性表现之一是它们在给定整数输入时可以返回非整数结果,
increase(x_total[15s]) # 10s 为 3,但是从 10s 数据推导到15s ,在increase会产生的结构是4.5


# 2.例如,以下表达式返回区间向量中每个时间序列过去 5 分钟内 HTTP 请求数的增长数:
increase(prometheus_http_requests_total{job="apiserver"}[5m])

Tips: increase 的返回值类型只能是计数器类型,主要作用是增加图表和数据的可读性, 使用 rate 函数记录规则的使用率,以便持续跟踪数据样本值的变化。


irate() 函数

描述:irate(v range-vector) 函数用于计算区间向量的增长率,但是其反应出的是瞬时增长率(即返回一个计数器正在增加的每秒速率),多用于图形展示。

Tips: irate 函数是通过区间向量中最后两个两本数据来计算区间向量的增长速率,它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。这种方式可以避免在时间窗口范围内的“长尾问题”,并且体现出更好的灵敏度,通过irate函数绘制的图标能够更好的反应样本数据的瞬时变化状态。

例如,以下表达式返回区间向量中每个时间序列过去 5 分钟内最后两个样本数据的 HTTP 请求数的增长率:

1
irate(prometheus_http_requests_total{job="api-server"}[5m])

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

Tips: 如果query_range 的步长大于抓取时间间隔,则使用irate时将跳过数据。

注意: 当将irate()函数与聚合运算符(例如 sum())或随时间聚合的函数(任何以 _over_time 结尾的函数)一起使用时,必须先执行 irate 函数,然后再进行聚合操作,否则当采样目标重新启动时 irate() 无法检测到计数器是否被重置。


resets() 函数

描述: resets(v range-vector) 的参数是一个区间向量(返回范围向量中的每个时间序列重置次数)。对于每个时间序列它都返回一个计数器重置的次数。两个连续样本之间的值的减少被认为是一次计数器重置。

1
2
3
# 1.显示进程的CPU时间在过去一个小时重置的次数。
resets(process_cpu_seconds_total[1h])
# {instance="localhost:9090", job="prom-Server"} 0


8.Gauge类型处理函数

changes() 函数

描述: changes (v range-vector)输入一个区间向量返回这个区间向量内Gauge类型每个样本数据值变化的次数(瞬时向量)

1
2
3
4
5
# 例如,如果样本数据值没有发生变化则返回结果为 1
changes(node_load5{instance="192.168.1.75:9100"}[1m]) # 结果为 1

# 例如,计算进程重启次数。
changes(process_start_time_seconds[1h]) # {instance="localhost:9090", job="Server"} 0


deriv() 函数

描述: deriv(v range-vector) 函数用于返回GuaGue值的变化速度,其参数是一个区间向量返回一个瞬时向量。

Tips: 它使用简单的线性回归计算区间向量 v 中各个时间序列的导数, 使用最小二乘法回归来估计范围向量中的每个时间序列的斜率。

Tips: 这个函数一般只用在 Gauge 类型的时间序列上。

1
2
# 1.根据过去一小时的样本计算每秒驻留内存的变化速度。
deriv(process_resident_memory_bytes[1h]) # {instance="localhost:9090", job="Server"} 1195.152658509455


predict_linear() 函数

描述: predict_linear(v range-vector, t scalar) 函数可以预测时间序列 v 在 t 秒后的值。根据所提供范围内的数据预测未来Gauge的值。

Tips: 它基于简单线性回归的方式,对时间窗口内的样本数据进行统计,从而可以对时间序列的变化趋势做出预测。该函数的返回结果不带有度量指标,只有标签列表。

例如,基于 2 小时的样本数据,来预测主机可用磁盘空间的是否在 4 个小时候被占满,可以使用如下表达式:predict_linear(node_filesystem_free{job="node"}[2h], 4 * 3600) < 0 通过下面的例子来观察返回值:

1
2
3
4
5
6
predict_linear(prometheus_http_requests_total{code="200",instance="120.77.65.193:9090",job="prometheus",method="get"}[5m], 5)
# 结果:
{code="200",handler="query_range",instance="120.77.65.193:9090",job="prometheus",method="get"} 1
{code="200",handler="prometheus",instance="120.77.65.193:9090",job="prometheus",method="get"} 4283.449995397104
{code="200",handler="static",instance="120.77.65.193:9090",job="prometheus",method="get"} 22.99999999999999
...

例如, 预测四个小时内每个文件系统剩余的可用空间量。

1
2
3
4
5
predict_linear(node_filesystem_free_bytes{instance="192.168.1.107:9100"}[1h],4 * 3600)
# {device="/dev/mapper/ubuntu--vg-lv--0",fstype="ext4", instance="192.168.1.107:9100", job="linux_exporter", mountpoint="/"}
81532763513.3
# 等同于
deriv(node_filesystem_free_bytes{instance="192.168.1.107:9100"}[1h] * 4 * 3600) + node_filesystem_free_bytes{instance="192.168.1.107:9100"}[1h]

这个函数一般只用在 Gauge 类型的时间序列上。


delta() 函数

描述: delta(v range-vector)值,其参数是一个区间向量,返回一个瞬时向量。它计算一个区间向量 v 的第一个元素和最后一个元素之间的差值。由于这个值被外推到指定的整个时间范围,所以即使样本值都是整数,你仍然可能会得到一个非整数值。

例如,下面的例子返回过去两小时的 CPU 温度差:

1
2
3
4
5
delta(node_hwmon_temp_celsius{instance="aiserver"}[1h])
# {chip="platform_coretemp_0", instance="aiserver", job="K8S-weiyigeek-Prod", sensor="temp1"}
# -2.0338977305373644
# {chip="platform_coretemp_0", instance="aiserver", job="K8S-weiyigeek-Prod", sensor="temp10"}
# -2.0338977305373644


idelta() 函数

描述: idelta(v range-vector) 的参数是一个区间向量, 返回一个瞬时向量。它计算最新的 2 个样本值之间的差值。
即采用时间范围中的最后两个样本并返回它们的差异。


holt_winters() 函数

描述: holt_winters(v range-vector, sf scalar, tf scalar) 函数基于区间向量 v,生成时间序列数据平滑值。平滑因子 sf 越低, 对旧数据的重视程度越高。趋势因子 tf 越高,对数据的趋势的考虑就越多。其中0< sf, tf <=1并且它只能与仪表一起使用。

1
2
3
# 1.平滑内存使用量,平滑因子为0.1,趋势因子为0.5,该两个因数必须介于(0~1)之间。
holt_winters(process_resident_memory_bytes[1h],0.1,0.5)
# {instance="localhost:9090", job="Server"} 167181065.43937477


9.<aggregation>_over_time() 随时间聚合函数

描述: 下面的函数列表允许传入一个区间向量,它们会聚合每个时间序列的范围,并返回一个瞬时向量:

1
2
3
4
5
6
7
8
* avg_over_time(range-vector) : 区间向量内每个度量指标的平均值。
* min_over_time(range-vector) : 区间向量内每个度量指标的最小值。
* max_over_time(range-vector) : 区间向量内每个度量指标的最大值。
* sum_over_time(range-vector) : 区间向量内每个度量指标的求和。
* stddev_over_time(range-vector) : 区间向量内每个度量指标的总体标准差。
* stdvar_over_time(range-vector) : 区间向量内每个度量指标的总体标准方差。
* count_over_time(range-vector) : 区间向量内每个度量指标的样本数据个数。
* quantile_over_time(scalar, range-vector) : 区间向量内每个度量指标的样本数据值分位数,φ-quantile (0 ≤ φ ≤ 1),该函数适用于在范围向量中跨单个时序数据查询。

Tips : 请注意,指定间隔中的所有值在聚合中都具有相同的权重,即使这些值在整个间隔中的间隔不等。


absent_over_time() 函数

描述: absent_over_time(v range-vector) 如果传递给它的范围向量有任何元素则返回一个空向量,如果传递给它的范围向量没有元素,则返回一个值为 1 的 1 元素向量。

1
2
3
4
5
6
7
8
absent_over_time(nonexistent{job="myjob"}[1h])
# => {job="myjob"}

absent_over_time(nonexistent{job="myjob",instance=~".*"}[1h])
# => {job="myjob"}

absent_over_time(sum(nonexistent{job="myjob"})[1h:])
# => {}

Tips : 在给定的指标名称和标签组合在一定时间内不存在时间序列时发出警报非常有用。


示例演示

1
2
3
4
5
# 1.查看一个进程内存峰值使用量
max_over_time(process_resident_memory_bytes[1h]) # {instance="localhost:9090", job="prom-Server"} 219848704

# 2.更近一步计算整个应用程序。
max without(instance)(max_over_time(process_resident_memory_bytes[1h]))

Tips: 不要在rate上使用avg_over_time,因为该函数返回的是瞬时而不是范围向量。


0x03 实际案例

描述: 实际案例将会持续更新。
基础示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 1.显示所有节点的多个挂载点的文件系统空间大小
node_filesystem_size_bytes
# node_filesystem_size_bytes{device="/dev/mapper/ubuntu--vg-lv--0", fstype="ext4", instance="192.168.1.107:9100", job="linux_exporter", mountpoint="/"} 104091082752
# node_filesystem_size_bytes{device="/dev/sda4", fstype="ext4", instance="192.168.1.223:9100", job="linux_exporter", mountpoint="/"} 284151599104

# 2.指定label的name查询
prometheus_prometheus_http_requests_total{code="200"}
prometheus_prometheus_http_requests_total{code="200",job="prometheus"}

# 3.查询指定标签的节点文件系统空间大小
node_filesystem_size_bytes {env="prod", fstype="ext4", instance="192.168.1.107:9100"}

# 4.采用正则表达式进行匹配
# - prometheus 请求响应码在2.x和3.x以及访问路径不为/alert.*匹配到的。
prometheus_prometheus_http_requests_total{code =~ "2.*|3.*",handler !~ "/alert.*"}
# prometheus_prometheus_http_requests_total{code="200", handler="/api/v1/label/:name/values", instance="localhost:9090", job="Server"} 40
# prometheus_prometheus_http_requests_total{code="200", handler="/api/v1/labels", instance="localhost:9090", job="Server"} 1

# 5.通过`[time]`来实现时间范围
prometheus_prometheus_http_requests_total{code =~ "2.*|3.*",handler=~ "/alert.*" ,job="prometheus"}[5m]

# 6.五分钟的cpu平均使用率
100 - (avg(irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# 7.可用的内存百分比
(node_memory_MemAvailable_bytes / (node_memory_MemTotal_bytes))* 100

# 8.磁盘一分钟读的速率
irate(node_disk_reads_completed_total{}[1m])
rate(prometheus_tsdb_head_samples_appended_total[5m]) # - 计算出 Prometheus 一分钟内每秒的平均采集数。

# 9.网络五分钟的接收速率(网络流量)
irate(node_network_receive_bytes_total{device!~'tap.*|veth.*|br.*|docker.*|virbr*|lo*'}[5m])* 8
# {cluster="weiyigeek-lb-vip.k8s", device="cali05e09d75aa7", instance="192.168.1.225:9100", job="linux_exporter"} 5476.866666666667


promtheus

1
2
# 监控实例是否正常
avg without()(up) < 1


node_exporter

1
2
3
4
5
6
7
8
9
10
# CPU 指标 # 
# CPU 核心数统计
count without(cpu)(node_cpu_seconds_total{mode="idle"})
# CPU 使用率大于90%
(node_load5 /ignoring(mode) count without(cpu)(node_cpu_seconds_total{mode="idle"}) * 100) > 90
round(100 - ((avg by (instance,job,env)(irate(node_cpu_seconds_total{mode="idle"}[5m]))) * 100)) > 90
# 系统每个CPU模式的平均消耗
avg without(cpu)(rate(node_cpu_seconds_total[5m]))
# 所有CPU的空闲模式的时间比例
avg without(cpu, mode)(rate(node_cpu_seconds_total{mode="idle"}[5m]))


Windows (win_exporter)

1
2
3
4
5
6
7
8
# Windows CPU 核心数
count without(core)(windows_cpu_time_total{mode="idle"})

# Windows CPU 平均使用率大于90%
round (100 - ((avg without(core,mode)(irate(windows_cpu_time_total{mode="idle"}[5m]))) * 100)) > 90

# Windows Mem 平均使用率大于90%
round((1 - (windows_os_physical_memory_free_bytes / windows_cs_physical_memory_bytes)) * 100) > 90