作者:vivo 互联网容器团队 - Han Rucheng

本文介绍了vivo容器团队基于 Prometheus等云原生监控生态来构建的容器集群监控体系,在业务接入容器监控的过程中遇到的挑战、艰难,并分享了相应的应答策略和优化计划。

一、背景介绍

随着vivo业务迁徙到容器平台,vivo云原生监控体系面临着指标量疾速上涨带来的一系列挑战,本文将分享vivo 容器化我的项目中容器监控遇到的问题以及咱们的解决和优化办法。

二、监控架构

首先对vivo容器监控架构进行一个简略的介绍。

  • 【架构高可用】:集群维度的双正本 Prometheus 采集底层exporter数据,adapter多实例主动选主实现容灾。
  • 【数据长久化】:通过remoteWrite将数据存储到后端的VictoriaMetrics中进行长久化存储,Grafana应用VictoriaMetrics做为数据源展现和告警。
  • 【监控统一化】:通过remoteWrite将数据交由kafka-adapter转发到Kafka,由公司根底监控等服务通过生产Kafka中的数据来进行展现和告警。

原生Prometheus没有提供高可用的规范计划,咱们通过自研 Adapter “分组选举”形式实现去重,即每个 Prometheus 正本对应一组 Adapter,两组 Adapter 之间会进行选主,只有Leader组的 Adapter才会转发数据。通过这种形式既实现了去重,也实现了Prometheus双正本高可用。

三、问题景象

过来几年来,vivo容器化服务快速增长,监控流量上涨数倍,咱们次要遇到如下三个问题:监控组件负载疾速升高、容器监控数据断点和数据存储组件负载陡增

3.1 监控组件负载疾速升高

容器化每次部署IP都会变动的个性,导致容器监控指标量相比物理机和虚拟机要高出好几个数量级。同时因为集群规模的一直减少以及业务的快速增长,导致监控 Prometheus、VictoriaMetrics 负载疾速增高,给咱们容器监控带来极大的挑战。监控总工夫序列能够精简为以下的表达式,即与 Pod数量、Pod指标量、指标Label维度数量呈线性关系:

TotalSeries = PodNum PerPodMetrics PerLabelCount

而随着集群规模的一直减少以及容器数量的一直增多,监控序列就会快速增长,同时监控组件负载疾速升高,会对容器监控零碎的稳定性产生影响。

3.2 监控丢点景象

vivo容器层面(业务)的监控数据则通过自研Adapter转发给Kafka,进而存储到公司根底监控做业务监控展现和告警配置,同时也存储一份到Druid做更多维度的统计报表。咱们在推送监控数据的时候发现,Pod维度的指标难以保障发送频率,即配置指标采集频率为 10s,然而在推送的数据中频率无奈做到10s,且会有稳定。下图为 采集频率设置 10s,查问1分钟的指标数据。

一分钟内某一容器的 container\_cpu\_user\_seconds\_total 指标的值:

能够看到只取到了4个值,与冀望的 6个值不相符,即产生了“掉点”的状况,监控面板按指定频率展现数据会有频繁掉0景象。

3.3 数据存储组件负载陡增

vivo容器监控应用 VictoriaMetrics的v1.59.1-cluster版本做为后端时序数据库来长久化存储监控数据。在应用过程中发现 VictoriaMetrics的负载有不定期增高的状况,而后端数据库的提早会导致监控查问告警性能的异样影响用户体验。

四、解法

4.1 监控组件负载疾速升高

咱们应用 Prometheus-Operator 治理 Prometheus,因为优化计划中有 Prometheus-Operator 相干的名词,故为了上面的了解,先对 Prometheus-Operator 做一个介绍:

(图片起源:官网架构图)

