天天看点

Prometheus监控之PromQL表达式语法学习(1)

0x00 PromQL 介绍

  • 1.基础简述
  • 2.基础标准
  • 3.数据类型
  • 瞬时数据 (Instant vector)
  • 区间数据 (Range vector)
  • 纯量数据 (Scalar)
  • 字符串数据 (String)
  • 4.选择器 - (​

    ​Selector​

    ​)
  • 5.匹配器 - (​

    ​Matcher​

    ​)
  • 6.偏移修改器 - (​

    ​Offset​

    ​)
  • 7.修饰符 -​

    ​@​

  • 8.子查询
  • 9.查询类型
  • Counter 类型
  • Gauge 类型
  • Summary 类型
  • Histogram 类型
  • 10.API查询指标数据
  • Query
  • Query_range

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​

// 请求`/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请求率:
rate(promhttp_metric_handler_requests_total{code="200",job="LocalServer"}[5m])
# {code="200", instance="localhost:9090", job="LocalServer"}  0.016666666666666666      

您可以尝试图形范围参数和其他设置。

Prometheus监控之PromQL表达式语法学习(1)

2.基础标准

2.1 时间单位:

描述: Prometheus 中的持续时间被用于 ​​

​PromQL​

​​ 和​

​配置文件​

​中,它支持的单位如下:

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

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

5h
1h30m
5m
10s      

Tips : 你可以使用一个整数带一个单位,例如​

​90m​

​​是有效的,而​

​1h30m​

​​和​

​1.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 不会丢弃反引号内的换行符(​

​反引号内不处理转义​

​)。

例子:

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

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

[-+]?(
[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?
| 0[xX][0-9a-fA-F]+
| [nN][aA][nN]
| [iI][nN][fF]
)      

例子:

23
-2.43
3.4e-9
0x8f
-Inf
NaN      

3.数据类型

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

瞬时数据 (Instant vector)

​即时时向量选择器​

​​: 查询评估时间之前返回最近样本的瞬时向量,即零个或者多个时间序列的列表,​

​每个时间序列包含一个样本,所有时间序列都共享相同的时间戳​

​。并且当你使用瞬时向量选择器时,不会返回已过时的时间序列。

示例说明:

# (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) 查询执行时间为准按照分钟粒度返回与选择器匹配的所有时间序列
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) 纯量只有一个数字,没有时序
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" 被称为匹配器,并且你可以在一个选择器利用多个匹配器串在一起。

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) 查询标签 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) 查询标签 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) 查询标签 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) 查询标签 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) 在选择器中使用具有相同标签名称的多个匹配器,查找 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 修饰符​

​总是需要立即跟随选择器

示例演示:

// 例如,以下表达式返回 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​

​ 标志启用。

示例演示:

// 例如,以下表达式返回 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() 都有的评估时间。
  • 对于范围查询, 它们分别解析为范围查询的开始和结束,并在所有步骤中保持不变。
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 : 子查询的结果是一个范围向量

格式定义:

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

9.查询类型

Counter 类型

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

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

# (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方法。

  • 查询计算每台计算机上文件系统的总大小。
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      
  • 查询每台机器上最大的挂载文件系统的大小。
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      
  • 查询每台机器上挂载点平均的文件系统的大小。
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) 查询并返回提供每秒的总请求数
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个左右才能保证足够的准确率,该数字看起来很小的数字,但是存储桶是需要成本,并且每个桶都是一个额外的时序存储。

# 用于跟踪时序数据库压缩所需的秒数 : 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:使用当前时间进行指标查询

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​

​标准的时间

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)

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.利用标量进行查询,其没有标签只是数字

描述: 与 {} 不同,后者是一个没标签的时间序列标识符。

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 : 将来自不同执行的所有瞬时向量组合成范围向量并返回。

# 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"]
]
}
]
}
}      

继续阅读