Prometheus-基础系列-(四)-PromQL语句实践-1

Prometheus-基础系列-(四)-PromQL语句实践-1

PromQL 语句

使用PromQL 可以方便的对监控指标数据进行统计和分析,这相当于学习一本简单语言有点类似于T-SQL,里面会涉及到常用的运算符、内置函数,让我们方便对数据进行一些高级处理

我们已经有心里准备要学习一个简单语言,学习这个查询语句之前先了解下数据模型

时间序列

通过Node Exporter组件、暴露的HTTP接口也就是之前的 ip:9100/metrics ,可以采集到所有的监控指标数据。例如:

# HELP node_cpu_guest_seconds_total Seconds the cpus spent in guests (VMs) for each mode.
# TYPE node_cpu_guest_seconds_total counter
node_cpu_guest_seconds_total{cpu="0",mode="nice"} 0
node_cpu_guest_seconds_total{cpu="0",mode="user"} 0
# HELP node_cpu_seconds_total Seconds the cpus spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 19102.84
node_cpu_seconds_total{cpu="0",mode="iowait"} 3.15
node_cpu_seconds_total{cpu="0",mode="irq"} 0
node_cpu_seconds_total{cpu="0",mode="nice"} 3.25
node_cpu_seconds_total{cpu="0",mode="softirq"} 1.71
node_cpu_seconds_total{cpu="0",mode="steal"} 0
node_cpu_seconds_total{cpu="0",mode="system"} 65.96
node_cpu_seconds_total{cpu="0",mode="user"} 57.11
# HELP node_disk_io_now The number of I/Os currently in progress.
# HELP node_load1 1m load average.
# TYPE node_load1 gauge
node_load1 0.02
# HELP node_load15 15m load average.
# TYPE node_load15 gauge
node_load15 0.12
# HELP node_load5 5m load average.
# TYPE node_load5 gauge
node_load5 0.07

注释 # 会告诉你每个监控项 为什么数据,当前这里面监控的数据:node_cpu_seconds_total 代表 metrics 其中里面的数据为 指标的纬度和特征后面是 values 数据值。

样本

Prometheus会将所有采集到的样本数据以时间序列(time-series)的方式保存在 内存数据库 中,并且定时保存到硬盘上。time-series是按照时间戳和值的序列顺序存放的,我们称之为向量(vector). 每条time-series通过指标名称(metrics name)和一组标签集(labelset)命名。如下所示,可以将time-series理解为一个以时间为Y轴的数字矩阵:

^
  │   . . . . . . . . . . . . . . . . .   . .   node_cpu_seconds_total{cpu="cpu0",mode="idle"}
  │     . . . . . . . . . . . . . . . . . . .   node_cpu_seconds_total{cpu="cpu0",mode="system"}
  │     . . . . . . . . . .   . . . . . . . .   node_load1{}
  │     . . . . . . . . . . . . . . . .   . .  
    <------------------ 时间 ---------------->

在time-series中的每一个点称为一个样本(sample),样本由以下三部分组成:

  • 指标(metric):metric name和描述当前样本特征的labelsets;
  • 时间戳(timestamp):一个精确到毫秒的时间戳;
  • 样本值(value): 一个float64的浮点型数据表示当前样本的值。
<--------------- metric ---------------------><-timestamp -><-value->
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 1122
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0

指标(Metric)

在形式上,所有的指标(Metric)都通过如下格式标示:

<metric name>{<label name>=<label value>, ...}

指标的名称(metric name)可以反映被监控样本的含义(比如, http_request_total - 表示当前系统接收到的HTTP请求总量)。指标名称只能由ASCII字符、数字、下划线以及冒号组成并必须符合正则表达式 [a-zA-Z_:][a-zA-Z0-9_:]*

标签(label)反映了当前样本的特征维度,通过这些维度Prometheus可以对样本数据进行过滤,聚合等。标签的名称只能由ASCII字符、数字以及下划线组成并满足正则表达式 [a-zA-Z_][a-zA-Z0-9_]*

