开发者学堂课程【3天吃透 Prometheus:PromQL 进阶】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/1244/detail/18448
PromQL 进阶
5. Histogram quantile 的函数
这个函数允许自己我们指一个分位数,这个分位数就是位于0到1之间的,比如定义刚才所说0.5,即表示50分位数,这整个区间内的50分位是谁?跟上这个basename,就是我们自己指定的标签名,加上bucket,它就能通过函数粗略的估算出我们的所有采样当中大概正好中位数名的数是谁。我第一次的描述可能不是特别精确,我再重复一遍。正常情况下,我们所谓的取中位数指的就是在你的整个样本取值中间我们虽然认为我们的取值是0-100,但我们同学不可能正好0分分布到0分到100分之间,很有可能你是30分到99分之间。我想知道30分到99分之间正好中间中位数是谁?他要根据你的范围来做计算,但这种计算只能是一种线性计算,因为我们没有存真正的样本数都是多少,这种计算一定会有偏差。现在大家应该容易理解。很有可能他是这样算的,举个例子,你比如小于等于我现在让你取50分的,现在在60分上的同学有几个?比如同学有几个,落在小于45的有几个,那就意味着45-60之间我们是不是可以算他一个大约数?根据这几个数字我们评估,比如我现在这个范围内有三个同学,而45-60之间一共有15个数字,于是我就取一个最中间数,认为这是他的,就正常计算把3个均匀的分布到这个范围内,差不多最中间数如果是4个,也只能是按照4个,把这4个均匀的分布到这个范围上,找一个中间数,再不然找中间那俩值再做个平均,什么类似这种方式来进行估算。所以它一定得到的不是精确值,只能是估算它的结果。但如果我们要非要得到精确结果怎么办?没办法,histogram这种直方图本身就不支持,因为它本身就是一种线性推算出来,这种偏差一定是存在的。这个图它大体上就描述这种偏差。
正常红线表示正常的样本分布应该具有的样子,因为这是正态分布,差不多正常情况下,这种统计都是满足正态分布的。但是蓝线大概表示出来。比如这是分位点,这是1/4分位点,这是四分位点,这是中位数,3/4分位点,这是百分位点。很显然,它估算时,类似于以这种区间的方式来估算,我们的估算值应该是落在直线上,很有可能落在直线上,或者是落在蓝色的画的不规则线上,跟我的红线一定是有偏离,再重复一遍,因为它是个估算,它不是真实的样本值。你的样本值没有被记录。我们要想得到精确样本值怎么办?只有一个办法。我们使用另外一个,叫做summary的类型,因为summary是客户端,直接算好分位数,直接上报服务端直接记,不用计算,因为我已经记好,这几个分位数分别是什么?比如在我们的采样区间内,50分位数是几?75分位数是几?但你想再算60分位数怎么办?对不起,我上报的只有25分位数、50分位数、75分位数和百分位数。没有别的,你就用不到。所以summer的好处是能得到固定分位点上的精确值,但不能去任意估算。这是summer的特点。因为我们说过summer是报什么值的,报什么数的,直接指明我这个分位点。每一个桶里边,你可以认为它不是桶。时间序列记录了每一个分位点上对应的样本,到底是什么?比较常见的是summary直接上报零、零点二五、零点七、五和一几个分位点。我们说过这叫中位数1/4分位数,这是四分三分位数,百分位数也有这样几个点的,比如我想知道百分之50%以下的,或者为0.5以下的,0.9以下的,0.99以下的这几个分位点,什么意思?分位数代表你的采样值有50%大概是什么样?有90%大概是什么样?99%大概什么样?什么意思?仍然以刚才我们同学的例子为例来进行说明。假设我们某一次采样的结果当中,在这某采样的结果当中,我们认为60分位数,或者我们有一个叫做中位数是75,我们认为什么意思?班里边同学有一半小于75,少考的分数是低于75,另外一半是多于75,同样,我们认为叫99分位数99%是70。可以用什么?班里边的同学,99%的同学都低于70分,只有1%的同学是高于70分,这叫统计分布。
6.统计分布在监控中的作用
我们在监控中有什么作用?很简单,比如我们现在记录的是什么?是我们的HTTP服务器,注意抓的指标是HTTP服务器的请求响应时长,叫response_time_seconds。
随便举个例子,就这样一个指标叫http的起响应时长,以秒为计算,开始给它记分位数,想知道我们的网站大概请求时长多少?你要在这用gage来记录会有什么结果?用Gage来记录,那就意思每一次采样它都记下一个所谓的响应时长,这叫Gage。因为我知道响应时长它不可能是个计数器,不同请求,他们的数据可大可小。所以我们要使用gage计数有什么特点?想知道平均时长,我们到底请求响应时长大概位于什么样的区间,有什么样特性。
于是我们记录下所有的请求,或者叫我们记录下每一个采样点的请求的具体的响应时长。到最后,我评估一下大家大体上请求时长都有多少于是我取平均数,比如平均数为1.3秒。但是我们说过平均值是会坑人。可能有50%的请求大概都在1.2秒,但是也有个别请求,可能请响应结果为10秒钟。它无法精确地反映出来我们的真正网站的节目响应情况,因此,我们如果把它使用histogram来进行技术会有什么特点?我也可以查出来说99%的请求大概它的时长在是什么?比如我们求取了一个99分位数为1.1,你可以理解什么意思?99%的请求响应时长都不超过1.1秒,我认为网站是正常,1%的异常我们认为是可以接受的。但你使用平均数,你无法知道它到底百分之几有多少。平均值是1.3,但很有可能有很多请求是0.001秒钟完成,但只有50%,大概就在0.001秒之内就能完成。而另外50%很有可能是在5或者在10秒以上完成的,你说平均1.3,你认为这合理吗?你的网站服务,正常吗?这不是一个大坑吗?所以我们说很多时候平均数是无法精确描述我们的真正某一个测量度的特征的,这就是为什么我们要使用分位数的原因,其实对我们将来在我们的网站的应用的监控的响应时长这方面用的最多,基本上分位数都是用在这个位置的,包括比如你在磁盘存数据,多长时间能存完磁盘,请求响应时长,网站请求响应时长等,这些其实都是重要的指标,数据应用监控当中,响应时间是一个特别关键的指标,这也是为什么我这里又利用那么多时间来给大家再次讲解概念的原因,相关知识一定要理解清楚。当然要想使用好分位数确实不是件容易的事。我们回头继续说promql,我们前面已经讲到promql的基础的表达式。
二、prometheus 的聚合函数
聚合计算,我们讲过大多数指标我们采集后,不用也不可能去一个一个查看它的样本值,这对我们而言不关键,更重要的是,假如我们的web服务器跑20个实例,因为我们现在网站访问量很大,跑20个实例,这些实例上统计的响应时长也不可能主节点每一个节点的查看。所以多数情况下很有可能会把多个target上的同一个指标合并起来统一进行计算,比如求解它的平均值之类的来进行,所以我们说一般来讲,单个指标的价值不大,监控场景中往往需要联合并可视化一组指标这概念,这一组指标很有可能是来自于不同target的同一指标。也有可能是位于某一个对应的指标名称下的多个维度,我可以给它聚合起来进行计算,这种联合机制所谓叫聚合操作。
比如像计数、求和平均值、分位数、标准差及方差等统计函数,把这些函数应用于时间序列的样本之上,我们让它生成具有统计学意义的结果,所以我们对于做监控的同学来说,了解统计学知识有时候还是很有必要的,当然也不一定非要去懂,回顾中学的什么叫标准差,什么叫方差也可以,接着我们也可以对查询结果事先按照某种分类机制进行分组,叫groupby。各位在学MySQL的时候应该学过,我们班里边所有同学,你可以求平均,比如这某一次考试,求所有同学的平均得分,也可以干什么?我们班里边一共分4组,求每一个组的平均得分,这就是分组统计,或者是每一个组各自的有多少个同学等。这种就叫分组统计,分组其中包括分组统计数、分组求平均值、分组求和等,这个叫计数,可能更合适一点。
聚合操作其实就是由prometheus内置的聚合函数来进行计算。它可以针对一组值进行计算并返回注意单个值或少量几个值。既然叫聚合,不能越聚越多,它其实是一种折叠的效果,它应该起到一种叫做折叠的效果。我们要减少数量的prometheus内置提供了11个聚合函数,我们也可以把它称为叫做聚合运算符,但是各位要记得的是,这有个特别要点,重要的要点,这些运算符仅支持应用于单个即时向量的元素。意思是这些计算的函数是不支持用在范围向量之上,其返回值也是具有少量元素的新向量,甚至是只有一个元素的,只有一个元素不一定叫标量,因为它可能得到的结果刚好有只有一个元素,但有些值是标量,因为它本身不具有向量的意义,它称为叫标量。这些聚合运算符既可以基于向量表达式返回结果中的时间序列的所有标签维度进行分组聚合,也可以仅基于指定标签维度的分组。再分组聚合。什么意思?比如这里有个是序列,有指标名,它有三个标签。我可以只针对标签1做聚合,也可以针对标签1标签2做分组聚合。也可以把所有的标签拿过来做分组聚合。所有标签都拿过就意味着只有这一个值,这一个序列自己能聚合。话回来即多个target上这个序列可能就不止一个,这是prometheus的聚合函数。我们来学习这些聚合函数都是什么以及它该怎么用。
1.聚合表达式
promql中的聚合操作语法是以下两种格式,其中任何一个都行。我们来看怎么用,第一,使用聚合,聚合函数或者叫聚合操作符([parameter,])[without│by(label list>)], 我们要使用的聚合函数比如叫avg,你要使用的是avg,这表示我要在这写avg,这叫向量表达式,就表示你要打算对哪个向量表达式。我们要知道过滤就和我们前面所说的时间序列过滤器,针对过滤器本身做聚合,怎么聚?可以整个聚合,也可以指定的标签聚合。其中without叫排除法,意思是要把指标排完后,排除以后把剩下的指标为标准进行聚合。也可以使用by,这表示什么?包含法就以我指定的指标进行聚合,反过来的不聚合。
下面这种表达格式跟上面一样:[without│by(label list>)] ([parameter,]),只是下面把without写前面。意思without和by既可以直接写在聚合函数后面,也可以写在小括号括起来的聚合表达式的后面。这就所谓的聚合操作的基本的语法格式。
我们聚合时可以先分组后聚合,叫分组聚合。所以without和by分组与否的特别重要标准,它俩不能同时使用。因without表示排除法,表示把某些标签排除以后把剩下的标签用来做聚合。而by表示以仅以指定的标签做聚合。事实上,每一个函数只有功能上的区别,在表达格式上,在使用的语法格式上没有区别。我们举个例子就知道。我把我的prometheus再次启动,user/local/Prometheus,我们让它运行。
现在我们去打开站点,我们打开表达式浏览器,看里边有哪些指标可以被我们使用。当然更重要的是,我们要想聚合,要看怎么聚合。要求和我们说过,一般要用在gauge类型的指标上还记得求平均值也应该是gauge类型的指标,一定要记得聚合函数只能用于及时向量而且还不能用于范围向量,因而我们在这里可用指标。这是一个9090,大家知道这是prometheuse自己的指标。9090是prometheus进程自己的监听的端口,我们也可以使用9100,这是node的端口,1.1上好像没启用,我看意义上应该node exporter所输入的指标。我们找一个Gauge类型的指标而后就可以对它做聚合。这是最容易理解的,还回到9090里。我们就直接搜索,在查找一个gauge,这里它的标签太少,我们要找两个以上标签的。各位看
Node file system available bytes,叫节点文件系统的可用空间,以字节为单位,filesystems space available to non-root user
Bytes,底下定义这是sdae。设备sdae文件系统是什么?挂载点是什么?大概还剩这么多空间,这是第二个,这是第三个。能看懂这意思,所以我们就查这个指标叫Node file system available bytes。复制后我在这里先把它过滤出,我们看它的所有指标。
各位注意这里的区别,首先,这有节点123各自每一个节点上的统计,所以instance代表的节点,如果我们要只统计单一节点,instance就必须要过滤,我们要以它为分组进行聚合,分别统计每一个节点上的设备,同样的逻辑,如果我们考虑我们计算出来所有节点上的所有空闲文件系统的剩余空间之和是多大?
很显然,我所有是不是都可以不过滤?我们就直接使用sum,叫sum求和就可以,后面使用括号括起,我们格式这叫操作符,要使用括号括起来,这里还有个参数。有些聚合函数要求有参数,但SUM不要求。我们既然没有指定任何聚合分组的标准,那意味着事实上这里就表示把所有节点上的所有磁盘设备的空闲空间全部加起就取得一个结果。
假如我们要分节点,以节点每一个节点上空闲空间多少,我们就使用by(instance)(Node_filesystem_avail_bytes)就可,sum对它进行求和。把by写前面写后边都可以,by对应的叫做instance标签execute,by (instance),这也需要个括号,这就是所谓的叫node01上的所有的空闲空间之和,这容易理解。很显然,我们要根据别的标准进行聚合。再比如我只看看所有节点上的sdae的空间的大小,很显然我们就基于device进行聚合就可以,就这么简单,看你自己的需要,我们也可以根据挂载点进行聚合,amount每一个挂载点,比如我们这就分每个节点上的根还剩多少空间,每个节点上的boat还剩多少空间就可以,甚至于对其他的挂载点,你像这run,我们不聚合,你可以写得更复杂一点。比如在这我们先去过滤它的mountpoint的值,要么是boot,要么是跟,我们先取出来,只取出来这样对应的指标序列。
对这些指标序列,我再分进行聚合,选sum先聚合就可以。而聚合时,我们还可以对各个挂载点分别进行聚合。意思就是我算所有节点上boot的空间有多大,所有点根的共同性规定多大,即the by-的问题,你by mount point,就根据我们的mountpoint本身进行聚合,也就意味着每一节上的所有的boot剩余空间是这么大,容易理解,只要各位知道这样怎么用,我就不一一去解释每一个函数的意义,就没不用一一去演示,因为它的格式都是一样。当然我一直用的是by,你也可以使用without等,这根据需要,根据自己需要的场景。
于是我们来看后续的这些函数都有什么功能,它们分别都是什么。
2.11个聚合函数
其实大多数都很容易理解,而且各位都应该都使用过。像刚才我一直使用sum求和,avg平均值,count就是计数,这三个应该最容易理解,还有两个更容易理解的最大值和最小值,其他几个我们需要简单解释一下。比如这个叫标准差,标准差是描述数据波动大小的或者称为叫波动程度的,叫做标准差。对样本直求方差,它是求取标准差过程中的一个中间状态,它们的意义比较相近,方差和标准差的统计学的意义比较相近,但他们适用场景会有所区别。接着topk,这是我们做排序的时候用到的最多。
比如像刚才我们得到的所谓的过滤出后,我们期望得到空闲空间量最大的磁盘空间是谁,最大的设备是谁,就可以使用topk,还可以分组进行聚合,每一个节点上,它可能有很多个磁盘挂载点。我们取出来空闲空间量最大的各自的前两个,这不就是topk吗?而bottomk则是最小的几个,topk刚刚说过叫由大而小,叫逆序。排完序后取指定的数量,上面是大,下面是小,而bottomk上面是小,下面是大,是顺序排序,依然是求最上面两个,所以我们说topk是取得最大指定的数量,而bottomk是取的最小的指定数量。bottomk和topk到底是返回几个?这两个都是需要指参数parameter,现在就有意义。比如返回前10个,返回前5个,这个数字的意义。
下面quantile,叫分位数,用于评估数据的分布状态的,该函数会返回分组内指定的分位数的值,注意这给我们刚才讲的Histoquantile或者叫histogramquantile不同histogramquantile函数只适用于叫histo数据类型,而这适用的是什么?应该是一个gag类型的数据或者是一个counter类型的数据。所以它本来就是样本值。它从各样本值里边找一个中位数,找一个1/4分位数,找3/4分位数。
这跟我们刚才讲的histogramquantile是有所不同的。histogramquantile是不用自己的样本值,直接保留的就是桶存储桶和计数,summary直接保存分位数,用不着样本值。而如果我们需要用样本值的时候,你可能使用gage,使用counter计数,但偶尔我们需要在这样的样本值上去求得这整个样本的分布状态。这个时候我们就要使用quantile来定义。所以它是两回事。再重复一遍,这是为什么他俩名字都不一样。后面count_values,这个指的是对分组内的时间序列的样本值进行数量统计,它跟count是有很相像的。但是count_values有它的特殊作用,而且count_values是接受参数的。它跟bottomk跟topk一样,你可以指定我只对内范围内的多少个矩形计数或多大范围进行计数,类似于这种,再重复一遍,count_values是用于在时间序列中的每一个样本值出现的次数进行计数或者精确地讲比如counter,我这里指定一个时间序列,它算出里一共有100个数,100个样本,就一共有100个样本,而count_values指的是它在里边它认为你其中这100个样本里,3出现6次,7出现8次,对每一个样本值进行分别计数,这叫count values,因此count_values会输出很多个时间序列它的返回值,每一个值都是一个时间序列。其他的应该就没有什么特别需要再说明。各位只需要知道比较复杂的函数只有后4个,就是topkey,bottomk,quantile和countvalues。因为它们4个是需要接受参数,前几个一个逆序,一个顺序。这个表示到底是参数,应该是你打算得到哪个分位值。比如五十分位值,九十九分位值,你要指定是哪一个分位值。而count values可以不用给它传参数,但我们要传参数就意味着你要指定哪个样本值,大概就是这样,这是它的聚合函数。