开发者学堂课程【3天吃透 Prometheus:Prometheus 进阶】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/1244/detail/18454
PromQL 进阶
内容介绍:
一、前期回顾
二、prometheus 的聚合函数
三、二元运算符
四、promQL 的解析过程
一、前期回顾
1. Prometheus 数据的采集
我们上节课讲到Prometheus要想能够实现数据的采集,在前期它大体在整个指标抓取过程当中,它有叫做指标抓取的生命周期,第一,我们首先得能发现服务,所以这里我们要有一个叫服务发现的过程,当然它的发现的主要目标是用于发现target。
我们只要有target,这Prometheus监控的特点,它在target之上基于所谓的叫做metrics。大家知道就要基于所谓的叫指标路径,就能实现所有的在target之上所有的指标的抓取。因而我们不必要告诉他需要去抓取那些指标,只需要告诉他target在何处,而后http协议或者https协议就是Prometheus server在指标抓取时所使用,叫scheme。它借助于这样的协议到对应的发现的端点之上,端点就是ip加端口,而后复制,加上magic的pass,就可以实现指标抓取。但是发现完成之后,在指标抓取之前,还有一些任务要做。
比如第一我们要配置,一定要记得配置,比如对特定的target,我们平均抓取的时间间隔是什么等,都可以在此处进行定义,所以这个过程我们称为叫配置。
接着我们还有一个项,在真正执行抓取之前,还有一个功能叫做重新打标。其实这是个特别重要的功能,因为我们要借助于重新打标完成,比如某个指标我们不想抓取,或者叫某个target,我们不想抓取,我们就要再重新打标,这一步完成。再不然我们期望能够在target之上去操作target的标签。
我们讲过,比如创建新的标签,使用已有标签的标签值赋予给新标签,或者基于已有标签的名称,而后给它基于前缀或者后缀或者其他组合的方式创建出新标签等都可以再重新打标位置完成。所以我们说重新打标,大体上要做这样几类操作。
第一,我们可以去操作标签值,基于标签值进行匹配以后做操作,这个时候我们可以把值赋予给一个新标签,一般而言是这样。接着,我们还可以实现去操作标签名,甚至还可以做标签的映射。操作标签名的时候,一般而言,我们是实现删除标签。
各位还能记得删除的时是正则表达是能匹配的就删除,或者正则表达式不能匹配的才删除。它有一个排除或者一个保留法,叫keep和drop。匹配标签名时,我们还有一种方式叫标签映射,要记得前面匹配标签值,叫标签值更合适做删除。而对于真正标签名的匹配,大多数我们可能需要做的是叫做标签名称的重新映射或者删除特定标签。所以这里是删除标签,这里是删除指标或者删除target,这里包括叫做标签名重新映射这样来归类。我们也可以在匹配到某个特定标签的标签值以后,认为带有标签的,我们不想监控,我们可以删除target,而后把标签名匹配出我们可以去删除标签,也可以去做标签的重新映射,这叫重新打标。
当然,这里重新打标主要是操作target上的标签,因为这个时候我们还没有抓取任何额外的其他指标,但我们target本身也是一个指标,可以这么理解。等这些步骤完成,我们就可以实现真正的指标抓取。抓取而来的指标它要存储在Prometheus自己本地的t、s、d、b中,所以抓取只要存储。但在存下来之前我们还可以再重新打标一次。但这里的重新打标操作的是该target上,写清楚叫该target上的。所有指标的标签,究竟是哪个指标,我们可以自己指定。我们可以通过标签名之类的方式来进行匹配,或者使用标签名指的就是--name这样的方式来进行定义,因为这样我们都匹配的是指标名。标签名和指标名不同,大家一定要了解。当然,这里的重新打标也可以操作标签值。
通过操作标签值的方式,我们可以修改特定,叫修改。
特定标签的值或附加新标签。同样,在重新打标时,在指标重新打标的时候,我们的这种操作逻辑都相同,只不过它是操作在该target上的所有指标的之上。如果我们对指标自身做操作,要删除指标,不像target既定的,一个target就是一个target,但是对指标而言,一个target上可能会有多个。所以我们对target指标名称的匹配,我们一样要使用一个所谓叫标签。大家还记得标签叫--name来进匹配就行,所以我们匹配出来--name的值,把它给drop。类似于这种格式,事实上就是达到能也能达到删除指标的目的。所以一样的逻辑,它同样是修改,特叫修改指定的标签值或附加型标签。这里要删除的不是target的,而是指标,但要使用叫做要匹配或者要检查,要通过匹配--name标签值完成它,也可以删除标签或者做标签名重新映射,这是我们上期给大家讲到的叫指标抓取的生命周期。
理解生命周期其实对我们来讲特别关键,因为理解了生命周期我们就能理解它在或者我们的Prometheus在很多配置过程当中,它的配置为什么能发挥作用,以及发挥作用在何处。而且我们提及过,由于Prometheus在抓取指标的时候,它是抓取该target所有指标。我们期望能够放弃某个指标,或者添加一些新指标或者修改某个指标,就只能通过重新打标来完成,所以我们说重新打标在Prometheus上是一个特别重要的功能,后面我们就给大家演示怎么做重新打标的。做个简要回顾,我们重新打标有个重要的action操作,其他的我们就不用再给我回顾。action刚才说过主要修改标签值的replace,这个是最重要的。后面我们要去删除指标和保留指标。在使用drop和keep大家还能记得事实上我们替换标签值的还有一个叫hashmode,我们说过我们匹配语言标签,把原标签的值取出来,对它做哈希计算使用。有叫哈希Mod,还有一个叫module,使用MODIO参数指定的哈希算法做哈希计算,计算后的哈希值复制给新标签,做指标映射的时候也有这样几个,labeldrop和labelmap,map是做映射。
很显然,keep则是只保留指定的标签,drop则表示删除匹配的标签。但是这两项我们说过要慎用,因为我们改变指标上的标签值,意味着要创建新标签,而且我们要删除指标上的指定一部分标签,导致该指标上有多个指标序列重名的时候也可能会造成一些混乱的后果。所以大家一定要记得删除指标的标签,一定要慎重,这是action。
2. promQL
再后来我们又给大家讲到promql,我们所谓的叫做Prometheus内置的查询语言,它有一个非常重要的查询过滤表达式。在这里边我们回顾几个特别重要的点。
第一,指标标识。大家一定要记得指标标识我们使用什么叫指标名称?我们称叫metricname,后面跟上花括号,里边跟上label=value,可能这种有多个。各位一定要记得的是在同一个指标名称下,我怎么标示多个不同的时间序列?只要label的组合不同,它就是不同的时间序列。所以我们说在一个指标下却可能存在多个时间序列的。
因为指标名称只用来描述描述被监控对象会叫target的某一个基本属性或叫基本特征。label则是用来给基本特征这上附加多维度特性的或者立体特性的。我们此前曾经说过,比如有一个指标叫做CPUusage,但对于CPUusage而言,我们可能有用户空间的usage,有一内核空间的usage,有nice的usage等。所以我们这里可以添加很多维度。
因而一个指标名称下有可能会存在多个时间序列,但是它并非是便利的。比如我们有3个label,不一定每一个label有所有的取值,或者不一定有所有可能性存在的组合,它通常是有限组合,各位要了解。于是我们要想能够实现指标,要想查询,其实就是对指标序列进行过滤。因此查询指的就叫过滤指标,叫时间序列,过滤时间序列。过滤时间序列怎么过滤?无非就是过滤指标名,过滤标签值,再不然就过滤指标名和标签值的组合。
3.过滤的方法
我们说过的过滤方法有三种。第一,我们可以只指定标签名metricname,这样得到的结果就是只返回该指标下的时间序列,而不是所有指标。这表示一定要明白这个道理,叫只返回只查询,或者叫只查询该指标下的名称下的所有时间序列,第一个要特别重要的关键点。第二,我们也可以只指定标签组合。标签组合这里不是等于什么之类的这种赋值类的组合,而是我们要什么叫做比较表达式,大家一定要理解。因而我们在这个地方,标签的组合,它其实是使用的叫做metric,我们称之为叫做指标匹配,或者叫标签选择器。我们要沿用K8S中的标签选择器。但是在Prometheus当中,我们通常把它称为叫匹配器。匹配器就是对指标值进行过滤,而且我们说过支持4种过滤操作符,等值比较,不等比较,模式匹配,不同模式匹配,我们使用这样几种表达方式。因此我们就可以对于所有指标,是对所有指标名下去查找拥有我们所指定的标签。比如我们指定的叫APP标签,并且它值能够匹配我们这所指定的模式就可以。比如叫做promhtttp的类似这种方式。或者就叫Prom。我们就要使用典型要使用正则表时,这表示以它为前缀的所有的拥有这个标签,而且标签只满足这个条件的所有指标名下的所有事件序列。所以这没限定指标名称,那就意味着他去查找所有指标名称上拥有这个标签,并且它的值能满足匹配条件的。我们还可以指定把metricname和匹配器同时指定的格式,这种格式就意味着只查找指定指标名称下符合,标签选择题的时间序列。所以各位一定要记得这里的过滤时间序列怎么过滤?我们的promql其实就是在基础之上来进行定义的,指标过滤条件表达式,大家应该知道我们实现时间序列过滤时,它的返回值有4种类型,分别叫即时向量,范围向量range vector,第三叫标量,就是一个单一值,一个正常值,还有可能是字符串,所以我们在prometheus上支持4种数据类型不一致,叫数据类型返回值、即时向量、范围向量、标量和字串,我们知道在表达式浏览器当中,我们所能够绘图的只能是及时向量返回值。因为表达式浏览器自身会附加一个可以缩进,可以我们去拉近或者推远的镜头,它本身会带一个所谓的时间范围,因而不能对范围向量进行展示,所以这是返回值的类型,但是有些函数可能只能对范围向量做计算,比如像rate,我们给大家介绍过类似于这种,同时我们讲过指标也有4种类型,指标类型分别是指标类型其实对prometheus的服务端来讲没有任何意义,因为它们是把所有的数据都展平为双精度浮点数据保存的,而对于它主要是在客户端上报时,也就我们的exporter或instrumentation,在接受到指标抓取请求上报数据时,它可能有指标类型的概念。
4.指标的类型
我们说过指标类型有四种,第一叫counter,计数器,单调递增,除非重置。第二,Gage,仪表盘,仪表盘是一个可增可减的数据,对仪表盘而言,所以我们说经常可以求平均值,求和,求最大值,求最小值等。而对计数器而言,更多的我们是做Delta计算,即用于某一个值减去它的前一项值来这样计算,来求得它的速率,或者叫变化率,变化速率。
第三种类型是我们上次说到的直方图,叫Histogram直方图。
第四种叫做summary。这两个可能稍微难以理解,因为无论是直方图还是summary,在一个指标下单一指标会直接生成多个时间序列,单一指标直接生成多个时间序列。它们的作用都在于去实现做采样数据的分布统计,对采样数据做分布统计所不同的地方在于大家知道histogram是通过把一个取值范围划分成多个bucket,一个把指标采样的取值范围划分为多个叫做存储桶,我们称为叫bucket。每一次采样的结果不会被记下来,注意这一点,每次采样或者每次指标抓取都行,每次采样的样本值不会被记录,而记录的是什么?而记录只是这个样本值处于哪个桶所表达的范围当中,而只是将该值叫做映射,映入其所处的存储桶或者存所处的bucket,而后对该bucket中的计数加1。所以我们每个bucket只是记录那些落入该存储桶所表示的范围内的样本的数量,这里大家要记得。所以我们说每次采纳样本值本身不会被记,而它能记录的只是看这个值到底处于我们刚才分好的这些存储桶当中以小于等的上边界找一个离它最近,能容纳它的存储桶,把它计入存储桶的计数。所以每个桶里边放的是什么,不是样本本身,而是桶本身所能容纳的样本的数量。但除此之外,还记录什么?还有两个固定指标,一个是所有样本数count,大家能记得叫做所有样本数,或者样本的个数,总个数,因为它是做个数计数的,还有一个叫做sum,这叫做所有样本的和,所有样本值的和,所以我们抓取很多样本,这些样本每抓一次都会通过累加的方式加在以sum为后缀的指标名称上。它的前缀就是你自己定指标名,比如我自己定义histogram类型的。这种指标是你一定需要有个名称,这个文具又称为叫basename,大家能记得,而前面我们所划分的这些桶大家还能记得。它通常会有指定多个桶边界,所以它的桶的表达格式那就是basename跟上bucket,而后在指标中我们le。这样的标签来使用一个标签通过le来表达它的上边界是什么。我们说过histogram是一个叫累积直方图,大家还能记得的叫做累积直方图。所以在累积直方图上,各位来看我们使用bucket,使用le等于标签,指定它的上边界是什么就行,所以特定标签叫le至关重要,因为它标记桶边界。每一个桶都有一个上边界,存储桶或者观测桶的上边界及样本统计区别。
接着我们要想能够得到对应区间上的分位值统计。怎么办?比如以咱们班的同学为例,某一次考试结束,现在我想统计不及格的同学占班级所有同学的比例有多大,其实所表达的意思就是le。比如现在里统计的数据样本是分数,很显然,我这里有个le等于60,指的是什么意思?小于等于60,所以le等于60,它是一个bucket,是一个存储桶,它里边存储了小于等于60的所有同学,这叫样本数,这叫样本所有同学,这叫样本总数。所以在le里等于60当中就记录下我们小于等于60的所有同学的总数,我想记得上它的比例怎么办?很简单,除以什么?这里不是有一个叫basenamecount或者除以le等于我们有叫inf,因为最大桶肯定能记录进来所有同学的技术桶加inf最大上边界。很显然,所有数据,所有样本计数的时候一定都在这个桶里,马上有同学能够想一个逻辑,比如我现在这样分的桶,le等于45,le等于60,le等于75,le等于100,当然可能还有le等于95,等于90之类的。现在有一个同学他考了79分,请问哪个统计数会加1?这两个是不是都会加1?只要比值大的区间都会加1。因为我说过,它是叫累积直方图。所以有一个同学考30分意味着什么?没错,所有桶都会加一,这是他的技术的逻辑。很显然,我现在要计算差不多刚好考80分的同学,注意刚才说的概念,差不多考80分同学是谁?或者刚好考50分的同学是谁?你怎么计算?注意刚好考50分,因为我们的取值范围是0-100,50中位数, 50就叫中位数。所以我现在让你取出50可能不一定是50,因为它要是0到100,它中位数可能不止是50这一个,如果是1到100,它可能有两个。如果要算0分,50就是中位数,所以我让你估算一下50分的样本到底是谁。
大家有没有发现,这个桶的分法,很难取出来知道50是谁?所以在这种情况下,我们只能叫粗略的估算刚好中位数是几,其实不是50分是谁,而是你的中位数大概是几,因为这里不是50分。你要明白道理,因为很有可能我们同学考的范围是30到99,30-99的中位数是谁,而不是你的取值好像0-100的中位数,现在我们现在这里每个桶上都落很多统一计数,我们要得出来我们采样的所有结果,当中的中位数是谁,但是我们只记录每一个桶上有几个以及所有桶上的样本数的和和所有桶上的样本的总数,你想知道中位数是谁?我们又没有记录任何样本值,你想知道这中位数谁?怎么算?所以他们只能基于某一种线性的方式进行估算,因此,我们的prometheus提供一个叫Histogram quantile的函数。