其中以 __ 作为前缀的标签,是系统保留的关键字,只能在系统内部使用。标签的值则可以包含任何Unicode编码的字符。在Prometheus的底层实现中指标名称实际上是以 __name__= 的形式保存在数据库中的,因此以下两种方式均表示的同一条time-series:

api_http_requests_total{method="POST", handler="/messages"}

等同于:

{__name__="api_http_requests_total",method="POST", handler="/messages"}

在Prometheus源码中也可以找到指标(Metric)对应的数据结构,如下所示:

type Metric LabelSet
type LabelSet map[LabelName]LabelValue
type LabelName string
type LabelValue string

Metrics类型

在Prometheus的存储实现上所有的监控样本都是以time-series的形式保存在Prometheus内存的TSDB(时序数据库)中,而time-series所对应的监控指标(metric)也是通过labelset进行唯一命名的。

从存储上来讲所有的监控指标metric都是相同的,但是在不同的场景下这些metric又有一些细微的差异。 例如,在Node Exporter返回的样本中指标node_load1反应的是当前系统的负载状态,随着时间的变化这个指标返回的样本数据是在不断变化的。而指标node_cpu所获取到的样本数据却不同,它是一个持续增大的值,因为其反应的是CPU的累积使用时间,从理论上讲只要系统不关机,这个值是会无限变大的。

为了能够帮助用户理解和区分这些不同监控指标之间的差异,Prometheus定义了4中不同的指标类型(metric type):Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)、Summary(摘要)。

在Exporter返回的样本数据中,其注释中也包含了该样本的类型。例如:

# HELP node_cpu Seconds the cpus spent in each mode.
# TYPE node_cpu counter
node_cpu{cpu="cpu0",mode="idle"} 362812.7890625

Counter:只增不减的计数器

Counter类型的指标其工作方式和计数器一样,只增不减(除非系统发生重置)。常见的监控指标,如http_requests_total,node_cpu都是Counter类型的监控指标。 一般在定义Counter类型指标的名称时推荐使用_total作为后缀。

Counter是一个简单但有强大的工具,例如我们可以在应用程序中记录某些事件发生的次数,通过以时序的形式存储这些数据,我们可以轻松的了解该事件产生速率的变化。 PromQL内置的聚合操作和函数可以让用户对这些数据进行进一步的分析:

例如,通过rate()函数获取HTTP请求量的增长率:

rate(prometheus_http_requests_total[5m])



查询当前系统中,访问量前10的HTTP地址:

topk(10, prometheus_http_requests_total)



Gauge:可增可减的仪表盘

与Counter不同,Gauge类型的指标侧重于反应系统的当前状态。因此这类指标的样本数据可增可减。常见指标如:

  • node_memory_MemFree_bytes(主机当前空闲的内容大小)
  • node_memory_MemAvailable(可用内存大小)都是Gauge类型的监控指标。

通过Gauge指标,用户可以直接查看系统的当前状态:

node_memory_MemFree_bytes



对于Gauge类型的监控指标,通过PromQL内置函数delta()可以获取样本在一段时间返回内的变化情况。例如,

  • 计算load5分钟 负载在两个小时内的差异:
delta(node_load5{instance="localhost:9100",job="node"}[2h])



还有更牛逼的变化趋势预测

  • 使用deriv()计算样本的线性回归模型
  • 使用 predict_linear() 对数据的变化趋势进行预测。

例如,预测系统load5分钟负载在4个小时之后的剩余情况:

predict_linear(node_filesystem_free{job="node"}[1h], 4 * 3600)



使用Histogram和Summary分析数据分布情况

Histogram和Summary主用用于统计和分析样本的分布情况。

在大多数情况下人们都倾向于使用某些量化指标的平均值,例如CPU的平均使用率、页面的平均响应时间。这种方式的问题很明显,以系统API调用的平均响应时间为例:如果大多数API请求都维持在100ms的响应时间范围内,而个别请求的响应时间需要5s,那么就会导致某些WEB页面的响应时间落到中位数的情况,而这种现象被称为长尾问题。