上图是Prometheus-Operator官网提供的架构图,上面来介绍下图中各组件:

  1. Operator:  Operator是最外围的局部,作为一个控制器,他会去创立Prometheus、ServiceMonitor资源对象,而后会始终监控并维持这些资源对象的状态。
  2. Prometheus:这种资源对象就是作为Prometheus Server存在, Operator 依据自定义资源 Prometheus 类型中定义的内容而部署的 Prometheus Server。Prometheus 也能够通过 labelSelector 去匹配多个ServiceMonitor。
  3. ServiceMonitor:ServiceMonitor就是exporter的各种形象,exporter是用来提供专门提供metrics数据接口的服务。Prometheus就是通过ServiceMonitor提供的metrics数据接口去 pull 数据的。该资源通过 Labels 来选取对应的 Service Endpoint,让 Prometheus Server 通过选取的 Service 来获取 Metrics 信息。一个 ServiceMonitor 能够通过 labelSelector 的形式去匹配一类 Service。
  4. Service:Service是Kubernetes内建资源用于把一组领有雷同性能的Pod封装起来,并提供一个对立的入口来裸露这组Pod的服务,从而为客户端拜访提供了一个稳固的拜访地址,屏蔽了底层Pod的变动和故障。Service能够联合Kubernetes中的其余组件实现负载平衡、服务发现、集群外部通信等性能。

咱们重点关注 ServiceMonitor,因为ServiceMonitor为咱们提供了指定 target 采集的配置,例如采集频率,target内指标过滤,指标中label重命名等等操作。

对于监控组件负载疾速升高问题的解决,咱们次要从两个方面着手,别离是指标治理以及性能优化

4.1.1 指标治理

1、过滤未应用指标

第一个工作是过滤无用指标,Prometheus 会去从 Target 中去获取指标数据。每个 Target 下会有多个 endponit。每一个endpoint 又会提供几十上百个指标,而每个指标下的数据量也很大。但在生产环境中咱们实际上用到的指标可能只有几十个,Prometheus采集过去咱们又没有用到的指标就会浪费资源并升高监控零碎的稳定性。因而咱们须要对Prometheus 采集到的指标进行肯定水平的过滤,从而缩小资源的占用。

通过Prometheus提供的 scrape\_samples\_scraped 指标对采集的 target进行剖析找到采集样本量大的Target。

咱们进行指标过滤次要就是关注这些数据量大的 target,在进行指标过滤之前须要收集 Prometheus所采集的所有指标数据以及以后监控告警面板以及相干依赖服务所应用到的指标。再依据采集的指标和正在应用的指标进行正则表达式的书写。最终在对应 target的 ServiceMonitor将正则表达式写入。Prometheus则会过滤掉咱们不须要的指标。上面就是过滤 cAdvisor这个 target 的 container_threads 结尾的指标的示例。

# 过滤  container_threads  结尾的指标    - action: drop      regex: container_threads(.*)      sourceLabels:      - __name__

实现指标精简后,监控单次采集样本量从 1000万升高到 250万。Prometheus 的CPU 使用量升高 70% ,内存 使用量升高 55%。

2、过滤低优先级 pod 相干指标

对精简后的指标进行剖析,发现 Pod维度的监控指标占比为70%,且有相当比例的 Pod 是集群组件的 Daemonset的Pod。而Daemonset的Pod是随着集群规模的减少而减少的。

而对于大部分的集群组件Daemonset,因为设置了资源下限,咱们不须要关注其资源耗费状况,只须要关注是否存活和失常提供服务即可。故能够对这部分 Pod 的指标进行一个精简,不收集这些 Pod的 memory、cpu 等容器监控指标。

一个 Daemonset 提供的 Pod 的 Namespace 是雷同的,且Pod名称前缀雷同。

# 名称为cadvisor的 daemonset 提供的 podcadvisor-xxxx1                                    1/1     Running            cadvisor-xxxx2                                    1/1     Running

且 cAdvisor 提供的指标中蕴含了 namespace 和 pod 的 label。

container_memory_cache{container="POD", namespace="monitoring", pod="kube-state-metrics-xxxx-xxxx", service="cadvisor"}

所以咱们通过在 ServiceMonitor 下面组合指标的 pod 和 namespace,并与指定的规定进行匹配抛弃掉咱们不须要的 daemonset pod 的序列。

# 过滤掉 monitoring namespace 上面 telegraf 这个daemosnet提供的 pod 的相干指标    - action: drop      regex: monitoring@telegraf(.*)      separator: '@'      sourceLabels:      - namespace      - pod

在对集群中局部ds Pod 的指标进行过滤后。

对 cAdvisor 的单次采集数据量降落 70%。成果非常显著。

4.1.2 性能优化

1、平衡 Prometheus 负载

vivo 容器监控架构中最外围的组件就是 Prometheus了,而 Prometheus 也是日常呈现问题最多的一个组件,因为 Prometheus 不仅是须要采集数据,还须要将数据通过remote_write的形式推送的VictoriaMetrics 和 Kafka中。

