1. 二元操作符

    PromQL 的二元操作符支持基本的逻辑判断和算术运算,包含算术类、比较类和逻辑类三大类

    1.1 算术类二元操作符

    +:加
    -:减
    *:乘
    /:除
    %:求余
    ^:乘方
    
    算术类二元操作符可以使用在标量与标量、向量与标量,以及向量与向量之间
    - 标量与标量之间,结果很明显,跟通常的算术运算一致
    - 向量与标量之间,相当于把标量跟向量里的每一个标量进行运算,这些计算结果组成了一个新的向量
    - 向量与向量之间,会稍微麻烦一些。运算的时候首先会为左边向量里的每一个元素在右边向量里去寻找一个匹配元素(匹配规则后面会讲),然后对这两个匹配元素执行计算,这样每对匹配元素的计算结果组成了一个新的向量。如果没有找到匹配元素,则该元素丢弃
    
    # 标量&向量:简单来比喻就是标量是一个数字,向量是一组数字!
    

    1.2 比较类二元操作符

    == (equal)
    != (not-equal)
    >  (greater-than)
    <  (less-than)
    >= (greater-or-equal)
    <= (less-or-equal)
    
    比较类二元操作符同样可以使用在标量与标量、向量与标量,以及向量与向量之间。默认执行的是过滤,也就是保留值
    
    也可以通过在运算符后面跟 bool 修饰符来使得返回值 01,而不是过滤
    
    - 标量与标量之间,必须跟 bool 修饰符,因此结果只可能是 0(false) 或 1(true)
    - 向量与标量之间,相当于把向量里的每一个标量跟标量进行比较,结果为真则保留,否则丢弃。如果后面跟了 bool 修饰符,则结果分别为 10
    - 向量与向量之间,运算过程类似于算术类操作符,只不过如果比较结果为真则保留左边的值(包括度量指标和标签这些属性),否则丢弃,没找到匹配也是丢弃。如果后面跟了 bool 修饰符,则保留和丢弃时结果相应为 10
    

    1.3 逻辑类二元操作符

    and:	交集
    or:		合集
    unless:	补集
    
    具体运算规则如下:
    
    - `vector1 and vector2` 的结果由在 vector2 里有匹配(标签键值对组合相同)元素的 vector1 里的元素组成
    - `vector1 or vector2` 的结果由所有 vector1 里的元素加上在 vector1 里没有匹配(标签键值对组合相同)元素的 vector2 里的元素组成
    - `vector1 unless vector2` 的结果由在 vector2 里没有匹配(标签键值对组合相同)元素的 vector1 里的元素组成
    

    1.4 二元操作符优先级

    #PromQL 的各类二元操作符运算优先级如下:
    ^
    *, /, %
    +, -
    ==, !=, <=, <, >=, >
    and, unless
    or
    
  2. 向量匹配

    前面算术类和比较类操作符都需要在向量之间进行匹配。共有两种匹配类型,one-to-onemany-to-one | one-to-many

    2.1 One-to-one 向量匹配

    这种匹配模式下,两边向量里的元素如果其标签键值对组合相同则为匹配,并且只会有一个匹配元素。可以使用 `ignoring` 关键词来忽略不参与匹配的标签,或者使用 `on` 关键词来指定要参与匹配的标签。语法如下:
    <vector expr> <bin-op> ignoring(<label list>) <vector expr>
    <vector expr> <bin-op> on(<label list>) <vector expr>
    
    比如对于下面的输入:
    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
    
    执行下面的查询:
    method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
    得到的结果为:
    {method="get"}  0.04            #  24 / 600
    {method="post"} 0.05            #   6 / 120
    也就是每一种 method 里 code 为 500 的请求数占总数的百分比。由于 method 为 put 和 del 的没有匹配元素所以没有出现在结果里
    

    2.2 Many-to-one / one-to-many 向量匹配

    这种匹配模式下,某一边会有多个元素跟另一边的元素匹配。这时就需要使用 `group_left``group_right` 组修饰符来指明哪边匹配元素较多,左边多则用 `group_left`,右边多则用 `group_right`。其语法如下:
    <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{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
    
    组修饰符只适用于算术类和比较类操作符,对于前面的输入,执行下面的查询:
    method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
    将得到下面的结果:
    {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 错误次数占每种 method 请求数的比例。这里匹配的时候 ignoring 了 code,才使得两边可以形成 Many-to-one 形式的匹配。由于左边多,所以需要使用 group_left 来指明
    
    Many-to-one / one-to-many 过于高级和复杂,要尽量避免使用。但很多时候通过 ignoring 就可以解决问题
    
  3. 聚合操作符

    PromQL 的聚合操作符用来将向量里的元素聚合得更少。总共有下面这些聚合操作符:

    sum:求和
    min:最小值
    max:最大值
    avg:平均值
    stddev:标准差
    stdvar:方差
    count:元素个数
    count_values:等于某值的元素个数
    bottomk:最小的 k 个元素
    topk:最大的 k 个元素
    quantile:分位数
    PromQL 中的聚合操作语法格式可采用如下面两种格式之一
    ● <聚合函数>(向量表达式) by|without (标签)<聚合函数> by|without (标签) (向量表达式)
    聚合操作符语法如下:
    其中 `without` 用来指定不需要保留的标签(也就是这些标签的多个值会被聚合),而 `by` 正好相反,用来指定需要保留的标签(也就是按这些标签来聚合)
    
    下面来看几个示例:
    sum(http_requests_total) without (instance)
    #解释
    http_requests_total 度量指标带有 application、instance 和 group 三个标签。上面的表达式会得到每个 application 的每个 group 在所有 instance 上的请求总数。效果等同于下面的表达式:
    sum(http_requests_total) by (application, group)
     示例
    (1)每台主机 CPU 在最近 5 分钟内的平均使用率
    (1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance)) * 100
    (2)查询 1 分钟的 load average 的时间序列是否超过主机 CPU 数量 2 倍
    node_load1 > on (instance) 2 * count (node_cpu_seconds_total{mode="idle"}) by (instance)
    (3)计算主机内存使用率
    可用内存空间:空闲内存、buffer、cache 指标之和
    node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes
    已用内存空间:总内存空间减去可用空间
    node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)
    使用率:已用空间除以总空间
    (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) / node_memory_MemTotal_bytes * 100
    (4)计算每个 node 节点所有容器总计内存:
    sum  by (instance) (container_memory_usage_bytes{instance=~"node*"})/1024/1024/1024
    (5)计算 node01 节点最近 1m 所有容器 cpu 使用率:
    sum (rate(container_cpu_usage_seconds_total{instance="node01"}[1m])) / sum (machine_cpu_cores{instance="node01"}) * 100
    #container_cpu_usage_seconds_total 代表容器占用CPU的时间总和
    (6)计算最近 5m 每个容器 cpu 使用情况变化率
    sum (rate(container_cpu_usage_seconds_total[5m])) by (container_name)
    (7)查询 K8S 集群中最近 1m 每个 Pod 的 CPU 使用情况变化率
    sum (rate(container_cpu_usage_seconds_total{image!="", pod_name!=""}[1m])) by (pod_name) 
    #由于查询到的数据都是容器相关的,所以最好按照 Pod 分组聚合
    
    
    