为了区分是平均的慢还是长尾的慢,最简单的方式就是按照请求延迟的范围进行分组。例如,统计延迟在0~10ms之间的请求数有多少而10~20ms之间的请求数又有多少。通过这种方式可以快速分析系统慢的原因。Histogram和Summary都是为了能够解决这样问题的存在,通过Histogram和Summary类型的监控指标,我们可以快速了解监控样本的分布情况。

例如:

指标 prometheus_tsdb_wal_fsync_duration_seconds 的指标类型为 Summary

它记录了Prometheus Server中wal_fsync处理的处理时间,通过访问Prometheus Server的/metrics地址,可以获取到以下监控样本数据:

# HELP prometheus_tsdb_wal_fsync_duration_seconds Duration of WAL fsync.
# TYPE prometheus_tsdb_wal_fsync_duration_seconds summary
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.012352463
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.014458005
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.017316173
prometheus_tsdb_wal_fsync_duration_seconds_sum 2.888716127000002
prometheus_tsdb_wal_fsync_duration_seconds_count 216

从上面的样本中可以得知当前Prometheus Server进行wal_fsync操作的总次数为216次,耗时2.888716127000002s。其中中位数(quantile=0.5)的耗时为0.012352463,9分位数(quantile=0.9)的耗时为0.014458005s。

在Prometheus Server自身返回的样本数据中,我们还能找到类型为Histogram的监控指标prometheus_tsdb_compaction_chunk_range_bucket。