将监控 target 进行分类交由不同的组 Prometheus 采集,且每类 Prometheus 为双正本模式。随着集群规模的减少,发现以后模式的不合理之处,即因为Pod维度监控数据量级非常高,导致container 类型 Prometheus 负载远远高于其余类型的 Prometheus。在高负载的状况上面会产生重启,remote_write 异样等状况。

咱们 Prometheus组件架构为按类型采集监控指标。其中 Container类型的 Prometheus采集的指标数量远远大于 Component、Host、Resource类型。故须要手动均衡 集群中 Prometheus的负载 将集群的 container类型 Prometheus下面kubelet 和 kube-state-metrics 转移到 resource-Prometheus 下面 升高 container-Prometheus负载。(与此同时resource-Prometheus也会发送到 kafka-adapter)。且在负载低的Prometheus上 监控跳转面板用到的监控指标(外围指标)进行反复采集,尽可能避免数据失落。升高了container-Prometheus 40%的负,极大的缩小了Prometheus异常情况的产生。

2、缩小Prometheus存储数据工夫

咱们的第2个批改点在 Prometheus的数据存储工夫上,Prometheus的默认存储工夫为2周,后续测试发现 Prometheus的存储数据工夫对内存的影响很大,且当初监控数据的长久化存储都放在 VictoriaMetrics 下面,Prometheus存储的数据次要用于排查问题,不须要承当长久化存储的工作。故咱们批改Prometheus采集的数据本地存储工夫从7天改为2天。Prometheus 内存耗费升高 40%。

4.2 监控丢点景象

4.2.1 问题定位

最后咱们认为是 Prometheus 在remote_write 的过程中产生了丢点的状况,然而通过在社区查问和配置问题Prometheus 近程写相干的监控指标发现Prometheus并没有在近程写的时候抛弃数据,且发现在推送数据的过程中只有kubelet 内置的 cAdvisor提供的数据有"丢点"的状况。 故咱们开始钻研指标提供端组件 cAdvisor,发现cAdvisor”丢点”问题的起因在于 cAdvisor 组件有本人的刷新频率 和 工夫戳。cAdvisor 会去 cgroup 中读取数据并存储到内存中供内部应用。Kubelet的cAdvisor 的刷新数据频率达不到 10s,并且会依据刷新工夫放到指标中。 而 Prometheus 按 10s 采集频率去采集数据时,底层的 cAdvisor 如果还没有去刷新数据,内存中则还是上次的数据。而cAdvisor 在0.31版本及之后的版本中增加了工夫戳反对,即 cadvisor 提供的数据会带上本人的工夫戳。当 Prometheus 去采集 cadviosr数据时会以 cAdvisor提供的工夫戳为准。故当 Prometheus 依照ServiceMonitor 设置的采集频率10s去采集cAdvisor 提供的数据时,如果在此期间 cAdvisor 没有进行数据更新,则Prometheus会采集到与上次采集工夫戳和值雷同的状况,Prometheus 就只会记录一条数据。这就是cAdvisor “丢点”的实质。cAdvisor的刷新频率由 housekeeping相干参数 和 抖动 机制确定。

kubelet 内置 cAdvisor设置的参数:

// Kubelet 内置 cadvisor 默认参数  // cadvisor housekeeping 的距离,刷新数据的距离const defaultHousekeepingInterval = 10 * time.Second       // cadvisor 是否开启动静 housekeepingconst allowDynamicHousekeeping = true                         /*cadvisor housekeeping 的最大距离,allow_dynamic_housekeeping=true的时候, 会判断容器沉闷水平动静的调整 HousekeepingInterval, 当发现一段时间为容器状态为产生扭转会将 housekeeping 的距离 设置为maxHousekeepingInterval 。*/const maxHousekeepingInterval = 15 * time.Second
4.2.2 解决方案

依据下面的剖析,定位到无奈保障指标频率的根本原因在于 cAdvisor 的默认启动参数,而目前咱们采集的cAdvisor是内置于 kubelet 中的,如果要批改参数的话须要改变 kubelet。故综合思考集群稳定性和保护老本等因素,咱们决定以 daemonset 的形式部署一套cAdvisor,并依据需要设置 housekeeping 相干的参数来保障 cAdvisor 刷新数据的频率,并设置 Prometheus 采集 cAdvisor 数据的时候疏忽 cAdvisor 自带的工夫戳,即通过独自部署的 cAdvisor 提供Pod的监控数据并保障监控数据的频率。

