[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 promhttp_metric_handler_requests_total{code="200" } count(promhttp_metric_handler_requests_total{code="200" })
(2) 使用Graph
选项卡,展示查询到的数据 例如,输入以下表达式来绘制在自我抓取的Prometheus中发生的返回状态代码200
的每秒HTTP请求率:1 2 rate(promhttp_metric_handler_requests_total{code="200" ,job="LocalServer" }[5m])
您可以尝试图形范围参数和其他设置。
2.基础标准 2.1 时间单位: 描述: Prometheus 中的持续时间被用于 PromQL
和配置文件
中,它支持的单位如下:
单位
含义
ms
毫秒
s
秒, 等于 1000 ms
m
分钟, 等于 60 s
h
小时, 等于 60 min
d
天, 等于 24h
w
周, 等于 7d
y
年, 等于 365d
以下是一些有效持续时间的示例:
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 不会丢弃反引号内的换行符(反引号内不处理转义
)。
例子: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) 即时时向量选择器
: 查询评估时间之前返回最近样本的瞬时向量,即零个或者多个时间序列的列表,每个时间序列包含一个样本,所有时间序列都共享相同的时间戳
。并且当你使用瞬时向量选择器时,不会返回已过时的时间序列。
示例说明:
Tips: 例如返回即时向量的表达式是唯一可以直接绘制的类型。
区间数据 (Range vector) 范围向量选择器
: 与每个时间序列返回一个样本的瞬时向量选择器不同,范围选择器为每个时间序列返回多个样本(包含一组时序,每个时序有多个点
)即(包含每个时间序列随时间变化的数据点范围),并且范围向量总是与rate、avg_over_time
函数联合使用。
示例说明: 1 2 3 4 5 6 7 8 9 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 prometheus_prometheus_http_requests_total{code="200" ,}
Tips : 在采用Graph进行展示时,查询的表达式类型”range vector”是无效可导致执行查询时出错,必须是标量或即时向量。
字符串数据 (String) 描述: 一个简单的字符串值;目前未使用。
4.选择器 - (Selector
) 描述:在 Prometheus 浏览器表达式中选择器非常重要,它可以缩小我们查询或者要处理的时间序列范围。通过在花括号 ( {}) 中附加逗号分隔的标签匹配器列表来进一步过滤这些时间序列。
例如: job=”node” 被称为匹配器,并且你可以在一个选择器利用多个匹配器串在一起。1 2 go_info{BusinessType="jszg" ,env="prod" }
5.匹配器 - (Matcher
) 描述: 常用的匹配器解析说明。
=
(等式匹配器) : 最是常用的匹配器,通过此操作,你可以指定返回的时间系列包含一个具有特定值的标签。
例如: job="node"
作为一个空值标签和没有该标签一样, 你可以使用 foo=""
来指定 foo
标签不存在的指标。1 2 3 go_info{env="" ,instance="aiserver" }
!=
(否定的等式匹配器) : 通过此操作,你可以指定返回的时间系列没有包含特定值的标签。
例如: job != "node"
1 2 3 go_info{version!="go1.15.8" ,BusinessType="zk" }
=~
(正则表示式匹配器) : 通过此操作,它可以定标签的值与正则表达式相匹配。表达式语法可以在百度中进行查询。
例如: job =~ "n.*"
1 2 3 4 5 6 7 8 9 10 11 12 go_info{instance=~"ai.*" } {job=~".*" } # Bad! {job=~".+" } # Good! {job=~".*" ,method="get" } # Good! {__name__=~"job:.*" }
!~
(正则表示式反匹配器) : 通过此操作, 它可以定标签的值与正则表达式不相匹配。
例如: job !~ "n.*"
1 2 3 go_info{env!~"p.*" ,instance="aiserver" }
Tips : Prometheus 中的所有正则表达式都使用RE2 语法(https://github.com/google/re2/wiki/Syntax)。
示例演示: 1 2 3 4 5 6 7 8 9 node_filesystem_size_bytes{job=~"L.*" , device!~"tmpfs|shm" ,mountpoint=~"/$" } / 1024^3 node_filesystem_size_bytes{job=~"Linux" , mountpoint=~"/$" } / 1024^3
6.偏移修改器 - (Offset
) 描述: 该修饰符可以适用于任意类型的向量选择器,它可以让你获取查询执行时间,并在每个选择器的当前基础上将其回退到过去的这个时间上, 即可以改变时间为查询中的个别时刻和范围矢量偏移。。
Tips: 请注意 offset 修饰符
总是需要立即跟随选择器
示例演示: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 prometheus_http_requests_total offset 5 m sum(prometheus_http_requests_total{method="GET" } offset 5 m) process_resident_memory_bytes{instance="localhost:9090" } process_resident_memory_bytes{instance="localhost:9090" } offset 1 h rate(process_cpu_seconds_total{instance="localhost:9090" }[5 m]) - rate(process_cpu_seconds_total{instance="localhost:9090" }[5 m] offset 1 h)
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{handler="/metrics" } @ 1609746000 sum(prometheus_prometheus_http_requests_total{handler="/metrics" } @ 1609746000 ) rate(prometheus_prometheus_http_requests_total{handler="/metrics" }[5 m] @ 1609746000 ) # offset after @ prometheus_prometheus_http_requests_total @ 1609746000 offset 5 m # offset before @ prometheus_prometheus_http_requests_total offset 5 m @ 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 <instant_query> '[' <range > ':' [<resolution>] ']' [ @ <float_literal> ] [ offset <duration> ]
9.查询类型 Counter 类型 描述: 它是使用最频繁的数据类型,其记录的是事件的数量或者大小,通常用来跟踪某个特定代码路径被执行的频率,此类型其根本的的意义是计数器随着时间的推移而增加的速度。
Tips : 对于PromQL而言必须确保Counter变量是递增的,只有这样才能保证rate或者其它函数不会把counter的减少误当做应用重启后Counter置零操作。
1 2 3 4 5 6 rate(node_network_receive_bytes_total{job="Linux" }[5m]) sum without(device)(rate(node_network_receive_bytes_total{job="Linux" }[5m]))
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
查询每台机器上最大的挂载文件系统的大小。
1 2 3 max without(device,fstype,mountpoint)(node_filesystem_size_bytes{job="weiyigeek-Linux" }) / 1024^3
查询每台机器上挂载点平均的文件系统的大小。
1 2 3 avg without(device,fstype,mountpoint)(node_filesystem_size_bytes{job="weiyigeek-Linux" }) / 1024^3
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 sum without(handler)(rate(prometheus_http_response_size_bytes_count[5m])) sum without(handler)(rate(prometheus_http_response_size_bytes_sum[5m])) sum without(handler)(rate(prometheus_http_response_size_bytes_sum[5m])) / sum without(handler)(rate(prometheus_http_response_size_bytes_count[5m])) 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])) )
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 histogram_quantile( 0.90, sum without(instance)(rate(prometheus_tsdb_compaction_duration_seconds_bucket[1d])) ) sum without(instance)(rate(prometheus_tsdb_compaction_duration_seconds_sum[1d])) / sum without(instance)(rate(prometheus_tsdb_compaction_duration_seconds_count[1d]))
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 { "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 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 5 ^ 2
Tips : 描述: 标量是没有维度的单个数字,是除了瞬时与范围向量之外,被称为标量类型的值。 例如, 0 是标量它的值为零。 例如, {} 0 是包含单个样本且没有标签且值为零的瞬时向量。
1.2 比较二元运算符 描述:在PromQL中比较运算符是过滤的1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ==,!=,>,<,>=,<=, =~ , !~ process_open_fds > 10 10 < process_open_fds 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 1024 >= bool 42 sort_desc(sum without(instance)(process_open_fds >= bool 10)) avg without(instance)(count without(device)(node_disk_io_now) > bool 4)
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 node_hwmon_temp_celsius or ignoring(label) (node_hwmon_sensor_label * 0 + 1) node_hwmon_temp_celsius * ignoring(label) group_left(label) (node_hwmon_sensor_celsius or ignoring(lable)(node_hwmon_temp_celsius * 0 + 1)) node_uname_info or up{job="Server" } * 0 rate(process_cpu_seconds_total[5m]) unless process_resident_memory_bytes < 1024^2 * 100 up{instance="localhost:9090" } == 1 unless node_custom up == 1 unless on (job,instance) node_custom (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> 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 process_open_fds{instance="localhost:9090" } / process_max_fds{instance="localhost:9090" } sum without(cpu) (rate(node_cpu_seconds_total{mode="idle" }[5 m])) /ignoring(mode) sum without(mode,cpu) (rate(node_cpu_seconds_total[5 m])) sum by(cpu) (rate(node_cpu_seconds_total{mode="idle" }[5 m])) / on(mode) sum by(mode,cpu) (rate(node_cpu_seconds_total[5 m]))
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> method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
实际案例:1 2 3 4 5 6 7 sum without(cpu)(rate(node_cpu_seconds_total[5 m])) / ignoring(mode) group_left sum without(mode,cpu)(rate(node_cpu_seconds_total[5 m])) sum without(mode,cpu)(rate(node_cpu_seconds_total[5 m])) / ignoring(mode) group_right sum without(cpu)(rate(node_cpu_seconds_total[5 m]))
Tips : 多对一和一对多
匹配是应该仔细考虑的高级用例。通常正确可使用ignoring(<labels>)
提供所需的结果。
ignoring 修饰符 描述: 在匹配时忽略某些标签(类似于聚合操作中的without方式
on 修饰符 描述: 在匹配时允许减少该组被认为标签来提供的列表(类似于聚合操作中的by方式)
group_left 修饰符 描述: 该修饰符有两个功能,一是指定左侧操作数组中可以有多个匹配样本(始终从左侧操作数的样本中获取所有标签
)确保保留左侧需要进行多对一向量匹配的额外标签,二是将信息指标中的标签添加到一个目标的其它指标中。
简单示例:1 2 3 4 5 6 7 8 9 up * on (instance,job) group_left (version) python_info {instance="10.20.172.103:8000" , job="control" , version="3.7.3" } node_hwmon_temp_celsius * ignoring(label) group_left(label) node_hwmon_sensor_label
Tips: 可使用任何运算符来连接指标,当信息指标的值为1时时候,乘法不会更改其他指标的值。
group_right 修饰符 描述: 其工作方式与group_left相同,只是将操作对象从左换到右,但是通常使用group_left因为任何标签都是从左向右复制的,为了保证一致性以及方便人员理解所以推荐。
简单示例:1 2 3 prometheus_build_info * on (instance) group_right(version,revision) up
3.聚合运算符 描述: Prometheus 支持以下内置聚合运算符,可用于聚合单个即时向量的元素,从而生成具有聚合值的更少元素的新向量。
分组 描述: 在学习聚合运算符之前,需要了解实践序列的分组方式。
(1) Without 指定要删除的标签 1 2 3 4 5 6 7 8 9 sum without(device,mountpoint)(node_filesystem_size_bytes{instance="10.0.0.107:9100" }) 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 sort_desc(count by(__name__)({__name__=~"node_filesystem.+" })) count by(release)(node_uname_info) sum by()(node_uname_info)
聚合 描述: 聚合运算符寄仅适用于瞬时向量,也输出瞬时向量。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 sum without (instance) (prometheus_prometheus_http_requests_total) sum by (code, handler) (prometheus_prometheus_http_requests_total) count_values("version" , go_info) topk(5 , prometheus_prometheus_http_requests_total)
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 avg 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 count without(device)(node_disk_read_bytes_total{device=~"sd.+" ,instance="10.0.0.107:9100" }) count without(cpu)(count without(mode)(node_cpu_seconds_total{instance="10.0.0.107:9100" })) count(count without(cpu)(node_cpu_seconds_total{instance="10.0.0.107:9100" }))
count_values() 函数 描述: 该函数可以从一个组中返回多个时间序列。并按照组中的时间序列值建立频率直方图,每个值的计数作为输出时间序列的值,原始值作为新标签。
示例演示:1 2 3 4 5 6 7 8 9 10 11 count_values("kernelVersion" ,count without(instance,version,nodename,nodeType)(node_uname_info)) 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.+" }))
Tips: count_values 可与count 结合使用,来计算给定的聚合组的唯一值的数量。
min() 函数 max() 函数 描述: 两个聚合函数分别求取组内最小或最大值作为组的返回值。
示例演示:1 2 3 4 5 min without(device,fstype,mountpoint)(node_filesystem_size_bytes) max without(device,fstype,mountpoint)(node_filesystem_size_bytes)
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 方差: ((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
示例演示:1 2 3 4 5 6 7 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 topk without(device,fstype,mountpoint)(2 ,node_filesystem_size_bytes{instance="10.0.0.107:9100" }) bottomk without(device,fstype,mountpoint)(2 ,node_filesystem_size_bytes{instance="10.0.0.107:9100" }) / 1024 ^3 topk(5 ,avg_over_time(prometheus_http_requests_total[1 h]))
Tips: 该topk聚合函数不会删除__name__
标签,但是如果针对其数据进行运算时或者包含其它函数时
会删除__name__
标签(看上述两个示例),它们会在结果中展示。
quantile() 函数 描述: 该聚合函数指定分位数的值作为组的返回值,适用于对瞬时向量做跨聚合组查询,并且与topk类似分位数使用一个参数。
例如1, 查询不同目标机器中CPU系统模式使用率的第90百分位是多少。
1 2 3 4 quantile without(cpu) (0.9 ,rate(node_cpu_seconds_total{mode="system" }[5 m]))
例如2,使用分位数来显示图表中的中位数,第25百分位数和第75百分位数。
1 2 3 4 5 quantile without(instance) (0.75 ,rate(process_cpu_seconds_total[5 m])) quantile without(instance) (0.25 ,rate(process_cpu_seconds_total[5 m]))
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 scalar(sqrt(vector(4))) scalar(year()) sum(rate(node_cpu_seconds_total{mode!="idle" }[5m])) / scalar(count(node_cpu_seconds_total{mode="idle" }))
3.数学函数 描述: 数学函数对瞬时向量执行标准数学计算。并且瞬时向量中的每个样本都独立处理,返回值将删除指标名称。
abs() 函数 描述: abs(v instant-vector)
返回输入向量的所有样本的绝对值。
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 中所有样本数据的二进制对数。特殊情况同上。
log10() 函数 描述: log10(v instant-vector)
计算瞬时向量 v 中所有样本数据的十进制对数。特殊情况同上。
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))
sqrt() 函数 描述: sqrt(v instant-vector)
函数计算向量 v 中所有元素的平方根。
1 2 3 4 5 6 7 sqrt(vector(9)) vector(9) ^ 0.5 vector(9) ^ (1/3)
ceil() 函数 描述: ceil (v instant-vector)
将 v 中所有元素的样本值向上四舍五入
到最接近的整数。例如:1 2 node_load5{instance="192.168.1.75:9100" } ceil(node_load5{instance="192.168.1.75:9100" })
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)) floor(vector(6.5)) round(vector(6.5)) round(vector(6.4))
clamp() 函数 描述: clamp(v instant-vector, min scalar, max scalar)
将所有元素的样本值钳制在v
下限为min
和上限为max
。
特殊情况: - 返回空向量 if min > max
- 返回NaN
ifmin
或max
isNaN
clamp_max() 函数 描述: clamp_max(v instant-vector, max scalar)
函数,输入一个瞬时向量和最大值,样本数据值若大于 max,则改为 max,否则不变。例如:1 2 node_load5{instance="192.168.1.75:9100" } clamp_max(node_load5{instance="192.168.1.75:9100" }, 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" } clamp_min(node_load5{instance="192.168.1.75:9100" }, 3) clamp_min(process_open_fds,10)
4.时间函数 描述: Prometheus提供几个处理时间的函数,注意其完全使用UTC并没有时区的概念。
time() 函数 描述: time() 函数返回从 1970-01-01
到现在的秒数。注意:它不是直接返回当前时间而是时间戳.1 2 3 4 5 time() time() - process_start_time_seconds
minute() 函数 描述: minute(v=vector(time()) instant-vector)
函数返回给定 UTC 时间当前小时的第多少分钟。结果范围:0~59。
hour() 函数 hour(v=vector(time()) instant-vector)
以 UTC 格式返回每个给定时间的一天中的小时。返回值从 0 到 23。
month() 函数 描述: month(v=vector(time()) instant-vector)
函数返回给定 UTC 时间当前属于第几个月,结果范围:0~12。
year() 函数 描述: year(v=vector(time()) instant-vector)
函数返回被给定 UTC 时间的当前年份。
注意: 即使区间向量内的值分布不均匀,它们在聚合时的权重也是相同的。
实例演示:1 2 3 4 5 6 7 8 9 10 year(process_start_time_seconds) year(process_start_time_seconds) == bool scalar(year()) * (month(process_start_time_seconds) == bool scalar(month())) sum(year(process_start_time_seconds) == bool scalar(year()) * (month(process_start_time_seconds) == bool scalar(month())))
Tips : 乘法运算符在布尔值使用时就像和
运算符一样值1表示真,否则为假。
day_of_month() 函数 描述: day_of_month(v=vector(time()) instant-vector)
函数,返回被给定 UTC 时间所在月的第几天。返回值范围:1~31。1 day_of_month(vector(time()))
day_of_week() 函数 描述: day_of_week(v=vector(time()) instant-vector)
函数,返回被给定 UTC 时间所在周的第几天。返回值范围:0~6,0 表示星期天。1 day_of_week(vector(time()))
days_in_month() 函数 描述: days_in_month(v=vector(time()) instant-vector)
函数,返回当月一共有多少天。返回值范围:28~31。1 days_in_month(vector(time()))
timestamp() 函数 描述:timestamp(v instant-vector)
函数返回向量 v 中的每个样本的时间戳(从 1970-01-01 到现在的秒数)。
该函数从 Prometheus 2.0 版本开始引入, 与其它时间函数不同的是,它查看瞬时向量中的样本的时间戳而不是值。
1 2 3 4 5 6 7 8 timestamp(vector(time())) timestamp(up) node_time_seconds - timestamp(node_time_seconds)
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" } => label_join(up{instance="192.168.1.8:2379" ,job="etcd" ,service="etcd-k8s" }, "foo" , "," , "job" , "service" ) =>
例如, 一个简单例子1 2 3 4 5 go_info{job="LocalServer" } label_join(go_info{job="LocalServer" },"newlable" ,'|' ,"job" ,"version" )
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" } label_replace(up{job="LocalServer" }, "instance" , "$1 :9200" , "job" , "(.*)" )
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 absent(up) absent(up_not_existent) absent(up_not_existent) go_gc_duration_seconds_sum{job="LocalServer" } ==>> 4.2270563150000005 absent(go_gc_duration_seconds_sum{job="LocalServer" }) ==>> Empty query result prometheus_http_requests_total{method="get" } absent(prometheus_http_requests_total{method="get" }) => 1 absent(nonexistent{job="myjob" }) => {job="myjob" } => 1 absent(nonexistent{job="myjob" ,instance=~".*" }) => {job="myjob" } => 1 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]))
这表示最近 10 分钟之内 90% 的样本的最大值为 35.714285714285715。
Tips : 这个计算结果是每组标签组合成一个时间序列。我们可能不会对所有这些维度(如 job、instance 和 method)
感兴趣,并希望将其中的一些维度进行聚合,则可以使用 sum() 函数
例如,以下表达式根据 job 标签来对第 90 个百分位数进行聚合:1 2 3 4 5 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 = 度量指标:样本值[升序排列]
。
sort_desc() 函数 描述: sort(v instant-vector)
函数对向量按元素的值进行降序排序,返回结果:key: value = 度量指标:样本值[降序排列]
。
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 increase(x_total[15s]) 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 resets(process_cpu_seconds_total[1h])
8.Gauge类型处理函数 changes() 函数 描述: changes (v range-vector)
输入一个区间向量返回这个区间向量内Gauge类型每个样本数据值变化的次数(瞬时向量)
。1 2 3 4 5 changes(node_load5{instance="192.168.1.75:9100" }[1m]) changes(process_start_time_seconds[1h])
deriv() 函数 描述: deriv(v range-vector)
函数用于返回GuaGue
值的变化速度,其参数是一个区间向量返回一个瞬时向量。
Tips: 它使用简单的线性回归计算区间向量 v 中各个时间序列的导数, 使用最小二乘法回归来估计范围向量中的每个时间序列的斜率。
Tips: 这个函数一般只用在 Gauge 类型的时间序列上。1 2 deriv(process_resident_memory_bytes[1h])
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) 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])
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 holt_winters(process_resident_memory_bytes[1h],0.1,0.5)
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]) absent_over_time(nonexistent{job="myjob" ,instance=~".*" }[1h]) absent_over_time(sum(nonexistent{job="myjob" })[1h:])
Tips : 在给定的指标名称和标签组合在一定时间内不存在时间序列时发出警报非常有用。
示例演示 1 2 3 4 5 max_over_time(process_resident_memory_bytes[1h]) 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 node_filesystem_size_bytes prometheus_prometheus_http_requests_total{code="200" } prometheus_prometheus_http_requests_total{code="200" ,job="prometheus" } node_filesystem_size_bytes {env="prod" , fstype="ext4" , instance="192.168.1.107:9100" } prometheus_prometheus_http_requests_total{code =~ "2.*|3.*" ,handler !~ "/alert.*" } prometheus_prometheus_http_requests_total{code =~ "2.*|3.*" ,handler=~ "/alert.*" ,job="prometheus" }[5m] 100 - (avg(irate(node_cpu_seconds_total{mode="idle" }[5m])) * 100) (node_memory_MemAvailable_bytes / (node_memory_MemTotal_bytes))* 100 irate(node_disk_reads_completed_total{}[1m]) rate(prometheus_tsdb_head_samples_appended_total[5m]) irate(node_network_receive_bytes_total{device!~'tap.*|veth.*|br.*|docker.*|virbr*|lo*' }[5m])* 8
promtheus
node_exporter 1 2 3 4 5 6 7 8 9 10 count without(cpu)(node_cpu_seconds_total{mode="idle" }) (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 avg without(cpu)(rate(node_cpu_seconds_total[5m])) avg without(cpu, mode)(rate(node_cpu_seconds_total{mode="idle" }[5m]))
Windows (win_exporter) 1 2 3 4 5 6 7 8 count without(core)(windows_cpu_time_total{mode="idle" }) round (100 - ((avg without(core,mode)(irate(windows_cpu_time_total{mode="idle" }[5m]))) * 100)) > 90 round((1 - (windows_os_physical_memory_free_bytes / windows_cs_physical_memory_bytes)) * 100) > 90