关于云原生:vivo-容器集群监控系统优化之道

32次阅读

共计 8025 个字符,预计需要花费 21 分钟才能阅读完成。

作者: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 提供的 pod
cadvisor-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 是否开启动静 housekeeping
const 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 端升高数量从而更稳固提供的数据。

正文完
 0