PromQL的四种数据类型
-
瞬时向量(Instant vector):一组时间序列,每个时间序列包含单个样本,它们共享相同的时间戳。也就是说,表达式的返回值中只会包含该时间序列中最新的一个样本值。
-
区间向量(Range vector):一组时间序列,每个时间序列包含一段时间范围内的样本数据。
-
标量(Scalar):一个浮点型的数据值,没有时序。可以写成[-](digits)[.(digits)]的形式。需要注意的是,使用表达式count(http_requests_total)返回的数据类型依然是瞬时向量,用户可以通过内置函数scalar()将单个瞬时向量转换为标量。
-
字符串(String):一个简单的字符串值。字符串可以用单引号('')、双引号("")或反引号(``)来指定。
时间序列(向量)
按照时间顺序记录系统、设备状态变化的数据,每个数据成为一个样本。
-
数据采集以特定的时间周期进行,因而,随着时间流逝,将这些样本数据记录下来,将生成一个离散的样本数据序列。
-
该序列也称为向量(Vector),以时间轴为横坐标、序列为纵坐标,这些数据点连接起来就会形成一个矩阵。
时间序列的构成
每条时间序列(Time Series)是通过指标名称(Metrics name)和一组标签集(Label set)来命名的。
如果time相同,但是指标名称或者标签集不同,那么时间序列也不同。
如果某些时间没有数据,那么距镇上就没有时间序列填充了。
样本构成
矩阵中每一个点都可称为一个样本(Sample),样本主要由3方面构成。
-
指标(Metrics):包括指标名称(Metrics name)和一组标签集(Label set)名称,如request_total{path="/status",method="GET"}。
-
时间戳(TimeStamp):这个值默认精确到毫秒。
-
样本值(Value):这个值默认使用Float64浮点类型。
notice:
n1.过去数据
Prometheus会定期为所有系列收集新数据点。从Prometheus基于时间序列的基本特性来看,由于图4-1所示的矩阵的左侧通常为过去的数据,这些数据一般是只读(不会变更)的,故当前的数据才会在时间轴的右端垂直性写入。
2.到底什么是时间序列数据库
按照一定的时间间隔产生一个个数据点,而这些数据点按照时间戳和值的生成顺序存放,这样就构成了时间序列矩阵,以这种结构存储数据的库也就称之为时间序列数据库。
3.什么是时间序列
上文说到每条时间序列(Time Series)是通过指标名称(Metrics name)和一组标签集(Label set)来命名的,而这些其实说的都是序列,而不是时间,只有纵坐标序列,横坐标时间才能共同构成一个时间序列。
文中举的例子也同样是这个意思:
在某一时刻t0,request_total{path="/status",method="GET"}和request_total{path="/",method="GET"}就是两个不同的数据点,errors_total{path="/status",method="POST"}和errors_total{path="/health",method="GET"}也是两个不同的数据点,也就是说在这个时刻可能至少产生了4条数据。
这个例子在最开始就限定了条件,某一时刻。所以<font color=red>指标,标签集和时间点共同组成一个时间序列</font>。
指标
时间序列的指标(Metrics)存储格式为key-value。
image.pnghttp_request_total{status="200",method="GET"}@1434417560938=>94355为例,在Key-Value关系中,94355作为Value(也就是样本值Sample Value),前面的http_request_total{status="200",method="GET"}@1434417560938一律作为Key。
key的组成:
Metric Name:指标名(例子中的http_request_total)
Label:标签(例子中的{status="200",method="GET"})
Timestamp:时间戳(例子中的@1434417560938)
Prometheus Metrics两种表现形式:
image.png-
<\Metric Name>{<Label name>=<label value>, ...}
-
其中,Metric Name就是指标名称,反映监控样本的含义
-
指标名称只能由ASCII字符、数字、下划线以及冒号组成并必须符合正则表达式
[a-zA-Z_:][a-zA-Z0-9_:]
-
冒号用来表示用户自定义的记录规则。不能在Exporter中或监控对象直接暴露的指标中使用冒号来定义指标名称。
-
标签反映了当前样本的多种特征维度。通过这些维度,Prometheus可以对样本数据进行过滤、聚合、统计等操作,从而产生新的计算后的一条时间序列。
-
-
{_name_=metrics,<label name>=<label value>, ...}
- 这种方式是Prometheus内部的表现形式,是系统保留的关键字,官方推荐只能在系统内部使用。在Prometheus的底层实现中,指标名称实际上是以_name=<metric name>的形式保存在数据库中的;_name是特定的标签,代表了Metric Name。标签的值则可以包含任何Unicode编码的字符。
补充:
1.在Prometheus的世界里面,所有的数值都是64 bit的。每条时间序列里面记录的就是64 bit Timestamp(时间戳)和64 bit的Sample Value(采样值)。
2.指标名称和标签的组合代表了一条时间序列上的数据。不同的指标名称自然不是同一类的指标,但是相同的指标名称如果携带不同的标签,也代表了不同类的指标。比如下面的例子就是5条不同的时间序列。
·http_requests_total{status="200",method="POST"}
·http_requests_total{status="200",method="GET"}
·http_requests_total{status="404",method="GET"}
·http_requests_total
·http_requests_total{}
需要注意的是:
1)在没有标签的时候,http_requests_total等同于http_requests_total{},表达式会返回指标名称为http_requests_total的所有时间序列。后者中的花括号{}可以附加一组或者多组标签,从而进一步过滤时间序列。
2)所有的PromQL表达式都必须至少包含一个指标名称(例如http_request_total),或者一个<font color=red>不会匹配到空字符串</font>的标签过滤器(例如{status="200"}是正确的,但是{status=""就不行})。因此{status="200"}{quantile="1"}这样的表达式也是合法的。
PromQL中的4大选择器
匹配器(Matcher)
匹配器是作用于标签上的,标签匹配器可以对时间序列进行过滤,Prometheus支持完全匹配和正则匹配两种模式。
完全匹配
1.相等匹配器(=)
相等匹配器(Equality Matcher),用于选择与提供的字符串完全相同的标签。下面介绍的例子中就会使用相等匹配器按照条件进行一系列过滤。
image.png对于不存在的标签,比如demo标签不存在,那么go_gc_duration_seconds_count和go_gc_duration_seconds_count{demo=""}效果其实是一样的。
2.不相等匹配器(!=)
不相等匹配器(Negative Equality Matcher),用于选择与提供的字符串不相同的标签。它和相等匹配器是完全相反的。举个例子,如果想要查看job并不是HelloWorld的HTTP请求总数,可以使用如下不相等匹配器。
正则表达式
正则表达式匹配器(=~)
正则表达式匹配器(Regular Expression Matcher),用于选择与提供的字符串进行正则运算后所得结果相匹配的标签。Prometheus的正则运算是强指定的,比如正则表达式a只会匹配到字符串a,而并不会匹配到ab或者ba或者abc。如果你不想使用这样的强指定功能,可以在正则表达式的前面或者后面加上“.*”。比如下面的例子表示job是所有以Hello开头的HTTP请求总数。
image.pnghttp_requests_total直接等效于{name_="http_requests_total"},后者也可以使用和前者一样的4种匹配器(=,!=,=,!)。比如下面的案例可以表示所有以Hello开头的指标。
{_name__=~"Hello.*"}
如果想要查看job是以Hello开头的,且在生产(prod)、测试(test)、预发布(pre)等环境下响应结果不是200的HTTP请求总数,可以使用这样的方式进行查询。
http_requests_total{job="Hello.*",env="prod|test|pre",code!="200"}
正则表达式相反匹配器(!~)
正则表达式相反匹配器(Negative Regular Expression Matcher),用于选择与提供的字符串进行正则运算后所得结果不匹配的标签。因为PromQL的正则表达式基于RE2的语法,但是RE2不支持向前不匹配表达式,所以!~的出现是作为一种替代方案,以实现基于正则表达式排除指定标签值的功能。在一个选择器当中,可以针对同一个标签来使用多个匹配器。比如下面的例子,可以实现查找job名是node且安装在/prometheus目录下,但是并不在/prometheus/user目录下的所有文件系统并确定其大小。
node_filesystem_size_bytes{job="node",mountpoint=~"/prometheus/.*", mountpoint!~
"/prometheus/user/.*"}
PromQL采用的是RE2[1]引擎,支持正则表达式。RE2来源于Go语言,它被设计为一种线性时间的模式,非常适合用于PromQL这种时间序列的方式。但是就像我们前文描述的RE2那样,其不支持向前不匹配表达式(向前断言),也不支持反向引用,同时还缺失很多高级特性。
PromQL非法总结
由于所有的PromQL表达式必须至少包含一个指标名称,或者至少有一个不会匹配到空字符串的标签过滤器,因此结合Prometheus官方文档,可以梳理出如下非法示例。
{job=~".*"} # 非法! .*表示任意一个字符,这就包括空字符串,且还没有指标名称
{job=""} # 非法!
{job!=""} # 非法!
相反,如下表达式是合法的。
{job=~".+"} # 合法!.+表示至少一个字符
{job=~".*",method="get"} # 合法!.*表示任意一个字符
{job="",method="post"} # 合法!存在一个非空匹配
{job=~".+",method="post"} # 合法!存在一个非空匹配
PromQL使用小技巧
1.多个表达式之间使用“|”进行分割
http_requests_total{job="HelloWorld",status=~"500|501|502|503|504|505|506|507|509|510"}
2.查询5开头的状态码,比如5xx 500,501
http_requests_total{job="HelloWorld",status=~"5xx"}
3.匹配不以5开头的
http_requests_total{status!~"5.."}
瞬时向量选择器(Instant Vector Selector)
瞬时向量选择器用于返回在指定时间戳之前查询到的最新样本的瞬时向量,也就是包含0个或者多个时间序列的列表。
在最简单的形式中,可以仅指定指标的名称,如http_requests_total,这将生成包含此指标名称的所有时间序列的元素的瞬时向量。我们可以通过在大括号{}中添加一组匹配的标签来进一步过滤这些时间序列,如http_requests_total{job="helloWorld",group="middleware"}。
区间向量选择器(Range Vector Selector)
区间向量选择器返回一组时间序列,每个时间序列包含一段时间范围内的样本数据。和瞬时向量选择器不同的是,它从当前时间向前选择了一定时间范围的样本。区间向量选择器主要在选择器末尾的方括号[]中,通过时间范围选择器进行定义,以指定每个返回的区间向量样本值中提取多长的时间范围。例如,下面的例子可以表示最近5分钟内的所有HTTP请求的样本数据,其中[5m]将瞬时向量选择器转变为区间向量选择器。
http_request_total{}[5m] #范围选择器必须紧跟在{}后
时间范围必须是整数
时间范围通过整数来表示,可以使用以下单位之一:秒(s)、分钟(m)、小时(h)、天(d)、周(w)、年(y)。需要强调的是,必须用整数来表示时间,比如38 m是正确的,但是2 h 15 m和1.5 h都是错误的。这里的y是忽略闰年的,永远是60×60×24×365秒。
Prometheus不是绝对精准的
因为区间向量选择器它返回的是一定范围内所有的样本数据,虽然刮擦时间是相同的,但是多个时间序列的时间戳往往并不会对齐。
image.png虽然可以控制采集的频率,但是假如有成百上千的target,每次5秒的刮擦都会导致这些target在不同的位置被处理,所以时间序列一定会存在略微不同的时间点(只是略微不同)。因此会有人说,Prometheus虽然在趋势上是准确的,但是并不是绝对精准的。但是,这在实际生产中并不是非常重要,因为Prometheus等指标监控本身的定位就不像Log监控那样精准,而是趋势准确。
区间向量选择器往往和速率类的函数rate一起使用
比如子查询,以1次/分钟的速率采集关于http_requests_total指标在过去30分钟内的数据,然后返回这30分钟内距离当前时间最近的5分钟内的采集结果,如下所示。
rate(http_requests_total[5m])[30m:1m]
注意,使用不必要的子查询或者不停地嵌套子查询并不是好的PromQL风格。
一个区间向量表达式不能直接展示在Graph中,但是可以展示在Console视图中
由于范围向量选择器的返回的是范围向量型数据,它不能用于表达式浏览器中图形绘制功能,否则,表达式浏览器会返回"Error executing query: invalid expressiontype "range vector" for range query, must be Scalar or instant Vector"一类的错误
但是结合rate函数使用,返回的就不是范围向量型数据,可以显示Graph中
image.png偏移量修改器(Offset)
偏移量修改器可以让瞬时向量选择器和区间向量选择器发生偏移,它允许获取查询计算时间并在每个选择器的基础上将其向前推移。<font color=red>即可以按照某个时间戳向前推移查询</font>。
瞬时向量选择器和区间向量选择器都可获取当前时间基准下的样本数据,如果我们要获取查询计算时间前5分钟的HTTP请求情况,可以使用下面这样的方式。
http_request_total{} offset 5m
偏移向量修改器的关键字必须紧跟在选择器{}后面,如下的表达式分别是正确和错误的示例。
sum(http_requests_total{method="GET"} offset 5m) // 正确
sum(http_requests_total{method="GET"}) offset 5m // 非法
该操作同样适用于区间向量选择器,比如下这个例子,其以指标http_requests_total 5分钟前的时间点为起始高,返回5分钟之内的HTTP请求量的增长速率。
rate(http_requests_total[5m] offset 5m)
<font color=red>偏移向量修改器通过调整计算时间一样可以看到一些历史数据,但是这种方式一般只对调试单条语句的历史数据有帮助。随着新数据的到来,历史数据也会不断发生变化,所以建议在Grafana中直接看历史数据的变化趋势</font>。
网友评论