咱们的工作次要在部署 cAdvisor 和 批改对应的 ServiceMonitor。

1、部署 cAdvisor:次要是确定cAdvisor启动参数, 次要操作为禁用dynamic\_housekeeping 和 设置 housekeeping\_interval 为 1s,来保障 cAdvisor 获取数据的频率。

containers:// 参数设置  - -allow_dynamic_housekeeping=false  - -housekeeping_interval=1s

2、创立对应的ServiceMonitor 让 cAdvisor 让Prometheus 疏忽cadviosr自带的工夫戳。(因为 cadviosr本身的抖动机制,频率无奈固定)

cAdvisor的抖动机制:

// return jitter(cd.housekeepingInterval, 1.0)func jitter(duration time.Duration, maxFactor float64) time.Duration {if maxFactor <= 0.0 {maxFactor = 1.0}wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration))return wait}

cAdvisor的 ServiceMonitor上配置疏忽指标自带工夫戳

通过独自部署的 cAdvisor和 Prometheus 的疏忽 cAdvisor 自带的工夫戳,咱们胜利的解决了容器监控断点的问题,保障了监控的频率。

spec:  endpoints:  - honorLabels: true    // 疏忽工夫戳    honorTimestamps: false    interval: 10s

能够看到再去采集 1分钟内的容器相干监控数据,是很规范的 6 个数据点。至此监控“掉点”问题解决。

监控面板展现数据间断,无中断景象产生。

4.3 后端数据库负载突增

4.3.1 问题定位

从监控架构图能够看到,咱们应用社区 v1.59.1-cluster版本的VictoriaMetrics 作为监控后端的时序数据库,并在Prometheus 采集的数据后通过remote_write写入到时序数据库VictoriaMetrics中进行长久化存储,Grafana会从VictoriaMetrics 读取数据展现在对应的 Dashboard下面。而在咱们的理论应用中发现,Prometheus 近程写入VictoriaMetrics有不定期提早飙升的景象。

Prometheus写入VictoriaMetrics提早

写入数据库提早的飙升会导致,监控面板展现延时、监控误告警等一系列问题。

咱们对 VictoriaMetrics的具体指标进行剖析。发现 vmstorage 组件在底层执行 indexdb merge 操作的时候,其 CPU、内存等资源使用量会有一个突增, 即indexdb 的 Merge 操作十分耗费资源。

4.3.2 解决方案

正是因为VictoriaMetrics 这些的资源突增,导致本人负载过高,无奈失常响应 Prometheus的 remote_write的数据。咱们所冀望的是在 indexdb merge 的时候,资源使用量的增长不会影响到失常的数据插入和查问。通过查问相干资源失去VictoriaMetrics在1.73.0版本中对indexdb的 merge进行优化,晋升了整体性能。故咱们对VictoriaMetrics 进行了版本升级以优化这个问题。在版本升级后,未发现 VictoriaMetrics 在indexdb merge时有资源突增的状况产生。

五、总结

在Kubernetes大规模应用的明天,以 Prometheus 为外围的监控零碎已成为云原生监控畛域的事实标准。原生Prometheus没有提供高可用和长久化存储的规范计划,vivo通过自研adapter实现了Prometheus双正本高可用,并将数据写入到VictoriaMetrics中实现了数据的长久化存储。而在业务规模的增长的过程中,监控数据量也在快速增长,对监控采集和存储组件都带来了不小的压力,以后咱们通过升高数据提供端指标数量、优化采集组件参数、降级开源存储组件版本的形式,晋升了监控零碎的性能。

而架构的演变是随着业务规模的增长而一直的演变改良的,将来咱们将联合业务理论规模优化监控架构晋升容器监控整体性能。后续咱们布局在监控采集、监控查问、监控数据提供三个方向持续晋升提供零碎性能:

  • 【监控采集】:改良数据采集端架构,利用主动分片从而升高采集端压力。
  • 【监控查问】:利用 PrometheusRule以升高罕用查问耗时,晋升监控查问体验。
  • 【监控数据提供】:在exporter端升高数量从而更稳固提供的数据。