



确定target数目对Prometheus负载的关系
确定series数目和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 |

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


对预监控数据要有所了解:使用上述方法的前提是使用者必须对监控对象会上报的数据有所了解,例如必须知道监控对象会上报某个用于hash_mod的label,或者必须知道不同job的整体规模,才能对job进行划分。
实例负载不均衡:虽然上述方案预期都是希望将数据打散到不同Prometheus实例上,但实际上通过某些label的值进行hash_mod的,或者干脆按job进行划分的方式并不能保证每个实例最终所采集的series数是均衡的,实例依旧存在内存占用过高的风险。
配置文件有侵入:使用者必须对原配置文件进行改造,加入Relabel相关配置,或者将一份配置文件划分成多份,由于配置文件不再单一,新增,修改配置难度大大增加。
无法动态扩缩容:上述方案中的由于配置是根据实际监控目标的数据规模来特殊制定的,并没有一种统一的扩缩容方案,可以在数据规模增长时增加Prometheus个数。当然,用户如果针对自己业务实际情况编写扩缩容的工具确实是可以的,但是这种方式并不能在不同业务间复用。
部分API不再正常:上述方案将数据打散到了不同实例中,然后通过联邦或者Thanos进行汇总,得到全局监控数据,但是在不额外处理的情况下会导致部分Prometheus 原生API无法得到正确的值,最典型的是/api/v1/targets,上述方案下无法得到全局targets值。

无侵入,单配置文件:我们希望使用者看到的,修改的都是一份原生的配置文件,不用加任何特殊的配置。
无需感知监控对象:我们希望使用者不再需要预先了解采集对象,不参与集群化的过程。
实例负载尽可能均衡:我们希望能根据监控目标的实际负载来划分采集任务,让实例尽可能均衡。
动态扩缩容:我们希望系统能够根据采集对象规模的变化进行动态扩缩容,过程中数据不断点,不缺失。
兼容核心PrometheusAPI:我们希望一些较为核心的API,如上边提到的/api/v1/target接口是正常的。

Kvass sidecar:用于接收Coordinator下发的采集任务,生成新的配置文件给Prometheus,也服务维护target负载情况。
Kvass coordinator:该组件是集群的中心控制器,负责服务发现,负载探测,targets下发等。
Thanos 组件:图中只使用了Thanos sidecar与Thanos query,用于对分片的数据进行汇总,得到统一的数据视图。

如果该target已经被某个分片抓取,则继续分配给他,分片的series数不变。
如果该target没有任何分片抓取,则从负载探测模块获得其series(如果还未探测完则跳过,下个周期继续),从分片中挑一个目前内存中series加上该target的series后依然比阈值低的,分配给他。
如果当前所有分片没法容纳所有待分配的targets,则进行扩容,扩容数量与全局series总量成正比。



target的地址
target预估的series值
target的hash值
处理完relabel之后的label集合
将所有服务发现机制改为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

global:
evaluation_interval: 30s
scrape_interval: 15s
scrape_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: 15s
scrape_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。

/-/reload:由于Prometheus真正使用的配置文件由Sidecar生成,针对该接口,需要由Sidecar去处理并在处理成功后调用Prometheus的/-/reload接口。
/api/v1/status/config:该接口需要由Sidecar处理并把原配置文件返回。
其他接口直接发往Prometheus。


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: custom
scrape_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。
我们再通过thanos-query来查看全局数据,发现数据是完整的(其中metrics0为指标生成器生成的指标名)。



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左右






本文探讨了确定target和series数目与Prometheus负载的关系,指出当前方案存在实例负载不均衡、配置文件有侵入等问题。提出了无侵入、单配置文件等优化目标,并介绍了Kvass sidecar、Kvass coordinator和Thanos组件。还给出了target分配规则和配置生成方法,最后展示了测试数据。
2131

被折叠的 条评论
为什么被折叠?



