简介
Prometheus是由SoundCloud在2012年开源的一个用于监控与报警的组件,主要用于采集、存储和查询指标(Metrics)时间序列(Time Series)。在2016年,Prometheus继Kubernetes之后成为第二个加入CNCF的项目。
Prometheus的主要特性如下:
- 基于指标名称与标签构建了多维度的时间序列数据模型
- 提供PromQL,能够灵活地查询多维数据。
- 不依赖分布式存储;单server自洽。
- 通过基于Http的拉(Pull)模式进行数据采集
- 通过间接的网关也能够实现推(Push)模式数据采集
- 支持静态配置服务发现机制来实现采集
- 支持多种图标和仪表盘
在进一步了解Prometheus之前,首先需要大致了解下指标(Metrics)和时间序列(Time Series)是什么。简单地说,指标就是一类数据,而时间序列就是指标随着时间产生变化的集合。在现实世界中我们也有指标,假设气象局每隔1个小时测量一次温度并记录,于是我们便有了温度这一个指标,并且由间隔为1小时的温度时间序列。
换到我们的计算机世界,指标可以是cpu的占用率,时间序列是我们每间隔一段时间采集的占用率的集合。可以是以下形式 cpu占用率 ∈ {(t_0,v_0)... (t_i,v_i)},其中t表示时间戳,v表示值。
对于一个监控系统而言,指标和时间序列就是核心,通过这两个值,我们能够对程序/系统的运行状态,根据时间维度进行观测。
核心组件
整个Prometheus生态包含多个组件,除了Prometheus server组件其余都是可选的
- Prometheus Server:主要的核心组件,用来收集和存储时间序列数据。
- Client Library: :客户端库,为需要监控的服务生成相应的 metrics 并暴露给 Prometheus server。当 Prometheus server 来 pull 时,直接返回实时状态的 metrics。
- push gateway:主要用于短期的 jobs。由于这类 jobs 存在时间较短,可能在 Prometheus 来 pull 之前就消失了。为此,这次 jobs 可以直接向 Prometheus server 端推送它们的 metrics。这种方式主要用于服务层面的 metrics,对于机器层面的 metrices,需要使用 node exporter。
- Exporters: 用于暴露已有的第三方服务的 metrics 给 Prometheus。
- Alertmanager: 从 Prometheus server 端接收到 alerts 后,会进行去除重复数据,分组,并路由到对收的接受方式,发出报警。常见的接收方式有:电子邮件,pagerduty,OpsGenie, webhook 等。
架构
上图是Prometheus的架构,由以下几个模块构成
- Prometheus Server:服务端,负责周期性采集、存储指标,也为外部服务提供查询服务。
-
- Retrieval: 周期性地去暴露的endpoint上采集指标
- TSDB:Time Series Database,Prometheus自研的时序数据库
- Http Server:prometheus提供的http服务端
- Pushgateway:一个中间网关,负责将指标暂存,后续提供给server端采集。一般配合一些短期的job进行使用,原因在于短期的job的生命周期可能还没等到Retrieval进行采集就结束了。
- PromQL:Prometheus提供的查询语句服务端,能够配合如prometheus前端、grafana等ui界面查询。
- Alertmanager:负责将告警信息通知到三方的消息渠道,通过在Prometheus server上配置告警规则,server会将告警时间推送到Altermanager。
- Service Discovery:是指 Prometheus 可以动态的发现一些服务,拉取数据进行监控,如从DNS,Kubernetes,Consul 中发现, file_sd 是静态配置的文件。
- UI:Prometheus也提供了前端访问的服务,能够绘制一些简单的图标,当然也可以接入Grafana来获得更强大、美观的图表展示。
实战1-SpringCloudGateway自定义指标
Talk is cheap,show me the code.
下面以如何在SpringCloudGateway为案例,看下在真实项目中如何自定义采集指标
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.7.10</version>
</parent>
<properties>
<java.version>8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-cloud.version>3.1.5</spring-cloud.version>
<micrometer.version>1.10.4</micrometer.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
<version>${spring-cloud.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>${micrometer.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>${spring-cloud.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
主要引入依赖有
<dependency>
// 暴露指标的endpoint
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
// 指标采集
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
springboot的application.yaml如下,仅配置了一条路由,前缀是/httpbin。同时暴露了actuator的端口,开放了promethues的endpoint。
server:
port: 8080
spring:
jmx:
enabled: false
cloud:
gateway:
routes:
- id: httpbin
uri: http://httpbin.org
order: 1
filters:
- StripPrefix=1
predicates:
- Path=/httpbin/**
management:
server:
port: 8108
endpoints:
enabled-by-default: false
web:
exposure:
include: '*'
endpoint:
prometheus:
cache:
time-to-live: 1
enabled: true
记录指标的GlobalFilter
package com.xiaoyu.filter;
import io.micrometer.core.instrument.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.AbstractServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
/**
* @author chy
* @description
* @date 2024/8/13
*/
@Component
public class CustomMetricFilter implements GlobalFilter, Ordered {
@Autowired
private MeterRegistry meterRegistry;
private static final String METRICS_PREFIX = "test";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 记录开始时间
Timer.Sample sample = Timer.start(this.meterRegistry);
return chain.filter(exchange).doOnSuccess((aVoid) -> {
this.onSuccess(exchange, sample);
}).doOnError((throwable) -> {
this.onError(exchange, sample);
});
}
private void onSuccess(ServerWebExchange exchange, Timer.Sample start) {
record(exchange, start);
}
private void onError(ServerWebExchange exchange, Timer.Sample start) {
ServerHttpResponse response = exchange.getResponse();
if (response.isCommitted()) {
record(exchange, start);
} else {
response.beforeCommit(() -> {
record(exchange, start);
return Mono.empty();
});
}
}
private void record(ServerWebExchange exchange, Timer.Sample sample) {
// 组成tag
Tags tags = getTags(exchange);
Timer timer = Metrics.timer(METRICS_PREFIX, tags);
long duration = sample.stop(timer);
Metrics.counter(METRICS_PREFIX + ".count", tags).increment();
DistributionSummary ds = DistributionSummary.builder(METRICS_PREFIX + ".summary")
.tags(tags)
.publishPercentiles(0.5, 0.90, 0.95, 0.99)
.serviceLevelObjectives(Duration.ofMillis(50).toNanos(),
Duration.ofMillis(100).toNanos(),
Duration.ofMillis(200).toNanos(),
Duration.ofMillis(400).toNanos(),
Duration.ofMillis(800).toNanos(),
Duration.ofMillis(1600).toNanos(),
Duration.ofMillis(3200).toNanos(),
Duration.ofMillis(6400).toNanos()
)
.minimumExpectedValue((double) Duration.ofMillis(1).toNanos())
.maximumExpectedValue((double) Duration.ofSeconds(7).toNanos())
.register(meterRegistry);
ds.record(duration);
Timer timer2 = Timer.builder(METRICS_PREFIX + ".timer.histogram")
.tags(tags)
.publishPercentiles(0.5, 0.90, 0.95, 0.99)
.serviceLevelObjectives(Duration.ofMillis(10),
Duration.ofMillis(20),
Duration.ofMillis(50),
Duration.ofMillis(100),
Duration.ofMillis(150),
Duration.ofMillis(200),
Duration.ofMillis(250),
Duration.ofMillis(300),
Duration.ofMillis(350),
Duration.ofMillis(400),
Duration.ofMillis(450),
Duration.ofMillis(500),
Duration.ofMillis(600),
Duration.ofMillis(700),
Duration.ofMillis(800),
Duration.ofMillis(900),
Duration.ofMillis(1000),
Duration.ofMillis(1250),
Duration.ofMillis(1500),
Duration.ofMillis(1750),
Duration.ofSeconds(10)
)
.minimumExpectedValue(Duration.ofMillis(1))
.maximumExpectedValue(Duration.ofSeconds(10))
.register(meterRegistry);
timer2.record(duration, TimeUnit.NANOSECONDS);
}
private Tags getTags(ServerWebExchange exchange) {
String outcome = "CUSTOM";
String status = "CUSTOM";
String httpStatusCodeStr = "NA";
String httpMethod = exchange.getRequest().getMethod().name();
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
if (exchange.getResponse() instanceof AbstractServerHttpResponse) {
Integer statusInt = ((AbstractServerHttpResponse) exchange.getResponse()).getStatusCodeValue();
status = String.valueOf(statusInt);
httpStatusCodeStr = status;
HttpStatus resolved = HttpStatus.resolve(statusInt);
if (resolved != null) {
outcome = resolved.series().name();
status = resolved.name();
}
} else {
HttpStatus statusCode = exchange.getResponse().getStatusCode();
if (statusCode != null) {
httpStatusCodeStr = String.valueOf(statusCode.value());
HttpStatus resolved = HttpStatus.resolve(statusCode.value());
outcome = resolved.series().name();
status = resolved.name();
}
}
return Tags.of("outcome", outcome, "status", status, "httpStatusCode", httpStatusCodeStr,
"httpMethod", httpMethod, "routeId", route.getId());
}
@Override
public int getOrder() {
return -1;
}
}
这里暂且不对指标的记录细节详细描述,简单看下最终的效果。
先本地访问下/httpbin/get接口,然后在浏览器访问localhost:8108/actuator/prometheus
可以看到自己定义的指标(test开头)已经有数据了,恭喜你成功暴露了prometheus标准的指标。
核心概念
指标(Metric)
"Prometheus中一共有四种Metric",为什么这句话打了一个引号呢,因为这四种类型是在Prometheus客户端中划分的。实际上在Prometheus Server看来,所有的时间序列指标都是相同的。客户端进行划分也是为了方便我们使用与理解。
- Counter
- Gauge
- Histogram
- Summary
先来看下一个Prometheus的指标如何表示
<metric name>{<label name>=<label value>, ...}
更具体的案例如
api_http_requests_total{method="POST", handler="/messages"}
// 指标名称为 api_http_requests_total
// 有两个标签 method、handler
Tips:实际上metric_name也是一个特殊的label,prometheus会默认为指标创建一个__name__=‘metric_name’的label,这和prometheus的存储索引设计有点关系,这里先不细究。
Counter
Counter,英译中为计数器,实际上Counter也是一个累加值,一个counter要被被重置为0,要么一直累加。一般情况下,Counter可以被用来统计比如http请求总数、任务完成数或者错误数量。
虽然Counter的api在累加时,能够加上一个负数,但是官方不推荐你这样使用,如果想要记录一个浮动的数目,可以使用Gauge。
Gauge
Gauge,英译中为仪表盘、尺度,在Prometheus中Gauge被用于表示一个浮动的指标。在实际运用中,Gauge可以用于表示如当前并发的任务数,当前并发的请求数,又或者是当前活跃的实例数量。
Histogram
Histogram,英译中为直方图/柱状图。一般用于记录请求耗时、请求大小等数据。在使用该指标时候,需要指定桶的数据上限。如下代码块中记录了一个Histogram指标,并对duration进行了记录。在serviceLevelObjectives方法也就是第4到12行中,指定了桶的大小和范围。
比如当duration为90ms时,将会落入Duration.ofMillis(100)、Duration.ofMillis(150)、Duration.ofMillis(200)、... 、Duration.ofSeconds(10)桶中。
Timer timer2 = Timer.builder(METRICS_PREFIX + ".timer.histogram")
.tags(tags)
.publishPercentiles(0.5, 0.90, 0.95, 0.99)
.serviceLevelObjectives(Duration.ofMillis(10),
Duration.ofMillis(20),
Duration.ofMillis(50),
Duration.ofMillis(100),
Duration.ofMillis(150),
Duration.ofMillis(200),
// ...
Duration.ofSeconds(10)
)
.minimumExpectedValue(Duration.ofMillis(1))
.maximumExpectedValue(Duration.ofSeconds(10))
.register(meterRegistry);
timer2.record(duration, TimeUnit.NANOSECONDS);
Histogram延伸出了三个指标
- metric_name_bucket{le=""}
小于桶上限大小的记录个数
- metric_name_sum
累计总和,假设Histogram记录的是请求耗时,那么这个指标的含义就是所有请求耗时的和。
- metric_name_count
总共的记录数量,假设Histogram记录的是请求耗时,那么这个指标的含义就是请求总数。
使用histogram_quantile()函数能够从直方图聚合中计算分位数。比如P99、P95等
Summary
Summary(摘要)呈现的效果与Histogram类似,同样也有三个延伸的指标
- metric_name{quantile="<φ>"}
这边表示分位数,具体见quantile的值。
- metric_name_sum
与Histogram的一样
- metric_count
与Histogram的一样
这里可能有些疑问,为什么有Histogram了还要有Summary。
在询问ChatGPT后得到了如下的解答
在Prometheus中,Histogram和Summary都是用于收集和处理度量数据的聚合类型,但它们的用法和特性有所不同。以下是对这两种指标的详细解释:
Histogram
定义:Histogram用于统计和分布数据的一个集合。它将值分成多个桶(buckets),每个桶代表一个值的范围。每个桶都有一个计数器,用于记录落在该范围内的事件数量。
用途:
适合于高维度数据的统计。
可以用于计算数据的分布情况(如响应时间的分布)。
可以计算请求的百分位数,但不如Summary精确。
工作原理:
你可以定义一些桶大小,比如: [0.1, 0.2, 0.5, 1.0, 2.0]。
这会生成统计每个桶内的计数,比如有多少个请求的响应时间在0.1秒以下,有多少在0.2秒以下等等。
提供总的请求计数和累积的直方图值(将所有小于等于当前桶值的计数相加)。
优缺点:
优点:可以根据桶的划分得到较好的数据分布视图。
缺点:在真实应用中只能估算百分位数。
Summary
定义:Summary也用于处理和统计数值数据。它记录观察值的总计(总和)和数量,并且提供了计算特定时间窗口内的分位数(如p50、p90、p99等)。
用途:
适合需要实时精确计算分位数的情况。
比如需要了解请求响应时间的特定百分位数。
工作原理:
Summary在客户端会维护一个队列来存储样本,以便在上报时计算出分位数。
可以直接获取特定的分位数值(如0.5, 0.9, 0.99等)。
优缺点:
优点:能够精确地计算分位数,适合小样本数据。
缺点:由于在处理时需要维护状态,因此生成的样本会消耗更多的内存和计算资源,而且数据不能用于跨实例的聚合。
总结
选择Histogram:当你希望在各个实例之间聚合数据并能大致了解分布情况时,可以选择Histogram。它更适用于高流量,具有大量实例的服务。
选择Summary:当你需要精确的分位数计算且不需要在多个实例之间聚合时,Summary可能是更好的选择。
根据具体的使用场景和需求,可以选择最适合的指标类型。
以下是Summary与Histogram的详细对比
| Summary | Histogram | |
|---|---|---|
| 配置 | 分位数和滑动窗口 | 区间配置(桶区间) |
| 客户端性能 | 需要流式计算代价大 | 只需要增加bucket,代价小 |
| 服务端性能 | 直接读取,无需计算 | 需要计算分位数,代价高 |
| 精度 | 与分位数设置有关 | 与bucket的数量划分有关 |
| 聚合 | 一般无法聚合 | 可以聚合 |
Job和实例
在Prometheus中对一系列相同服务实例的采集行为称之为Job,一个job的表现形式如下:
JobName:scrap_some_service
instance1: ip1:port1
instance2: ip2:port2
表示配置了一个job名称为scrap_some_service,采集了两个实例,地址分别为 ip1:port1,ip2:port2。
特别的,对于被采集的指标都会包含一个label
metric_name{job=''...}
如何配置一个job,可查看Configuration | Prometheus
查询
基本查询
瞬时值查询
直接输入指标名称即可查询,即可查询所有为名称的指标的瞬时值。
metric_name
比如输入 prometheus_http_requests_total 即可查询全部名称为promehteus_http_requests_total的指标
也可以通过label对指标进行过滤,label的过滤有以下四种方式
- =:标签值等于指定值
- !=:标签不等于指定值
- ~=: 标签值等于某正则表达式
- !~: 标签值不等于某正则表达式
范围值查询
prometheus支持按照时间范围查询指标,查询语法如下
metric_name{}[time_range]
time range的单位如下
ms- millisecondss- secondsm- minutesh- hoursd- days - assuming a day always has 24hw- weeks - assuming a week always has 7dy- years - assuming a year always has 365d1
如以下查询语句,会返回过去1小时30分中apiserver_request_duration_seconds_count指标的所有时间序列。
偏移查询
prometheus也支持单独查询某一刻的历史数据,语法如下
metric_name offset time
这里的time的语法与上一节time range的语法一致。
更多查询
关于更多查询的语法,可见Operators | Prometheus,本文不做赘述。
存储设计
关于这块我自认为不能比
这篇文章讲的更加清楚。
实战2-serviceMonitor配置采集
在k8s中,我们可以通过serviceMonitor这个cr来配置prometheus的采集规则。一个典型的serviceMonitor的定义如下
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: test-service-monitor
spec:
// 指定采集pod的端口,接口,以及采集间隔
endpoints:
- interval: 30s
path: /actuator/prometheus
port: monitor
// 指定作用明明空间
namespaceSelector:
any: true
// 只有匹配到如下label的pod才会被采集
selector:
matchLabels:
micrometer-prometheus-discovery: 'true'
完成配置后,可在prometheus的前端页面查看已经被prometheus感知的serviceMonitor
当然也可以通过查询语句,查看相关的指标是否被prometheus采集了,来确认serviceMonitor是否生效。
内存占用异常
在k8s中部署了prometheus一段时间后,运维同事反应prometheus的pod内存占用异常,达到了惊人的40G。
使用如下命令可以查看prometheus的内存分布,可以看到实际上程序的内存占用为10GB,另外30GB来自于prometheus的mmap,在查询历史chunk中的数据时,prometheus会将历史数据通过mmap映射到内存。
go tool pprof -symbolize=remote -inuse_space https://monitoring.prod.cloud.coveo.com/debug/pprof/heap
在如下内存分布中label所使用的内存占用了1GB左右,而一个head才1.8GB左右,这提示我们label的差异性可能比较大,可能存在相同key的label,value的值特别多。
File: prometheus
Type: inuse_space
Time: Apr 24, 2019 at 4:20pm (CEST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 8839.83MB, 84.87% of 10415.77MB total
Dropped 398 nodes (cum <= 52.08MB)
Showing top 10 nodes out of 64
flat flat% sum% cum cum%
1628.82MB 15.64% 15.64% 1628.82MB 15.64% github.com/prometheus/tsdb/index.(*decbuf).uvarintStr /app/vendor/github.com/prometheus/tsdb/index/encoding_helpers.go
1233.86MB 11.85% 27.48% 1234.86MB 11.86% github.com/prometheus/prometheus/pkg/textparse.(*PromParser).Metric /app/pkg/textparse/promparse.go
1199.99MB 11.52% 39.00% 1199.99MB 11.52% github.com/prometheus/tsdb.seriesHashmap.set /app/vendor/github.com/prometheus/tsdb/head.go
1186.88MB 11.40% 50.40% 1186.88MB 11.40% github.com/prometheus/prometheus/pkg/labels.(*Builder).Labels /app/pkg/labels/labels.go
987.60MB 9.48% 59.88% 987.60MB 9.48% github.com/prometheus/tsdb/chunkenc.NewXORChunk /app/vendor/github.com/prometheus/tsdb/chunkenc/xor.go
836.65MB 8.03% 67.91% 836.65MB 8.03% github.com/prometheus/tsdb.newMemSeries /app/vendor/github.com/prometheus/tsdb/head.go
650.21MB 6.24% 74.16% 1850.20MB 17.76% github.com/prometheus/tsdb.(*stripeSeries).getOrSet /app/vendor/github.com/prometheus/tsdb/head.go
450.52MB 4.33% 78.48% 450.52MB 4.33% github.com/prometheus/tsdb/index.newReader.func2 /app/vendor/github.com/prometheus/tsdb/index/index.go
360.78MB 3.46% 81.95% 360.78MB 3.46% github.com/prometheus/tsdb/index.(*MemPostings).Delete /app/vendor/github.com/prometheus/tsdb/index/postings.go
304.51MB 2.92% 84.87% 304.51MB 2.92% github.com/prometheus/tsdb.(*decbuf).uvarintStr /app/vendor/github.com/prometheus/tsdb/encoding_helpers.go
prometheus提供一个tsdb的分析工具,方便我们查看chunk中数据的分布。如下链接可以下载到该分析工具。
https://github.com/prometheus/prometheus/releases/download/v2.13.0/prometheus-2.13.0.linux-amd64.tar.gz
解压后得到目录如下
执行解析命令,其中需要指定下查看的block文件的路径
./tsdb analyze path/to/some/prometheus/datadir | less
可以看到kueblet的指标占了大头,而kubelet是默认采集与暴露的。此外在label中,还能够看到key为id的label数量非常多,而在我们的业务大盘中并没有使用该label。
Block path: /prometheus/prometheus-db/01D9CMTKZAB0R8T4EM95PKXKQ6
Duration: 2h0m0s
Series: 5547383
Label names: 248
Postings (unique label pairs): 159621
Postings entries (total label pairs): 44259261
Label pairs most involved in churning:
4424281 job=kubelet
4424281 service=monitoring-prometheus-oper-kubelet
4417556 endpoint=cadvisor
1154707 __name__=container_network_tcp_usage_total
524866 __name__=container_tasks_state
419893 __name__=container_memory_failures_total
419893 __name__=container_network_udp_usage_total
209946 scope=hierarchy
209946 type=pgfault
209946 scope=container
209946 type=pgmajfault
124554 node=ip-10-1-28-104.ec2.internal
124547 instance=10.1.28.104:4194
123625 node=ip-10-1-31-50.ec2.internal
123619 instance=10.1.31.50:4194
123535 node=ip-10-1-24-105.ec2.internal
123528 instance=10.1.24.105:4194
123455 node=ip-10-1-26-91.ec2.internal
123449 instance=10.1.26.91:4194
122999 node=ip-10-1-30-66.ec2.internal
122992 instance=10.1.30.66:4194
Label names most involved in churning:
4448288 __name__
4448286 service
4448286 job
4448280 instance
4448280 endpoint
4425365 node
4417169 id
1154707 tcp_state
524867 state
420440 type
419951 scope
419893 udp_state
61127 namespace
54746 device
53712 cpu
30180 image
30111 name
29976 pod_name
29976 container_name
23829 pod
11653 interface
Most common label pairs:
5230403 job=kubelet
5230403 service=monitoring-prometheus-oper-kubelet
5181993 endpoint=cadvisor
1332991 __name__=container_network_tcp_usage_total
605905 __name__=container_tasks_state
484724 __name__=container_network_udp_usage_total
484724 __name__=container_memory_failures_total
242362 type=pgfault
242362 scope=hierarchy
242362 scope=container
242362 type=pgmajfault
198766 endpoint=http
178005 namespace=infrastructure
137297 namespace=monitoring
135105 node=ip-10-1-28-104.ec2.internal
134282 instance=10.1.28.104:4194
133879 node=ip-10-1-24-105.ec2.internal
133623 node=ip-10-1-26-91.ec2.internal
133602 node=ip-10-1-31-50.ec2.internal
133540 node=ip-10-1-21-53.ec2.internal
133170 node=ip-10-1-28-252.ec2.internal
Highest cardinality labels:
116525 id
19148 type
4794 queue
3655 mountpoint
2926 __name__
2323 name
1073 container_id
956 exported_pod
949 pod_name
747 pod_ip
697 device
678 interface
657 instance
523 pod
286 replicaset
205 url
176 instance_type
173 le
146 image
133 address
90 container
Highest cardinality metric names:
1332991 container_network_tcp_usage_total
605905 container_tasks_state
484724 container_memory_failures_total
484724 container_network_udp_usage_total
121181 container_memory_swap
121181 container_start_time_seconds
121181 container_memory_rss
121181 container_memory_usage_bytes
121181 container_memory_working_set_bytes
121181 container_memory_failcnt
121181 container_memory_max_usage_bytes
121181 container_memory_cache
121181 container_last_seen
121181 container_cpu_user_seconds_total
121181 container_cpu_system_seconds_total
121181 container_cpu_load_average_10s
121173 container_spec_cpu_period
121173 container_spec_cpu_shares
120963 container_spec_memory_limit_bytes
120963 container_spec_memory_swap_limit_bytes
120963 container_spec_memory_reservation_limit_bytes
在后续的处理中,通过配置 <metric_relabel_confis> 将id drop掉
经过如此操作后,prometheus的内存占用从40GB降低到了8GB