4.学习方法

#这是grafanca的模板的PQL语句
(node_filesystem_size_bytes{instance=~"$instance",fstype=~"ext.*|xfs|nfs",mountpoint !~".*pod.*"}-node_filesystem_free_bytes{instance=~"$instance",fstype=~"ext.*|xfs|nfs",mountpoint !~".*pod.*"}) *100/(node_filesystem_avail_bytes {instance=~"$instance",fstype=~"ext.*|xfs|nfs",mountpoint !~".*pod.*"}+(node_filesystem_size_bytes{instance=~"$instance",fstype=~"ext.*|xfs|nfs",mountpoint !~".*pod.*"}-node_filesystem_free_bytes{instance=~"$instance",fstype=~"ext.*|xfs|nfs",mountpoint !~".*pod.*"}))
#先拆分
(node_filesystem_size_bytes{instance=~"192.168.88.130:9100",fstype=~"xfs"}-node_filesystem_free_bytes{instance=~"192.168.88.130:9100",fstype=~"xfs"}) *100/(node_filesystem_avail_bytes {instance=~"192.168.88.130:9100",fstype=~"xfs"}+(node_filesystem_size_bytes{instance=~"192.168.88.130:9100",fstype=~"xfs"}-node_filesystem_free_bytes{instance=~"192.168.88.130:9100",fstype=~"xfs"}))
#在拆分
(node_filesystem_size_bytes-node_filesystem_free_bytes) *100/(node_filesystem_avail_bytes+(node_filesystem_size_bytes-node_filesystem_free_bytes))
#分解
(node_filesystem_size_bytes-node_filesystem_free_bytes)
/
(node_filesystem_avail_bytes+(node_filesystem_size_bytes-node_filesystem_free_bytes))
*
100
#得出结论
(总量-空闲量)/(可用量+(总量-空闲量))*100
#答案
使用量/总量*100
#说明写PQL必须从最后一步开始写,先确定在慢慢精确
总结
1.  不是所有的指标(数据)都可以在数据库中直接查询得到,有些需要使用运算式计算得来。
2.  运算过程没有正确与否,简单或复杂只要得到的结果正确即可
3.  学习promQL(PQL)可以通过grafana的模板学习参考

3. PromQL函数

Prometheus 内置了一些函数来辅助计算,下面介绍一些典型的

abs():绝对值
sqrt():平方根
exp():指数计算
ln():自然对数
ceil():向上取整
floor():向下取整
round():四舍五入取整
delta():计算区间向量里每一个时序第一个和最后一个的差值
sort():排序

五、Prome

 posted on 2024-11-19 10:20  dapaige  阅读(121)  评论(0)    收藏  举报  来源