Prometheus笔记

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"}

度量类型:

  • Counter:单调递增的类型,比如总人数。
  • Gauge:可增加可减少的数字,比如CPU使用率。
  • 还有Histogram和Summary,和时长以及窗口相关,没仔细看。

任务和实例:

  • 抓取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,相关资料如下:

Grafana也列出了一些Exporter,可以看到示例数据:

The USE Method

参考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

这样相当于给每个数据点加上了这两个标签了,然后再根据加上的标签,进行分组聚合。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容