概述
不久前,咱们在文章《如何扩大单个Prometheus实现近万Kubernetes集群监控?》中具体介绍了TKE团队大规模Kubernetes联邦监控零碎Kvass的演进过程,其中介绍了针对规模较大的集群,咱们是如何通过批改Prometheus代码来实现横向扩缩容的。通过计划上的改良,Kvass目前曾经反对以Sidecar的形式实现Prometheus集群化,而不是批改Prometheus代码。因为计划对社区有肯定价值,团队决定将我的项目开源进去,分享给社区。我的项目地址
本文首先将给出Prometheus的单机性能瓶颈,以及现有的社区集群化计划,随后将具体介绍开源版Kvass的设计思维,应用案例及压测后果。
另外,腾讯云容器团队在Kvass的设计思维上进一步优化,构建了反对多集群的高性能云原生监控服务,产品目前已正式公测,欢送读者试用。传送门: https://console.cloud.tencent...
后续章节咱们也将间接应用该产品来展现Kvass对大规模集群的监控能力。
Prometheus
Prometheus依附其强劲的单机性能,灵便的PromSQL,沉闷的社区生态,逐步成为云原生时代最外围的监控组件,被寰球各大产商用于监控他们的外围业务。
然而,面对大规模监控指标(数千万series)时,因为原生Prometheus只有单机版本,不提供集群化性能,开发人员不得不通过一直减少机器的配置来满足Prometheus一直上涨的内存。
单机性能瓶颈
咱们对单机Prometheus进行的压测,用以探测单个Prometheus分片的正当负载,压测的指标有两个。
- 确定target数目对Prometheus负载的关系
- 确定series数目和Prometheus负载的关系
target相关性
咱们放弃总series为100万不变, 通过扭转target个数,察看Prometheus负载变动。
压测后果
target数量 | CPU (core) | mem (GB) |
---|---|---|
100 | 0.17 | 4.6 |
500 | 0.19 | 4.2 |
1000 | 0.16 | 3.9 |
5000 | 0.3 | 4.6 |
- 从表中咱们发现target数目的改变对Prometheus负载的影响并不是强相干的。在target数目增长50倍的状况下,CPU耗费有小量增长,然而内存简直不变。
series相关性
咱们放弃target数目不变,通过扭转总series数,察看Prometheus的负载变动。
压测后果
series数量 (万) | CPU (core) | mem (GB) | 查问1000 series 15m数据(s) |
---|---|---|---|
100 | 0.191 | 3.15 | 0.2 |
300 | 0.939 | 20.14 | 1.6 |
500 | 2.026 | 30.57 | 1.5 |
- 从表中,Prometheus的负载受到series的影响较大,series越多,资源耗费越大。
- 当series数据超过300万时,Prometheus内存增长较为显著,须要应用较大内存的机器来运行。
压测过程中,咱们应用了工具去生成预期数目的series,工具生成的series每个label的长度及值的长度都较小,固定为10个字符左右。咱们的目标是察看绝对负载变动,理论生产中因为label长度不同,服务发现机制的耗费不同,雷同的series数目所耗费的负载会比压测中高不少。
现有集群化计划
针对单机Prometheus在大规模数据监控时的性能瓶颈问题,社区目前曾经存在一些分片化计划,次要包含以下几种。
hash_mod
Prometheus官网反对通过Relabel机制,在配置文件中,对采集上来的数据进行hash,通过在不同Prometheus实例的配置文件中指定不同的moduleID来进行分片化,而后通过联邦,Thanos等形式将数据进行对立汇总,如下图所示,读者也能够间接参考【官网文档】。
配置文件宰割
还有一种办法是依据业务进行job层面的宰割,不同Prometheus应用齐全独立的采集配置,其中蕴含了不同的job,。
上述计划存在的问题
无论是hash_mod的形式,还是配置文件宰割的形式,其本质都是将数据切分到多个采集配置中,由不同Prometheus进行采集。两者都存在以下几个毛病。
- 对预监控数据要有所理解:应用上述办法的前提是使用者必须对监控对象会上报的数据有所理解,例如必须晓得监控对象会上报某个用于hash_mod的label,或者必须晓得不同job的整体规模,能力对job进行划分。
- 实例负载不平衡:尽管上述计划预期都是心愿将数据打散到不同Prometheus实例上,但实际上通过某些label的值进行hash_mod的,或者罗唆按job进行划分的形式并不能保障每个实例最终所采集的series数是平衡的,实例仍旧存在内存占用过高的危险。
- 配置文件有侵入:使用者必须对原配置文件进行革新,退出Relabel相干配置,或者将一份配置文件划分成多份,因为配置文件不再繁多,新增,批改配置难度大大增加。
- 无奈动静扩缩容:上述计划中的因为配置是依据理论监控指标的数据规模来非凡制订的,并没有一种对立的扩缩容计划,能够在数据规模增长时减少Prometheus个数。当然,用户如果针对本人业务理论状况编写扩缩容的工具的确是能够的,然而这种形式并不能在不同业务间复用。
- 局部API不再失常:上述计划将数据打散到了不同实例中,而后通过联邦或者Thanos进行汇总,失去全局监控数据,然而在不额定解决的状况下会导致局部Prometheus 原生API无奈失去正确的值,最典型的是/api/v1/targets ,上述计划下无奈失去全局targets值。
Kvass的原理
设计指标
针对上述问题,咱们心愿设计一种无侵入的集群化计划,它对使用者体现进去的,是一个与原生Prometheus配置文件统一,API兼容,可扩缩容的虚构Prometheus。具体而言,咱们有以下设计指标。
- 无侵入,单配置文件:咱们心愿使用者看到的,批改的都是一份原生的配置文件,不必加任何非凡的配置。
- 无需感知监控对象:咱们心愿使用者不再须要事后理解采集对象,不参加集群化的过程。
- 实例负载尽可能平衡:咱们心愿能依据监控指标的理论负载来划分采集工作,让实例尽可能平衡。
- 动静扩缩容:咱们心愿零碎可能依据采集对象规模的变动进行动静扩缩容,过程中数据一直点,不缺失。
- 兼容外围PrometheusAPI:咱们心愿一些较为外围的API,如上边提到的/api/v1/target接口是失常的。
架构
Kvass由多个组件形成,下图给出了Kvass的架构图,咱们在架构图中应用了Thanos,实际上Kvass并不强依赖于Thanos,能够换成其余TSDB。
- Kvass sidecar: 用于接管Coordinator下发的采集工作,生成新的配置文件给Prometheus,也服务保护target负载状况。
- Kvass coordinator: 该组件是集群的核心控制器,负责服务发现,负载探测,targets下发等。
- Thanos 组件: 图中只应用了Thanos sidecar与Thanos query,用于对分片的数据进行汇总,失去对立的数据视图。
Coordinator
Kvass coordinaor 首先会代替Prometheus对采集指标做服务发现,实时取得须要采集的target列表。
针对这些target,Kvass coordinaor会负责对其做负载探测,评估每个target的series数,一旦target负载被探测胜利,Kvass coordinaor 就会在下个计算周期将target调配给某个负载在阈值以下的分片。
Kvass coordinaor 还负责对分片集群做扩缩容。
服务发现
Kvass coordinaor援用了原生Prometheus的服务发现代码,用于实现与Prometheus 100%兼容的服务发现能力,针对服务发现失去的待抓取targets,Coordinaor会对其利用配置文件中的relabel_configs进行解决,失去解决之后的targets及其label汇合。服务发现后失去的target被送往负载探测模块进行负载探测。
负载探测
负载探测模块从服务发现模块取得解决之后的targets,联合配置文件中的抓取配置(如proxy,证书等)对指标进行抓取,随后解析计算抓取后果,取得target的series规模。
负载探测模块并不存储任何抓取到的指标数据,只记录target的负载,负载探测只对target探测一次,不保护后续target的负载变动,长期运行的target的负载信息由Sidecar保护,咱们将在前面章节介绍。
target调配与扩容
在Prometheus单机性能瓶颈那一节,咱们介绍过Prometheus的内存和series相干,确切来说,Prometheus的内存和其head series间接相干。Prometheus 会将最近(默认为2小时)采集到的数据的series信息缓存在内存中,咱们如果能管制好每个分片内存中head series的数目,就能无效管制每个分片的内存使用量,而管制head series理论就是管制分片以后采集的target列表。
基于上边的思路,Kvass coordinaor会周期性的对每个分片以后采集的target列表进行治理:调配新target,删除有效target。
在每个周期,Coordinaor会首先从所有分片取得以后运行状态,其中包含分片以后内存中的series数目及以后正在抓取的target列表。随后针对从服务发现模块失去的全局target信息进行以下解决
- 如果该target曾经被某个分片抓取,则持续调配给他,分片的series数不变。
- 如果该target没有任何分片抓取,则从负载探测模块取得其series(如果还未探测完则跳过,下个周期持续),从分片中挑一个目前内存中series加上该target的series后仍然比阈值低的,调配给他。
- 如果以后所有分片没法包容所有待调配的targets,则进行扩容,扩容数量与全局series总量成正比。
target迁徙和缩容
在零碎运行过程中,target有可能会被删除,如果某个分片的target被删除且超过2小时,则该分片中的head series就会升高,也就是呈现了局部闲暇,因为target调配到了不同分片,如果有大量target被删除,则会呈现很多分片的内存占用都很低的状况,这种状况下,零碎的资源利用率很低,咱们须要对系统进行缩容。
当呈现这种情时,Coordinaor会对target进行迁徙,行将序号更大的分片(分片会从0进行编号)中的target转移到序号更低的分片中,最终让序号低的分片负载变高,让序号高的分片齐全闲暇进去。如果存储应用了thanos,并会将数据存储到cos中,则闲暇分片在通过2小时候会删除(确保数据已被传到cos中)。
多正本
Kvass的分片以后只反对以StatefulSet形式部署。
Coordinator将通过label selector来取得所有分片StatefulSet,每个StatefulSet被认为是一个正本,StatefulSet中编号雷同的Pod会被认为是同一个分片组,雷同分片组的Pod将被调配雷同的target并预期有雷同的负载。
/api/v1/targets接口
上文提到Coordinator依据配置文件做了服务发现,失去了target列表,所以Coordinator实际上能够失去/api/v1/targets接口所须要的返回后果汇合,然而因为Coordinator只做了服务发现,并不进行理论采集,所以target的采集状态(例如衰弱状态,上一次采集工夫等)都无奈间接得悉。
当Coordinator接管到/api/v1/targets申请时,他会基于服务发现失去的target汇合,联合向Sidecar(如果target已调配)或向探测模块(target还未调配)询问target采集状态,综合后将正确的/api/v1/targets后果返回。
Sidecar
上一节介绍了Kvass coordinaor的基本功能,要想零碎失常运行,还须要Kvass sidecar的配合,其核心思想是将配置文件中所有服务发现模式全副改成static_configs并间接将曾经relabel过的target信息写入配置中,来达到打消分片服务发现和relabel行为,只采集局部target的成果。
每个分片都会有一个Kvass sidecar,其外围性能包含从Kvass coordinator承受本分片负责的target列表,生成新的配置文件给该分片的Prometheus应用。另外,Kvass sidecar还会劫持抓取申请,保护target最新负载。Kvass sidecar还作为PrometheusAPI的网关,修改局部申请后果。
配置文件生成
Coordinaor通过服务发现,relabel及负载探测后,会将target调配给某个分片,并将target信息下发给Sidecar,包含
- target的地址,
- target预估的series值
- target的hash值
- 解决完relabel之后的label汇合。
Sidecar依据从Coordinator失去的target信息,联合原始配置文件,生成一个新的配置文件给Prometheus应用,这个新的配置文件做了如下改变。
- 将所有服务发现机制改为static_configs模式,并间接写入target列表,每个target蕴含通过relabel之后的label值
- 因为当初target曾经relabel过了,所以删除job配置中的relabel_configs项,然而仍旧保留metrics_rebale_configs
- 将target的label中的scheme字段全副替换成http,并将原schme以申请参数的模式退出到label汇合中
- 将target的job_name以申请参数的模式退出到label汇合中* 注入proxy_url将所有抓取申请代理到Sidecar
咱们来看一个例子,如果原来的配置是一个kubelet的采集配置
global: evaluation_interval: 30s scrape_interval: 15sscrape_configs:- job_name: kubelet honor_timestamps: true metrics_path: /metrics scheme: https kubernetes_sd_configs: - role: node bearer_token: xxx tls_config: insecure_skip_verify: true relabel_configs: - separator: ; regex: __meta_kubernetes_node_label_(.+) replacement: $1 action: labelmap
通过注入将生成一个新的配置文件
global: evaluation_interval: 30s scrape_interval: 15sscrape_configs:- job_name: kubelet honor_timestamps: true metrics_path: /metrics scheme: https proxy_url: http://127.0.0.1:8008 # 所有抓取申请代理到Sidecar static_configs: - targets: - 111.111.111.111:10250 labels: __address__: 111.111.111.111:10250 __metrics_path__: /metrics __param__hash: "15696628886240206341" __param__jobName: kubelet __param__scheme: https # 保留原始的scheme __scheme__: http # 设置新的scheme,这将使得代理到Sidecar的抓取申请都是http申请 # 以下是通过relabel_configs解决之后失去的label汇合 beta_kubernetes_io_arch: amd64 beta_kubernetes_io_instance_type: QCLOUD beta_kubernetes_io_os: linux cloud_tencent_com_auto_scaling_group_id: asg-b4pwdxq5 cloud_tencent_com_node_instance_id: ins-q0toknxf failure_domain_beta_kubernetes_io_region: sh failure_domain_beta_kubernetes_io_zone: "200003" instance: 172.18.1.106 job: kubelet kubernetes_io_arch: amd64 kubernetes_io_hostname: 172.18.1.106 kubernetes_io_os: linux
上边新生成的配置文件是Prometheus真正应用的配置文件,Sidecar通过Coordinator下发的target列表来生成配置,就能够让Prometheus有选择性得进行采集。
抓取劫持
在上边的配置生成中,咱们会将proxy注入到job的配置中,并且target的label中,scheme会被设置成http,所以Prometheus所有的抓取申请都会被代理到Sidecar,之所以要这么做,是因为Sidecar须要保护每个target新的series规模,用于Coordinator查阅后作为target迁徙的参考。
从上边配置生成咱们能够看到,有以下几个额定的申请参数会被一并发送到Sidecar
- hash:target的hash值,用于Sidecar辨认是哪个target的抓取申请,hash值由Coordinator依据target的label汇合进行计算取得并传递给Sidecar。
- jobName:是哪个job下的抓取申请,用于Sidecar依据原配置文件中job的申请配置(如原proxy_url,证书等)对抓取指标发动真正的申请。
- scheme:这里的scheme是target通过relabel操作之后最终失去的协定值,尽管在job配置文件中曾经有scheme字段,但Prometheus配置文件仍旧反对通过relabel指定某个target的申请协定。在上述生成新配置过程中,咱们将实在的scheme保留到这个参数里,而后将scheme全副设置成http。
有了上述几个参数,Sidecar就能够对抓取指标发动正确的申请,并失去监控数据,在统计的target这次抓取的series规模后,Sidecar会将监控数据拷贝一份给Prometheus。
API代理
因为Sidecar的存在,局部发往Prometheus的API申请须要被非凡解决,包含
- /-/reload:因为Prometheus真正应用的配置文件由Sidecar生成,针对该接口,须要由Sidecar去解决并在解决胜利后调用Prometheus的/-/reload接口。
- /api/v1/status/config:该接口须要由Sidecar解决并把原配置文件返回。
- 其余接口间接发往Prometheus。
全局数据视图
因为咱们将采集指标扩散到了不同分片中,导致每个分片的数据都只是全局数据的一部分,所以咱们须要应用额定的组件来将所有数据进行汇总并去重(多正本的状况下),失去全局数据视图。
以thanos为例
thanos是一个十分好的计划,通过退出thanos组件,能够很不便得失去kvass集群的全局数据视图。当然咱们也能够通过退出remote writer配置来应用其余TSDB计划,例如influxdb,M3等等。
应用例子
这一节咱们通过一个部署例子,来直观感受一下Kvass的成果,相干yaml文件能够在这里找到https://github.com/tkestack/k...
读者能够将我的项目clone到本地,并进入examples。
git clone https://github.com/tkestack/kvass.gitcd kvass/examples
部署数据生成器
咱们提供了一个metrics数据生成器,能够指定生成肯定数量的series,在本例子中,咱们将部署6个metrics生成器正本,每个会生成10045 series (其中45 series为golang的metrics)。
kubectl create -f metrics.yaml
部署kvass
当初咱们部署基于Kvass的Prometheus集群,用以采集这6个metrics生成器的指标。
首先咱们部署rbac相干配置
kubectl create -f kvass-rbac.yaml
接着部署一个Prometheus config文件,这个文件就是咱们的原始配置,咱们在这个配置文件中,应用kubernetes_sd来做服务发现
kubectl create -f config.yaml
配置如下
global: scrape_interval: 15s evaluation_interval: 15s external_labels: cluster: customscrape_configs:- job_name: 'metrics-test' kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_label_app_kubernetes_io_name] regex: metrics action: keep - source_labels: [__meta_kubernetes_pod_ip] action: replace regex: (.*) replacement: ${1}:9091 target_label: __address__ - source_labels: - __meta_kubernetes_pod_name target_label: pod
当初咱们来部署Kvass coordinator
kubectl create -f coordinator.yaml
咱们在Coordinator的启动参数中设置每个分片的最大head series数目不超过30000
--shard.max-series=30000
咱们当初就能够部署带有Kvass sidecar的Prometheus了,这里咱们只部署单个正本
kubectl create -f prometheus-rep-0.yaml
部署thanos-query
为了失去全局数据,咱们须要部署一个thanos-query
kubectl create -f thanos-query.yaml
查看后果
根据上述计算,监控指标总计6个target, 60270 series,依据咱们设置每个分片不能超过30000 series,则预期须要3个分片。
咱们发现,Coordinator胜利将StatefulSet的正本数改成了3。
咱们看下单个分片内存中的series数目,发现只有2个target的量
咱们再通过thanos-query来查看全局数据,发现数据是残缺的(其中metrics0为指标生成器生成的指标名)
云原生监控
腾讯云容器团队在Kvass的设计思维上进一步优化,构建了高性能反对多集群云原生监控服务,产品目前已正式公测。
大集群监控
这一节咱们就间接应用云原生监控服务来监控一个规模较大的实在集群,测试一下Kvass监控大集群的能力。
集群规模
咱们关联的集群规模大抵如下
- 1060个节点
- 64000+ Pod
- 96000+ container
采集配置
咱们间接应用云原生监控服务在关联集群默认增加的采集配置,目前已蕴含了社区支流的监控指标:
- kube-state-metrics
- node-exporer
- kubelet
- cadvisor
- kube-apiserver
- kube-scheduler
- kube-controler-manager
测试后果
- 总计3400+target, 2700+万series
- 总计扩容了17个分片
- 每个分片series稳固在200w以下
- 每个分片耗费内存在6-10G左右
云原生监控所提供的默认Grafana面板也能失常拉取
targets列表也能失常拉取
多集群监控
值得一提的是,云原生监控服务不仅反对监控单个大规模集群,还能够用同个实例监控多个集群,并反对采集和告警模板性能,可一键将采集告警模板下发至各地区各个集群,彻底辞别了每个集群反复增加配置的问题。
总结
本文从问题剖析,设计指标,原理分析,应用案例等方面具体介绍了一种开源Prometheus集群化技术,可在不批改Prometheus代码的前提下使其反对横向扩缩容,从而监控单机Prometheus无奈监控的大规模集群。
【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!