Kubernetes中的CPU节流:事后分析


Kubernetes是我们基础架构中很重要的一部分。我们不仅在生产环境中使用Kubernetes来部署应用程序,而且还在CI/CD以及开发者基础架构中大量使用它。当在开发我们的CI/CD基础架构时,我们处理了一个在开发和CI环境中应用程序启动时间过长的性能问题。

在本文中,我们将尝试深入研究降低应用程序性能的问题以及如何最终解决该问题。

背景

在Grofers,我们遵循微服务架构,其中所有关键组件(如付款,购物车,库存等)都组织为微服务。因此,开发人员无法在同一名称空间中同时处理多个服务。这导致我们采用一种设计,其中每个开发人员都有自己的命名空间,所有服务都部署在隔离的环境中以进行测试和调试。内部我们称之为‘Grofers-in-a-namespace’。为了实现这一目标,我们开发了一种称为mft的内部工具。 Mft用于在Kubernetes中创建新的名称空间,并从VaultConsul注入必要的依赖项。

然后,通过通用的Jenkins安装程序部署运行Grofers副本所需的所有服务。 然后,这些服务通过Ingress暴露给开发人员,以供测试套件使用,或用作调试应用程序测试的端点(Endpoint)。

问题

我们为服务采用了USE-RED仪表板,以帮助我们跟踪关键指标。 这使我们能够进一步优化基础架构,以充分利用其性能。

当我们开始分析此类指标时,我们发现某些应用程序需要花费大量时间来启动和准备,这是开发人员在本地设置中未观察到的。 此外,我们在Jenkins上的一些工作花费了很多时间来创建环境并将其准备就绪,而这是我们以前没有考虑的。 这让我们重新审查所有指标,以确定可能导致应用程序在Kubernetes基础架构中启动缓慢的原因。

此外,在生产环境中未观察到这些问题。 生产部署的表现形式略有不同,CPU和内存分配更为自由。 此外,我们的生产集群还有更多的扩展空间,这使我们认为这是基础架构特定的问题。

根本原因

经过近一个月的调试,我们决定重新审查我们的测试和Kubernetes的设置,以帮助隔离问题。 在我们的RAV(回归和验证)测试的优化过程中,我们列出所有可能影响容器性能的Kubernetes指标。 我们发现了一个有趣的指标是CPU节流(container_cpu_cfs_throttled_seconds_total)。 确定该指标后,我们发现了令人惊讶且有趣的结果。 我们一些最关键的服务正处在CPU节流状态,我们一无所知。 此外,我们观察到在CI和dev环境中,在启动时某些特定的容器更容易发生这种情况,这些容器是我们在启动时运行某种CPU密集型操作的容器。
1.png

我们立即开始做因果分析,并得出以下原因:
  1. 不正确的容器CPU限额导致应用程序迅速达到限额条件,然后导致Kubernetes对其进行CPU节流。
  2. 后台活动(如GC)在一段时间后触发,导致CPU周期增加。 这也可能是由于基于JVM的应用程序的堆大小不正确引起的。
  3. 节点上的某些周期性CPU密集型活动窃取了cgroup可用的CPU周期,这也暗示了应用程序逻辑中的周期性峰值的CPU限额不确定。


什么是CPU节流

几乎所有的容器编排器都依赖于内核控制组(cgroup)机制来管理资源约束。 在容器编排器中设置硬CPU限制后,内核将使用完全公平调度器(CFS)Cgroup带宽控制来实施这些限制。 CFS-Cgroup带宽控制机制使用两个设置来管理CPU分配:配额(quota)和周期(period)。 当应用程序在给定时间段内使用完其分配的CPU配额时,此时它将受到CPU节流,直到下一个周期才能被调度。

cgroup的所有CPU指标都位于/sys/fs/cgroup/cpu,cpuacct/<container>。配额和周期通过cpu.cfs_quotacpu.cfs_period 来设置。
2.png

cgroup中的CPU资源详情

你也可以在cpu.stat中查看限制指标。 在cpu.stat中,你会发现:
  1. nr_periods — cgroup中任何线程可运行的周期数
  2. nr_throttled — 应用程序可运行的周期数,在运行周期可以使用全部配额,所有周期用完之后被节流
  3. throttled_time — cgroup中各个线程被限制的总时间。


监视内存限制以防止OOM终止

要考虑的另一个有趣指标是由于OOM而导致的容器重新启动的次数。 这突出显示了那些经常达到其Kubernetes清单中指定的内存限制的容器。
kube_pod_container_status_terminated_reason{reason=”OOMKilled”})

解决方案

> 解决该问题的快速方法是将限额提高在10-25%之间,以确保减少或完全避免峰值的出现。

在确定根本原因之后,我们提出了一些可能的解决方案。 我们做了以下的考虑:

CPU节流主要是因为CPU限额较低。 它的限额实际上影响了Cgroup的行为。 因此,解决该问题的快速方法是将限额提高在10-25%之间,以确保减少或完全避免峰值的出现。 由于请求保持不变,因此这也不会影响启动Pod的资源要求。

同时,对于某些密集型应用程序,尤其是那些利用基于JVM的系统的应用程序,由于JVM众所周知会占用大量资源,因此我们决定再次对应用程序进行性能分析,以获取正确的CPU和内存要求。 从长远来看,对于此类应用程序,调整JVM参数将是正确的解决方案。

收获以及下一步计划

对我们来说,这是一次很深刻的经历。 我们意识到,一些看起来不太好(或在这种情况下被忽略)的指标可能会对应用程序性能产生深远影响。 我们对CFS和cgroup以及内核如何处理资源虚拟化也有了一些深刻的认识。

基于此经历,我们提出了针对主要应用程序的应用程序性能分析计划,并将CPU节流添加到了我们对应用程序性能不佳的核心怀疑之一中。

原文链接:CPU Throttling in Kubernetes: A Postmortem(翻译:王欢)

0 个评论

要回复文章请先登录注册