GitHub:prometheus
架构图:时序数据存储,抓取数据,推送告警,提供PromQL查询数据,对接UI仪表盘,和K8s对接。
直接本机Docker启动,然后访问本机后台:http://localhost:9090/
docker run --name prometheus -d -p 127.0.0.1:9090:9090 prom/prometheus
可以docker inspect看到它的信息:
- 配置文件:
--config.file=/etc/prometheus/prometheus.yml
- 存储路径:
--storage.tsdb.path=/prometheus
数据模型:
- 所有数据都是时序数据,time series。
- 时序数据可以有name和label来分类过滤,比如:
<metric name>{<label name>=<label value>, ...}
api_http_requests_total{method="POST", handler="/messages"}
度量类型:
任务和实例:
- 抓取endpoint是一个实例,一般就是一个进程。
- 多个进程组成一个任务,主要是为了扩容和可靠性。
Docker
配置文件规则:Configuration
- 先启动一个node exporter:
docker run --rm -it -p 9100:9100 prom/node-exporter
- 编写Prometheus的配置文件,抓取这个配置:
scrape_configs:
- job_name: "node0"
metrics_path: "/metrics"
scrape_interval: 5s
static_configs:
- targets: ["host.docker.internal:9100"]
- 以本机配置启动:
docker run --rm -v `pwd`/prometheus.yml:/etc/prometheus/prometheus.yml \
-p 9090:9090 prom/prometheus
- 进入9090可以看到正常启动了。
Exporter
Exporter是无缝将现有系统接入Prometheus:链接
Prometheus有相当广泛的exporter,其实就是各个平台和软件的插件,比如几个关键的:
这个exporter的机制,是能广泛应用和接入的基础能力。
Node Exporter
主机监控的Exporter:Node/system metrics exporter
下载二进制后直接运行:链接
使用Docker运行,测试在Linux可以,在Mac不行:
docker run --rm --net=host --pid=host -v "/:/host:ro,rslave" \
prom/node-exporter --path.rootfs=/host
在Darwin下,还是直接运行二进制比较好,注意还是需要允许运行会提示是恶意软件:
./node_exporter-1.3.1.darwin-amd64/node_exporter
Darwin下测试用,也可以直接非host方式运行:
docker run --rm -p 9100:9100 \
ccr.ccs.tencentyun.com/ossrs/node-exporter
编译执行:
make
./node_exporter
Prometheus配置文件prometheus.yml
:
scrape_configs:
- job_name: "node"
metrics_path: "/metrics"
scrape_interval: 5s
static_configs:
- targets: ["host.docker.internal:9100"]
启动服务:
docker run --rm -it -v `pwd`/prometheus.yml:/etc/prometheus/prometheus.yml \
-p 9090:9090 prom/prometheus
Textfile Collector
Node Exporter可以采集文件,比如/etc/node-exporter/node-meta.prom
,或者指定路径:
mkdir node0 && echo 'machine_role{role="apache"} 1' > node0/roles.prom
启动时指定采集这个目录:
docker run --rm -it -p 9100:9100 -v $(pwd):/data -w /data \
prom/node-exporter --collector.textfile.directory node0
可以看到这个采集的数据:
machine_role
machine_role{instance="9100", job="node0", role="apache"} 1
Lighthouse
在LightHouse上运行Prometheus:
docker run --rm --add-host=mgmt.srs.local:10.0.24.2 \
-v `pwd`/prometheus.yml:/etc/prometheus/prometheus.yml \
-p 9090:9090 ccr.ccs.tencentyun.com/ossrs/prometheus
运行Node Exporter:
docker run --rm --net=host --pid=host -v "/:/host:ro,rslave" \
ccr.ccs.tencentyun.com/ossrs/node-exporter --path.rootfs=/host
注意,若启动Prometheus时,指定了data目录,需要使用root启动docker,即--user root
,否则访问失败,因为它使用特定的用户运行:
docker run --user root --rm --add-host=mgmt.srs.local:10.0.24.2 \
-p 9090:9090/tcp -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
-v $(pwd)containers/data/prometheus:/prometheus \
ccr.ccs.tencentyun.com/ossrs/prometheus
BaseUrl
可以指定Prometheus的baseUrl:链接
启动时指定参数:
prometheus --web.external-url http://localhost:19090/prometheus/
Selectors
Prometheus有几种数据类型,参考链接
- Instant vector - 实时的向量,时序数据的集合,时间戳相同。只有这种类型的数据,才能被图形化。
- Range vector - 范围向量,时序数据的集合,一定时间范围。
- Scalar - 标量,浮点数据类型的标量。
先看Instant vector,直接输入node_load1
就是一个Instance vector,如下所示:
node_load1
node_load1{instance="host.docker.internal:9100", job="node0"} 2.474609375
node_load1{instance="host.docker.internal:9102", job="node2"} 0.13
Note: 所谓实时(instant),就是指定的某个时间戳;所谓时序time series,就是不同时间有不同的值;所谓向量vector,就是time series的集合。
再看Range vector,输入时间范围,采样是5s输入30s,如下所示:
node_load1[10s]
node_load1{job="node0"} 1.95361328125 @1660643735.965 1.876953125 @1660643740.968
node_load1{job="node2"} 0.46 @1660643736.352 0.42 @1660643741.351
Note: 可以看到,每个time series的值是一个时间范围的数据,比如上面包含了两个采样点,采样的时间戳并不相同。这就是按时间聚合时,我们会使用的数据类型,使用不同的函数处理它。
Operators
操作符Operators,是针对Instant vector和Scalar之间的运算,不能用于Range vector:
node_load1 * 100
{instance="host.docker.internal:9100", job="node0"} 221.09375
{instance="host.docker.internal:9102", job="node2"} 28.000
对两个Instant vector相除时,他们的label要相同,比如计算网络包所占的字节数:
node_network_receive_bytes_total{device="en0"}/node_network_receive_packets_total
{device="en0", instance=":9100", job="node0"} 17.207300663986636
Note:如果label不同就没有结果。计算结果会丢弃metric的名称,只保留匹配的label。
也支持集合的操作,比如or将两个vector合并了,比如把load和cpu展示在一个图:
node_load1 or node_cpu_seconds_total{cpu="0",mode="user"}
node_load1{job="node0"} 3.33447265625
node_load1{job="node2"} 0.66
node_cpu_seconds_total{cpu="0", job="node0", mode="user"} 48824.2
node_cpu_seconds_total{cpu="0", job="node2", mode="user"} 1115.41
Note: 这样可以把两个指标展示在一个图中了,同时对不同的指标进行处理。是完全按label匹配,而不是按值匹配,因为两个指标的值几乎是不会相等。
Vector maching
Vector matching向量匹配,针对两个可能不完全相等label的向量,比如node比cpu_seconds就少了cpu和mode标签:
node_load1{job="node0"} 3.33447265625
node_load1{job="node2"} 0.66
node_cpu_seconds_total{cpu="0", job="node0", mode="user"} 48824.2
node_cpu_seconds_total{cpu="0", job="node2", mode="user"} 1115.41
如果直接把两个相除,则是空,因为标签并不匹配,无法相除,这时候可以忽略掉cpu和mode,这就是一对一的匹配:
node_cpu_seconds_total{cpu="0",mode="user"} / ignoring(cpu,mode) node_load1
{instance="host.docker.internal:9100", job="node0"} 17082.595555555556
{instance="host.docker.internal:9102", job="node2"} 19009.5
如果我们选择两个cpu,即cpu0和1,这时候就是多对一的关系:
node_load1 or node_cpu_seconds_total{cpu=~"0|1",mode="user"}
node_load1{instance="host.docker.internal:9100", job="node0"} 2.92138671875
node_load1{instance="host.docker.internal:9102", job="node2"} 0.13
node_cpu_seconds_total{cpu="0", instance="host.docker.internal:9100", job="node0", mode="user"} 48954.11
node_cpu_seconds_total{cpu="0", instance="host.docker.internal:9102", job="node2", mode="user"} 1141.35
node_cpu_seconds_total{cpu="1", instance="host.docker.internal:9100", job="node0", mode="user"} 8483.03
node_cpu_seconds_total{cpu="1", instance="host.docker.internal:9102", job="node2", mode="user"} 1148.34
针对多对一的匹配运算,就不能直接相除了,而是需要加上group_left,即以左边的为基数:
node_cpu_seconds_total{cpu=~"0|1",mode="user"} / ignoring(cpu,mode) group_left node_load1
{cpu="0", instance=":9100", job="node0", mode="user"} 19395.831582205028
{cpu="0", instance=":9102", job="node2", mode="user"} 12694.333333333334
{cpu="1", instance=":9100", job="node0", mode="user"} 3360.5223984526115
{cpu="1", instance=":9102", job="node2", mode="user"} 12772.555555555557
使用的是ignore某些标签让剩下的标签相等,也可以on
直接指定匹配的标签,结果也是一样的:
node_cpu_seconds_total{cpu=~"0|1",mode="user"} / on(instance) group_left node_load1
Aggregate
Aggregatable operators聚合操作,针对Instant vector,按照某些标签聚合,比如cpu有很多标签:
node_cpu_seconds_total{cpu=~"0|1",job="node0"}
node_cpu_seconds_total{cpu="0", instance="host.docker.internal:9100", job="node0", mode="idle"} 250784.34
node_cpu_seconds_total{cpu="0", instance="host.docker.internal:9100", job="node0", mode="nice"} 0
node_cpu_seconds_total{cpu="0", instance="host.docker.internal:9100", job="node0", mode="system"} 84181.76
node_cpu_seconds_total{cpu="0", instance="host.docker.internal:9100", job="node0", mode="user"} 49026.15
node_cpu_seconds_total{cpu="1", instance="host.docker.internal:9100", job="node0", mode="idle"} 361174.34
node_cpu_seconds_total{cpu="1", instance="host.docker.internal:9100", job="node0", mode="nice"} 0
node_cpu_seconds_total{cpu="1", instance="host.docker.internal:9100", job="node0", mode="system"} 13072.18
node_cpu_seconds_total{cpu="1", instance="host.docker.internal:9100", job="node0", mode="user" 8485.57
我们可以按照mode聚合,这样就可以看到整体不同mode的数据:
sum by(mode) (node_cpu_seconds_total{cpu=~"0|1",job="node0"})
{mode="idle"} 612159.87
{mode="nice"} 0
{mode="system"}97277.25
{mode="user"} 57527.03
Functions
Functions函数,可以对Instant vector或Range vector进行变换,比如求差值按时间的变化:
rate(node_cpu_seconds_total{cpu="0",job="node0",mode="user"}[10s])
{} 0.18210926555857848
node_cpu_seconds_total{cpu="0",job="node0",mode="user"}[10s]
node_cpu_seconds_total{} 49198.42@1660650581.185 49199.33@1660650586.166
increase(node_cpu_seconds_total{cpu="0",job="node0",mode="user"}[10s])/10
{} 0.18210926555857848
rate的输入是Range vector,输出是Instant vector,可以对结果再进行Aggregate操作:
sum by(instance) (rate(node_cpu_seconds_total{cpu="0",mode=~"user|system"}[10s]))
{instance="host.docker.internal:9100"} 0.3072289156609558
{instance="host.docker.internal:9102"} 0.02811809600318792
Note: 不同函数的输入和输出参数都不同,需要看手册。
由于Range vector每个time series也是一个集合,比如10秒的负载,包含两个采样:
node_load1[10s]
node_load1{job="node0"} 2.734375@1660650915.931 2.67529296875@1660650920.93
node_load1{job="node2"} 0.29@1660650916.317 0.26@1660650921.316
那么也可以对这些采样进行聚合操作,比如最大值:
max_over_time(node_load1[10s])
{instance="host.docker.internal:9100", job="node0"} 2.734375
{instance="host.docker.internal:9102", job="node2"} 0.29
然后再按标签进行聚合,求得系统最大的负载:
max(max_over_time(node_load1[10s]))
{} 2.734375
Label
关于如何打Label,相关资料如下:
- Labels
- Use labels
- Do not overuse labels
- Target labels, not static scraped labels
- How to have labels for machine roles:加个独立的标签,就可以标识exporter的属性,而不需要修改之前的指标。
- Exposing the software version to Prometheus
Grafana也列出了一些Exporter,可以看到示例数据:
The USE Method
For every resource, check utilization, saturation, and errors.
摘要:
- resource: 系统的资源。
- utilization: 资源的使用率。比如CPU使用率70%。
- saturation: 资源的饱和度,排队和过载情况。比如load,就是CPU任务排队的情况。
- errors: 错误事件和次数。
按照USE制作的Node Exporter大盘,参考链接:
- CPU Utilization
- CPU Saturation (Load per CPU)
- Memory Utilisation
- Memory Saturation (Major Page Faults)
- Net Utilization (Bytes Receive/Transmit)
- Net Saturation (Drops Receive/Transmit)
- Disk I/O Utilization
- Disk I/O Saturation
Metrics
哪些指标可以作为Metric,可以根据不同系统做分类:
- Online-serving systems在线服务器,比如SRS或API服务器,需要立刻对请求做响应的服务器。关键指标是请求数目、错误数目、请求耗时、服务器并发。应该在客户端和服务器同时采集,当两边的数据不同时会有助于分析问题;当然如果并发太高,就只能靠自己的统计系统了。一般是在请求结束时采集数据,比较方便采集错误和耗时。
- Offline processing离线处理。离线处理就不会在线等响应,离线处理一般是批处理完成的,而且会分成很多阶段处理。关键指标是每个阶段的输入输出,多少在处理中,上次处理完的时间;对于批处理,还需要跟踪分支。当任务挂起时,知道最后任务的完成时间很重要,更好的是任务的心跳。
- Batch jobs批处理。批处理和离线处理有时候有点混淆,因为离线处理有时候用批处理实现。批处理的关键特点是非连续性,所以很难抓取有效的指标。关键指标是最后成功的时间和结果(错误码),采集每个主要阶段的耗时也很重要。应该推送给PushGateway。任务级别的统计数据也很重要,比如处理的记录数。对于长时间运行的任务,基于pull的监控也很重要,可以度量系统的资源变化。对于频繁运行的批处理任务,比如每15分钟执行一次,转成离线处理服务会更好。
除了这几种类型的系统,还有一些系统的部分可以采集Metric:
- Libraries 库的指标采集,应该不需要用户配置。
- Logging 日志的指标,应该有个总的日志数,对于某个特别的日志应该看它的频率和耗时,对于函数的某些分支也可以采集,统计不同级别的日志数量也挺有用的。
- Failures 错误,和日志类似应该采集总数。以及总请求数,这样比较容易计算错误率。
- Threadpools 线程池,关键指标是排队的请求数,活跃的线程数,总线程数,处理的任务和耗时,队列的等待耗时也很有用。
- Cache 缓存,关键指标是总查询数,命中数目,延迟,错误数。
- Collectors Prometheus的Collector,采集的耗时和错误次数。这里建议用gauge而不是histogram,另外一个用gauge的例子是批处理的耗时,这是因为它们度量的是每次的推送或抓取,而不是分散的多个耗时。
到底该用哪种类型的指标:
- Counter vs Gauge:能变小的是Gauge,比如占用内存大小。
- Counter是递增的,直到进程重启会被Reset,比如处理的总请求数、总错误数、发送的总字节数。一般Counter很少能直接使用,是需要函数处理比如rate或做其他处理。
- Gauge的值可以被设置,可以变大变小,一般是状态的快照,比如处理中的请求数,可用的内存大小,温度等,对于gauge永远不要用rate函数。
- Summary和Histogram比较难,用得也比较少,大概是统计分布,比如耗时的分布,暂时没仔细看。
PromQL: Counter
Prometheus有自己的查询语句,对于Counter的例子。
比如节点的CPU执行时间,就是Counter单增的量。可以看到,这些数据就是CPU的时间片统计,会不断递增。输入下面的语句:
node_cpu_seconds_total
可以看到各个CPU,以及不同的mode的数据,我们过滤选择第0个CPU,以及mode为user。这时候过滤出来的是CPU0的user的累计时间片:
node_cpu_seconds_total{cpu="0",mode="user"}
我们可以用rate函数计算增量的变化率,也就是user的增量的随时间的变化:
rate(node_cpu_seconds_total{cpu="0",mode="user"}[10s])
-
rate(node_cpu_seconds_total{cpu="0",mode="user"}[10s])
返回0.162
-
increase(node_cpu_seconds_total{cpu="0",mode="user"}[10s])
返回1.62
可以看到1.62 / 10s = 0.162
,也就是rate=increase/duration
,取的是增量和时间的比。
Note: 注意如果采样是1m,那么时间范围就不能小于1m,否则会出现
Empty query result
。
PromQL: CPU percent
计算CPU的百分比,原始数据是CPU时间,可以先计算idle时间比例:
rate(node_cpu_seconds_total{mode="idle"}[30s])
然后将多个CPU的取最小值,注意rate要再加个括号:
min by(mode) (rate(node_cpu_seconds_total{mode="idle"}[30s]))
然后将idle换成usage,也就是:
1 - min by(mode) (rate(node_cpu_seconds_total{mode="idle"}[30s]))
再乘以100,就是100%了:
(1 - min by(mode) (rate(node_cpu_seconds_total{mode="idle"}[30s]))) * 100
PromQL: min by
取最小值时,取的是每个样本的最小值,比如两个CPU,如果取idle最小的,那是取每个样本最小的,相当于取最繁忙的那个值。
可以写个bash的死循环:
cat << END > min_by.sh
for ((;;)); do echo "" >/dev/null; done
END
启动这个程序:
bash min_by.sh
然后用绑定CPU方式测试,先绑定到0,然后切到1:
taskset -pc 0 $(ps aux|grep min_by.sh|grep bash|awk '{print $2}')
看两个CPU的图,明显发现有交换:
而用min by(mode)后,总是取idle最小的值了,这也就是系统忙的CPU图了:
若是min by(cpu),则是按cpu分组。
node_load1 // vector A
* // 操作符 A.value * B.value,由于 B.value=1,我们保持A的值不变,所以用的乘
on(instance) // JOIN on 用instance来join两个vector,A.instance==B.instance
group_left(sysname) // 保留B的字段, 相当于 SELECT A.*, B. sysname
node_uname_info // vector B
PromQL: Regex Match
可以选择两个CPU,用cpu=~"[01]"
:
(1-rate(node_cpu_seconds_total{cpu=~"[01]",mode="idle"}[30s]))*100
这就是正则表达式匹配了。
PromQL: on
一对一的vector匹配,将vector变换成一组,参考:One-to-one vector matches
启动两个node:
docker run --rm -it -p 9101:9100 prom/node-exporter
docker run --rm -it -p 9102:9100 prom/node-exporter
然后,配置Prometheus,抓取配置:
scrape_configs:
- job_name: "node1"
metrics_path: "/metrics"
scrape_interval: 5s
static_configs:
- targets: ["host.docker.internal:9101"]
- job_name: "node2"
metrics_path: "/metrics"
scrape_interval: 5s
static_configs:
- targets: ["host.docker.internal:9102"]
启动Prometheus:
docker run --rm -v `pwd`/prometheus.yml:/etc/prometheus/prometheus.yml \
-p 9090:9090 prom/prometheus
查看CPU的user数据:
node_cpu_seconds_total{cpu="0",mode="user"}
node_cpu_seconds_total{instance="host.docker.internal:9101"} 503.27
node_cpu_seconds_total{instance="host.docker.internal:9102"} 503.27
查看CPU的system的数据:
node_cpu_seconds_total{cpu="0",mode="system"}
node_cpu_seconds_total{instance="host.docker.internal:9101"} 336.28
node_cpu_seconds_total{instance="host.docker.internal:9102"} 336.28
我们可以按instance来直接匹配两个vector,让他们相除,得到system/user的比例:
node_cpu_seconds_total{cpu="0",mode="system"} / on(instance) node_cpu_seconds_total{cpu="0",mode="user"}
{instance="host.docker.internal:9101"} 0.6681900371569932
{instance="host.docker.internal:9102"} 0.6681900371569932
如果不指定on,由于这两个数据集有很多不同的标签,所以不知道如何一对一的匹配数据,也当然不知道如何操作。
PromQL: group_left
多对一的vector匹配,参考:Many-to-one and one-to-many vector matches
首先,需要启动多个node_exporter,一个Darwin,两个Linux,可以用docker启动:
./node_exporter-1.3.1.darwin-amd64/node_exporter
docker run --rm -it -p 9101:9100 prom/node-exporter
docker run --rm -it -p 9102:9100 prom/node-exporter
然后,配置Prometheus,抓取配置:
scrape_configs:
- job_name: "node0"
metrics_path: "/metrics"
scrape_interval: 5s
static_configs:
- targets: ["host.docker.internal:9100"]
- job_name: "node1"
metrics_path: "/metrics"
scrape_interval: 5s
static_configs:
- targets: ["host.docker.internal:9101"]
- job_name: "node2"
metrics_path: "/metrics"
scrape_interval: 5s
static_configs:
- targets: ["host.docker.internal:9102"]
启动Prometheus:
docker run --rm -v `pwd`/prometheus.yml:/etc/prometheus/prometheus.yml \
-p 9090:9090 prom/prometheus
查看负载数据:
node_load1
node_load1{instance="host.docker.internal:9100"} 3.15283203125
node_load1{instance="host.docker.internal:9101"} 0.7
node_load1{instance="host.docker.internal:9102"} 0.64
查看节点的信息数据:
node_uname_info
node_uname_info{instance="host.docker.internal:9100", sysname="Darwin"} 1
node_uname_info{instance="host.docker.internal:9101", sysname="Linux"} 1
node_uname_info{instance="host.docker.internal:9102", sysname="Linux"} 1
如果我们要按Linux和Darwin分组数据,就需要Join这两个数据集了。可以用instance来关联,达到根据sysname来分组数据的目的:
node_load1 * on(instance) group_left(sysname) node_uname_info
{instance="host.docker.internal:9100", sysname="Darwin"} 3.15283203125
{instance="host.docker.internal:9101", sysname="Linux"} 0.7
{instance="host.docker.internal:9102", sysname="Linux"} 0.64
分析这个语句:
node_load1 // vector A
* // 操作符 A.value * B.value,由于 B.value=1,我们保持A的值不变,所以用的乘
on(instance) // JOIN on 用instance来join两个vector,A.instance==B.instance
group_left(sysname) // 保留B的字段, 相当于 SELECT A.*, B. sysname
node_uname_info // vector B
如果更熟悉SQL,等价于SQL:
SELECT A.*, B.sysname, A.value*B.value FROM node_load1 as A
join node_name_info B on A.instance=B.instance
Note: 不同于SQL的是,由于Prometheus的数据集是时序的vector而不是table,而且肯定是对两个数据集的数据进行操作,所以Prometheus定义的操作符用来操作两个vector。
最后,我们按照sysname分组Join之后的数据:
sum by(sysname) (node_load1 * on(instance) group_left(sysname) node_uname_info)
{sysname="Darwin"} 2.5068359375
{sysname="Linux"} 0.29000000000000004
如果需要对结果算rate,不应该对最终结果算rate,应该先算rate后,再做group_left和sum。因为rate实际上是一个expr表达式,是可以对两个expr做group_left的。
PromQL: Join Custom Metrics
参考How to join Prometheus metrics by label with PromQL
参考How to have labels for machine roles
首先,我们先生成两个目录,放两个文件,给node_exporter抓取:
mkdir node1 node2
echo 'machine_role{role="apache"} 1' > node1/roles.prom
echo 'machine_role{role="postfix"} 1' > node2/roles.prom
接着,需要启动两个node_exporter,这样有两个不同的机器,可以用docker启动:
docker run --rm -it -p 9101:9100 -v $(pwd):/data -w /data \
prom/node-exporter --collector.textfile.directory node1
docker run --rm -it -p 9102:9100 -v $(pwd):/data -w /data \
prom/node-exporter --collector.textfile.directory node2
然后,配置Prometheus,抓取配置:
scrape_configs:
- job_name: "node1"
metrics_path: "/metrics"
scrape_interval: 5s
static_configs:
- targets: ["host.docker.internal:9101"]
- job_name: "node2"
metrics_path: "/metrics"
scrape_interval: 5s
static_configs:
- targets: ["host.docker.internal:9102"]
启动Prometheus:
docker run --rm -v `pwd`/prometheus.yml:/etc/prometheus/prometheus.yml \
-p 9090:9090 prom/prometheus
查看负载:
node_network_receive_bytes_total{device="eth0"}
node_network_transmit_bytes_total{instance="host.docker.internal:9101"} 15375606
node_network_transmit_bytes_total{instance="host.docker.internal:9102"} 723864
查看我们打的role的标签:
machine_role
machine_role{job="node0", role="apache"} 1
machine_role{job="node1", role="postfix"} 1
可见我们有了这两组数据,可以用job来关联,达到根据role来筛选数据的目的:
node_network_transmit_bytes_total{device="eth0"} * on(instance) group_left(role) machine_role
{instance="host.docker.internal:9101", role="apache"} 15698720
{instance="host.docker.internal:9102", role="postfix"} 735344
分析这个语句:
node_network_transmit_bytes_total{device="eth0"} // vector A
* // 操作符 A.value * B.value,由于 B.value=1,我们保持A的值不变,所以用的乘
on(instance) // JOIN on 用job来join两个vector,A. instance ==B.instance
group_left(role) // 保留B的字段, 相当于 SELECT A.*, B.role
machine_role // vector B
后续就可以按照role聚合了。
PromQL: Embed group_left
可以对指标进行多次JOIN,配置参考前一章PromQL: Join Custom Metrics
。
我们使用load数据:
node_load1
node_load1{instance="internal:9101"} 0.27
node_load1{instance="internal:9102"} 0.27
先让它和uname联合一次,加上nodename:
node_load1 * on(instance) group_left(nodename) node_uname_info
{instance="internal:9101", nodename="84270dfcb37f"} 0.27
{instance="internal:9102", nodename="0ac4874101bd"} 0.27
然后再和machine_role联合一次,加上role:
(node_load1 * on(instance) group_left(nodename) node_uname_info) * on(instance) group_left(role) machine_role
{instance="internal:9101", nodename="84270dfcb37f", role="apache"} 0.51
{instance="internal:9102", nodename="0ac4874101bd", role="postfix"} 0.51
这样相当于给每个数据点加上了这两个标签了,然后再根据加上的标签,进行分组聚合。
网友评论