# HELP prometheus_tsdb_compaction_chunk_range Final time range of chunks on their first compaction
# TYPE prometheus_tsdb_compaction_chunk_range histogram
prometheus_tsdb_compaction_chunk_range_bucket{le="100"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="6400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="25600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="102400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="409600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1.6384e+06"} 260
prometheus_tsdb_compaction_chunk_range_bucket{le="6.5536e+06"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="2.62144e+07"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="+Inf"} 780
prometheus_tsdb_compaction_chunk_range_sum 1.1540798e+09
prometheus_tsdb_compaction_chunk_range_count 780

与Summary类型的指标相似之处在于Histogram类型的样本同样会反应当前指标的记录的总数(以_count作为后缀)以及其值的总量(以_sum作为后缀)。不同在于Histogram指标直接反应了在不同区间内样本的个数,区间通过标签len进行定义。

同时对于Histogram的指标,我们还可以通过histogram_quantile()函数计算出其值的分位数。不同在于Histogram通过histogram_quantile函数是在服务器端计算的分位数。 而Sumamry的分位数则是直接在客户端计算完成。因此对于分位数的计算而言,Summary在通过PromQL进行查询时有更好的性能表现,而Histogram则会消耗更多的资源。反之对于客户端而言Histogram消耗的资源更少。在选择这两种方式时用户应该按照自己的实际场景进行选择。

你可以先简单这样理解,这个可以统计server性能。下面进入正题

PromQL

Prometheus通过指标名称(metrics name)以及对应的一组标签(labelset)唯一定义一条时间序列。指标名称反映了监控样本的基本标识,而label则在这个基本特征上为采集到的数据提供了多种特征维度。用户可以基于这些特征维度过滤,聚合,统计从而产生新的计算后的一条时间序列。

PromQL是Prometheus内置的数据查询语言,其提供对时间序列数据丰富的查询,聚合以及逻辑运算能力的支持。并且被广泛应用在Prometheus的日常应用当中,包括对数据查询、可视化、告警处理当中。可以这么说,PromQL是Prometheus所有应用场景的基础,理解和掌握PromQL是Prometheus入门的第一课。

看上面文字云里雾里的,直接看数据更直接



下面通过一些例子做个基本练习

查询时间序列

当Prometheus通过Exporter采集到相应的监控指标样本数据后,我们就可以通过PromQL对监控样本数据进行查询。

当我们直接使用监控指标名称查询时,可以查询该指标下的所有时间序列。如:

prometheus_http_requests_total

等同于:

prometheus_http_requests_total{}

该表达式会返回指标名称为 prometheus_http_requests_total 的所有时间序列:

prometheus_http_requests_total{code="200",handler="/api/v1/label/:name/values",instance="localhost:9090",job="prometheus"}  6
prometheus_http_requests_total{code="200",handler="/api/v1/query",instance="localhost:9090",job="prometheus"}   15
prometheus_http_requests_total{code="200",handler="/api/v1/query_range",instance="localhost:9090",job="prometheus"} 37
prometheus_http_requests_total{code="200",handler="/config",instance="localhost:9090",job="prometheus"} 1
prometheus_http_requests_total{code="200",handler="/flags",instance="localhost:9090",job="prometheus"}  1
prometheus_http_requests_total{code="200",handler="/graph",instance="localhost:9090",job="prometheus"}

PromQL还支持用户根据时间序列的标签匹配模式来对时间序列进行过滤,目前主要支持两种匹配模式:完全匹配和正则匹配。

PromQL支持使用 = != 两种完全匹配模式:

  • 通过使用 label=value 可以选择那些标签满足表达式定义的时间序列;
  • 反之使用 label!=value 则可以根据标签匹配排除时间序列;

例如,如果我们只需要查询所有prometheus_http_requests_total时间序列中满足标签instance为localhost:9090的时间序列,则可以使用如下表达式:

localhost 是Prometheus的server服务器

prometheus_http_requests_total{instance="localhost:9090"}



反之使用 instance!="localhost:9090" 则可以排除这些时间序列:

prometheus_http_requests_total{code!="200"}



除了使用完全匹配的方式对时间序列进行过滤以外,PromQL还可以支持使用正则表达式作为匹配条件,多个表达式之间使用 | 进行分离:

  • 使用 label=~regx 表示选择那些标签符合正则表达式定义的时间序列;
  • 反之使用 label!~regx 进行排除;

例如,如果想查询多个环节下的时间序列序列可以使用如下表达式:

prometheus_http_requests_total{environment=~"staging|testing|development",method!="GET"}

范围查询

直接通过类似于PromQL表达式http requeststotal查询时间序列时,返回值中只会包含该时间序列中的最新的一个样本值,这样的返回结果我们称之为 瞬时向量 。而相应的这样的表达式称之为__瞬时向量表达式

而如果我们想过去一段时间范围内的样本数据时,我们则需要使用 区间向量表达式 。区间向量表达式和瞬时向量表达式之间的差异在于在区间向量表达式中我们需要定义时间选择的范围,时间范围通过时间范围选择器 [] 进行定义。例如,通过以下表达式可以选择最近5分钟内的所有样本数据:

node_load5{}[2m]

获取系统5分钟平均负载,最近2分钟的所有样本数据:



通过区间向量表达式查询到的结果我们称为 区间向量

除了使用m表示分钟以外,PromQL的时间范围选择器支持其它时间单位:

  • s - 秒
  • m - 分钟
  • h - 小时
  • d - 天
  • w - 周
  • y - 年

时间位移操作

在瞬时向量表达式或者区间向量表达式中,都是以当前时间为基准:

node_load5{} # 瞬时向量表达式,选择当前最新的数据
node_load5{}[2m] # 区间向量表达式,选择以当前时间为基准,2分钟内的数据

而如果我们想查询,2分钟前的瞬时样本数据,或昨天一个小时的区间内的样本数据呢? 这个时候我们就可以使用位移操作,位移操作的关键字为 offset

可以使用offset时间位移操作:

说点你能听懂的,就是类似数据环比,例如订单数据与上周环比、上个月环比类似,你可以利用这个功能做些数据对比





使用聚合操作

一般来说,如果描述样本特征的标签(label)在并非唯一的情况下,通过PromQL查询数据,会返回多条满足这些特征维度的时间序列。而PromQL提供的聚合操作可以用来对这些时间序列进行处理,形成一条新的时间序列:

# 查询系统所有http请求的总量
sum(prometheus_http_requests_total)
# 按照mode计算主机CPU的平均使用时间
avg(node_cpu_seconds_total) by (mode)
# 后面的by 有点类似于 sql中的分组 order by
# 按照主机查询各个主机的CPU使用率
sum(sum(irate(node_cpu_seconds_total{mode!='idle'}[5m]))  / sum(irate(node_cpu_seconds_total[5m]))) by (instance)

标量和字符串

除了使用瞬时向量表达式和区间向量表达式以外,PromQL还直接支持用户使用标量(Scalar)和字符串(String)。

标量(Scalar):一个浮点型的数字值

标量只有一个数字,没有时序。

例如:

10
需要注意的是,当使用表达式count(prometheus_http_requests_total),返回的数据类型,依然是瞬时向量。用户可以通过内置函数scalar()将单个瞬时向量转换为标量。



字符串(String):一个简单的字符串值

直接使用字符串,作为PromQL表达式,则会直接返回字符串。



合法的PromQL表达式

所有的PromQL表达式都必须至少包含一个指标名称(例如http_request_total),或者一个不会匹配到空字符串的标签过滤器(例如{code="200"})。

因此以下两种方式,均为合法的表达式:

prometheus_http_requests_total # 合法
prometheus_http_requests_total{} # 合法
{method="get"} # 合法

而如下表达式,则不合法:

{job=~".*"} # 不合法

同时,除了使用 {label=value} 的形式以外,我们还可以使用内置的 __name__ 标签来指定监控指标名称:

{__name__=~"prometheus_http_requests_total"} # 合法
{__name__=~"node_disk_bytes_read|node_disk_bytes_written"} # 合法

数学运算

例如,我们可以通过指标 node_memory_MemFree_bytes 获取当前主机可用的内存空间大小,其样本单位为Bytes。这是如果客户端要求使用MB作为单位响应数据,那只需要将查询到的时间序列的样本值进行单位换算即可:

node_memory_MemFree_bytes / (1024 * 1024)

node_memory_MemFree_bytes 表达式会查询出所有满足表达式条件的时间序列,在上一小节中我们称该表达式为瞬时向量表达式,而返回的结果成为瞬时向量。

当瞬时向量与标量之间进行数学运算时,数学运算符会依次作用域瞬时向量中的每一个样本值,从而得到一组新的时间序列。

而如果是瞬时向量与瞬时向量之间进行数学运算时,过程会相对复杂一点。

例如:

如果我们想根据 node_disk_written_bytes_total node_disk_read_bytes_total 获取主机磁盘IO的总量,可以使用如下表达式:

node_disk_written_bytes_total + node_disk_read_bytes_total

那这个表达式是如何工作的呢?依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行运算,如果没找到匹配元素,则直接丢弃。同时新的时间序列将不会包含指标名称。 该表达式返回结果的示例如下所示:



PromQL支持的所有数学运算符如下所示:

  • + (加法)
  • - (减法)
  • * (乘法)
  • / (除法)
  • % (求余)
  • ^ (幂运算)

使用布尔运算过滤时间序列

在PromQL通过标签匹配模式,用户可以根据时间序列的特征维度对其进行查询。而布尔运算则支持用户根据时间序列中样本的值,对时间序列进行过滤。

例如,通过数学运算符我们可以很方便的计算出,当前所有主机节点的内存使用率:

(node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / node_memory_MemTotal_bytes

而系统管理员在排查问题的时候可能只想知道当前内存使用率超过95%的主机呢?通过使用布尔运算符可以方便的获取到该结果:

(node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / node_memory_MemTotal_bytes > 0.95

瞬时向量与标量进行布尔运算时,PromQL依次比较向量中的所有时间序列样本的值,如果比较结果为true则保留,反之丢弃。

瞬时向量与瞬时向量直接进行布尔运算时,同样遵循默认的匹配模式:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行相应的操作,如果没找到匹配元素,则直接丢弃。

目前,Prometheus支持以下布尔运算符如下:

  • == (相等)
  • != (不相等)
  • > (大于)
  • < (小于)
  • >= (大于等于)
  • <= (小于等于)

使用bool修饰符改变布尔运算符的行为

布尔运算符的默认行为是对时序数据进行过滤。而在其它的情况下我们可能需要的是真正的布尔结果。

例如,只需要知道当前模块的HTTP请求量是否>=1000,如果大于等于1000则返回1(true)否则返回0(false)。这时可以使用bool修饰符改变布尔运算的默认行为。 例如:

prometheus_http_requests_total > bool 1000

使用bool修改符后,布尔运算不会对时间序列进行过滤,而是直接依次瞬时向量中的各个样本数据与标量的比较结果0或者1。从而形成一条新的时间序列。



同时需要注意的是,如果是在两个标量之间使用布尔运算,则必须使用bool修饰符

2 == bool 2 # 结果为1

使用集合运算符

使用瞬时向量表达式能够获取到一个包含多个时间序列的集合,我们称为瞬时向量。

通过集合运算,可以在两个瞬时向量与瞬时向量之间进行相应的集合操作。目前,Prometheus支持以下集合运算符:

  • and (并且)
  • or (或者)
  • unless (排除)

vector1 and vector2 会产生一个由vector1的元素组成的新的向量。该向量包含vector1中完全匹配vector2中的元素组成。

vector1 or vector2 会产生一个新的向量,该向量包含vector1中所有的样本数据,以及vector2中没有与vector1匹配到的样本数据。

vector1 unless vector2 会产生一个新的向量,新向量中的元素由vector1中没有与vector2匹配的元素组成。

操作符优先级

对于复杂类型的表达式,需要了解运算操作的运行优先级

例如,查询主机的CPU使用率,可以使用表达式:

100 * (1 - avg (irate(node_cpu_seconds_total{mode='idle'}[5m])) by(job) )

其中irate是PromQL中的内置函数,用于计算区间向量中时间序列每秒的即时增长率。

在PromQL操作符中优先级由高到低依次为:

  1. ^
  2. *, /, %
  3. +, -
  4. ==, !=, <=, <, >=, >
  5. and, unless
  6. or

匹配模式详解

向量与向量之间进行运算操作时会基于默认的匹配规则:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行运算,如果没找到匹配元素,则直接丢弃。

接下来将介绍在PromQL中有两种典型的匹配模式:一对一(one-to-one),多对一(many-to-one)或一对多(one-to-many)。

一对一匹配

一对一匹配模式会从操作符两边表达式获取的瞬时向量依次比较并找到唯一匹配(标签完全一致)的样本值。默认情况下,使用表达式:

vector1 <operator> vector2

在操作符两边表达式标签不一致的情况下,可以使用on(label list)或者ignoring(label list)来修改便签的匹配行为。使用ignoreing可以在匹配时忽略某些便签。而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

使用PromQL表达式:

method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m

该表达式会返回在过去5分钟内,HTTP请求状态码为500的在所有请求中的比例。如果没有使用ignoring(code),操作符两边表达式返回的瞬时向量中将找不到任何一个标签完全相同的匹配项。

因此结果如下:

{method="get"}  0.04            //  24 / 600
{method="post"} 0.05            //   6 / 120

同时由于method为put和del的样本找不到匹配项,因此不会出现在结果当中。

多对一和一对多

多对一和一对多两种匹配模式指的是“一”侧的每一个向量元素可以与"多"侧的多个元素匹配的情况。在这种情况下,必须使用group修饰符:group_left或者group_right来确定哪一个向量具有更高的基数(充当“多”的角色)。

<vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>