在prometheus 表达式中,可操作的数据类型可归结为以下4类:
Instant vector
一组时间戳相同的时间序列。eg:
promQL: http_requests_total
---
element value
http_requests_total{instance=xxx} 1
http_requests_total{instance=aaa} 2
http_requests_total{instance=ccc} 3
Rage vector
某个时段的时间序列的值的集合。eg:
promQL: http_requests_total[1m]
---
element value
http_requests_total{instance=xxx} 40668
@1562816358.478
40669
@1562816373.478
40670
@1562816388.478
40671
@1562816403.478
Scalar
一个简单的浮点数, eg:
promQL: 1+1
---
element value
scalar 2
String
一个字符串,暂未用到
prometheus 采集的metrics都已时间序列的方式存储。PromQL 是时间序列查询语法。由上数据类型可知,查询结果共有四种数据类型。以下为各数据类型查询语法介绍。
Instant vector 表示同一时间戳下具有相同特征的时间序列。以node_exporter
采集的metrics node_memory_MemAvailable
为例。
获取全部的node_memory_MemAvailable
metric 时间序列:
promQL: node_memory_MemAvailable
---
element value
node_memory_MemAvailable{instance="192.168.1.1:9100",job="node_exporter",service="web"} 1537667072
node_memory_MemAvailable{instance="192.168.1.2:9100",job="node_exporter",service="web"} 15886266368
node_memory_MemAvailable{instance="192.168.1.3:9100",job="node_exporter",service="db"} 16204136448
node_memory_MemAvailable{instance="192.168.1.3:9100",job="node_exporter",service="mq"} 16204136448
即不加任何过滤条件。如果只看web
服务的时间序列,查询语句如下:
promQL: node_memory_MemAvailable{service="web"}
---
element value
node_memory_MemAvailable{instance="192.168.1.1:9100",job="node_exporter",service="web"} 1537667072
node_memory_MemAvailable{instance="192.168.1.2:9100",job="node_exporter",service="web"} 15886266368
标签支持以下几种操作符:
=
: 完全匹配!=
: 完全不匹配=~
: 部分匹配(可接正则表达式)!~
: 部分不匹配(可接正则表达式)例如过滤除service=web
外的其他时间序列,可通过:
promQL: node_memory_MemAvailable{service!~"web.*"}
or
promQL: node_memory_MemAvailable{service!="web"}
or
promQL: node_memory_MemAvailable{service=~"mq|db"}
与Instant Vector selector
不同的是,range vector 需要带上时间间隔。
比如展示service=db
5分钟内的内存可用量:
promQL: node_memory_MemAvailable{service="db"}[5m]
---
element value
node_memory_MemAvailable{instance="192.168.1.3:9100",job="node_exporter",service="db"} 16489734144 @1562826039.824
16489734144 @1562826039.824
16489394176 @1562826054.824
16487358464 @1562826069.825
16484458496 @1562826084.824
...
可选择的时间单位如下:
s
: secondsm
: minutesh
: hoursd
: daysw
: weeksy
: years假设当前时间为12:00pm
, 如果想看前一天12.00pm
的时间序列,可以采用offset
。写法如下:
promQL: node_memory_MemAvailable{service="db"} offset 1d
当然如果想看过去某个时间段内的时间序列也是ok的:
promQL: node_memory_MemAvailable{service="db"}[5m] offset 1d
promQL 支持以下二元运算:
运算符:+
, -
, *
, /
, %
, ^
分别对应加法,减法,乘法,除法,取余,指数运算
可用于scalar/scalar
, vector/scalar
, vector/vector
scalar/scalar:
promQL: 2 * 2
vector/scalar:
node_memory_MemFree_bytes/(1024*1024)
将内存单位换算为MB
vector/vector:
promQL: node_filesystem_size{instance="192.168.1.1:9100",device="/dev/sda1"} - node_filesystem_free{instance="192.168.1.1:9100",device="/dev/sda1"}
计算某块磁盘的使用量。
运算符:==
, !=
, >
, <
, >=
, <=
可用于scalar/scalar
, vector/scalar
, vector/vector
scalar/scalar:
promQL: 1 >= bool 2
---
element value
scalar 0
0
表示 False
, 1
表示 True
。
vector/scalar:
promQL: rate(http_requests_total{instance='192.168.1.1:9100'}[5m]) >= bool 100
---
element value
{instance='192.168.1.1',job="node_exporter"} 0
统计最近5分钟内,并发请求数是否大于100。
如果不带
bool
修饰符,则返回为5分钟内实际并发数(如果满足并发数大于100)或者空(并发数小于100)
vector/vector:
(node_memory_bytes_total - node_memory_free_bytes_total) / node_memory_bytes_total * 100 > bool 95
判断当前内存使用率是否超过95%
只能用于 instant vector 之间。
运算符:
and
(交集)or
(并集)unless
(补集)vector1 and vector2
会产生一个由vector1
的元素组成的新的向量。该向量包含vector1
中完全匹配vector2
中的元素组成。
vector1 or vector2
会产生一个新的向量,该向量包含vector1
中所有的样本数据,以及vector2
中没有与vector1
匹配到的样本数据。
vector1 unless vector2
会产生一个新的向量,新向量中的元素由vector1
中没有与vector2
匹配的元素组成。
暂时没想到例子,待补充。
作用于vector1/vector2
用于匹配出现在vector2
的vector1
中的时间序列。用伪代码可这样表示:
def match(vector1, vector2):
new_vector = set()
for item in vector1:
if item in vector2:
new_vector.add(item)
return new_vector
有两种匹配行为:一对一,一对多/多对一
这里参考官网示例来加以说明,假设有如下时间序列:
method_code:http_errors:rate5m{method="get", code="500"} 24
method_code:http_errors:rate5m{method="get", code="404"} 30
method_code:http_errors:rate5m{method="put", code="501"} 3
method_code:http_errors:rate5m{method="post", code="500"} 6
method_code:http_errors:rate5m{method="post", code="404"} 21
method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="del"} 34
method:http_requests:rate5m{method="post"} 120
one-to-one 可认为左右集合中的条目数量相等。
one-to-many 可认为左侧集合中一个条目对应右侧多个条目
many-to-one 同理
one-to-one:
语法:
or
ignoring(
说明:
两边的时间序列根据相同的标签来进行匹配。可以通过ignoring
来忽略某些标签。on
则用于将匹配条件限定在特定标签中。
promQL: method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
---
element value
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120
该表达式会返回在过去5分钟内,HTTP请求状态码为500的在所有请求中的比例。如果没有使用ignoring(code),操作符两边表达式返回的瞬时向量中将找不到任何一个标签完全相同的匹配项。
在上面例子中,左侧表达式返回的时间序列集为:
promQL: method_code:http_errors:rate5m{code="500"}
---
element value
method_code:http_errors:rate5m{method="get", code="500"} 24
method_code:http_errors:rate5m{method="post", code="500"} 6
由于使用了ignore
忽略了对code
标签的匹配,所以从右侧表达式匹配到的时间序列为:
method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="post"} 120
然后对结果集做/
除法操作,得到上面结果。
one-to-many/many-to-one:
多对一和一对多两种匹配模式指的是“一”侧的每一个向量元素可以与"多"侧的多个元素匹配的情况。在这种情况下,必须使用group修饰符:group_left或者group_right来确定哪一个向量具有更高的基数(充当“多”的角色)。
语法如下:
ignoring() group_left()
ignoring() group_right()
on() group_left()
on() group_right()
eg:
promQL: method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
---
element value
{method="get", code="500"} 0.04 // 24 / 600
{method="get", code="404"} 0.05 // 30 / 600
{method="post", code="500"} 0.05 // 6 / 120
{method="post", code="404"} 0.175 // 21 / 120
分析:
左侧表达式对应集合:
method_code:http_errors:rate5m{method="get", code="500"} 24
method_code:http_errors:rate5m{method="get", code="404"} 30
method_code:http_errors:rate5m{method="put", code="501"} 3
method_code:http_errors:rate5m{method="post", code="500"} 6
method_code:http_errors:rate5m{method="post", code="404"} 21
右侧表达式对应集合:
method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="del"} 34
method:http_requests:rate5m{method="post"} 120
由于使用了group_left
, 因此左侧集合代表多
的一侧。
由于右侧集合中,没有code
标签,所以需要通过ignore
来忽略。
聚合操作,顾名思义就是将多组序列聚合为一组。通过promQL
的内置函数来实现。
value
进行计数sum:
统计机器上存储容量
promQL: sum(node_filesystem_size{instance=~"192.168.1.1.+",device=~"/dev/sd.*"} )
---
element value
{} 520794112
to be continue
https://yunlzheng.gitbook.io/prometheus-book/parti-prometheus-ji-chu/promql/prometheus-aggr-ops
https://prometheus.io/docs/prometheus/latest/querying/operators/