Kubernetes中的CPU限制和激进节流

注意佩雷夫。:这个欧洲旅行聚合商Omio的警示性故事将读者从基础理论带到了Kubernetes配置迷人的实用错综复杂的事物。熟悉这种情况不仅有助于拓宽视野,而且可以防止非平凡的问题。



您是否曾经遇到以下事实:应用程序“卡住”了,停止了对运行状况检查请求的响应,并且您不了解这种行为的原因?一种可能的解释是CPU资源的配额限制。他将在本文中讨论。

TL; DR:
我们强烈建议您在使用具有CFS配额错误的Linux内核版本时,拒绝Kubernetes中的CPU限制(或在Kubelet中禁用CFS配额)。在核心一个严重的众所周知的错误,导致过度的节流和延迟


在Omio,整个基础架构由Kubernetes管理我们所有的有状态和无状态负载都只能在Kubernetes上运行(我们使用Google Kubernetes Engine)。在过去的六个月中,我们开始观察到随机减速。应用程序冻结或停止对运行状况检查作出响应,失去与网络的连接等。这种行为长期困扰着我们,最后,我们决定紧密解决这个问题。

文章摘要:

  • 关于容器和Kubernetes的几句话;
  • 如何执行CPU请求和限制;
  • CPU限制在多核环境中的工作方式;
  • 如何跟踪节流CPU;
  • 解决问题和细微差别。

关于容器和Kubernetes的几句话


实际上,Kubernetes是基础架构世界中的现代标准。它的主要任务是协调容器。

货柜


过去,我们必须创建诸如Java JAR / WAR,Python Eggs或可执行文件之类的工件,以便随后在服务器上启动。但是,为了使它们起作用,它们必须做其他工作:安装运行时(Java / Python),将必要的文件放在正确的位置,确保与特定版本的操作系统兼容,等等。换句话说,您必须密切注意配置管理(这通常会导致开发人员和系统管理员之间发生争执)。

容器改变了一切。现在,容器图像充当了工件。它可以表示为一种扩展的可执行文件,它不仅包含程序,还包含完整的运行时(Java / Python / ...),以及预先安装并可以运行的必要文件/包。无需任何其他步骤即可在各种服务器上部署和运行容器。

此外,容器在自己的沙箱环境中工作。它们具有自己的虚拟网络适配器,具有受限访问权限的文件系统,进程的层次结构,对CPU和内存的限制等。这一切都归功于Linux内核的特殊子系统-名称空间(名称空间)。

Kubernetes


如前所述,Kubernetes是一个容器乐队。它的工作方式如下:为它提供一个计算机池,然后说:“嘿,Kubernetes,启动我的容器的10个实例,每个实例具有2个处理器和3 GB的内存,并使它们正常运行!” Kubernetes负责其余的工作。他将找到可用容量,启动容器并在必要时重新启动它们,在更改版本时推出更新等。实际上,Kubernetes允许您从硬件组件中抽象出来,并使各种系统都适合于应用程序的部署和操作。


从一个简单的外行人的角度来看Kubernetes

Kubernetes中的请求和限制是什么


好的,我们找出了容器和Kubernetes。我们也知道几个容器可以在同一台机器上。

您可以使用公共公寓进行类比。占用一间宽敞的房间(汽车/节点)并将其租给数个租户(容器)。 Kubernetes充当房地产经纪人。随之而来的问题是,如何防止租户彼此冲突?例如,如果其中一个人决定占用卫生间半天怎么办?

这是请求和限制起作用的地方。 CPU 请求仅用于计划目的。这类似于容器的“愿望清单”,用于选择最合适的节点。同时,可以将“ CPU 限制”与“租约”进行比较-在我们为容器选择一个节点后,将无法超出既定限制。在这里出现一个问题...

Kubernetes中如何实现请求和限制


Kubernetes使用内核节流(跳过时钟)机制来实现CPU限制。如果应用程序超出限制,则会启用限制(即,它收到较少的CPU周期)。内存的请求和限制的组织方式不同,因此更易于检测。为此,只需检查上一个Pod重新启动状态即可:是否为“ OOMKilled”。随着CPU的节流,一切都不是那么简单,因为K8仅提供了可用的指标,而不是cgroup。

CPU请求



如何实现CPU请求

为简单起见,让我们以带有4核CPU的计算机为例看一下该过程。

K8s使用cgroups机制来控制资源(内存和处理器)的分配。他可以使用分层模型:后代继承父组的限制。分发详细信息存储在虚拟文件系统(/sys/fs/cgroup)中。如果是处理器,则为/sys/fs/cgroup/cpu,cpuacct/*

K8s使用该文件cpu.share分配处理器资源。在我们的例子中,根控制组接收4096个CPU资源份额-可用处理器能力的100%(1个内核= 1024;这是一个固定值)。根组根据图5中规定的后代份额按比例分配资源。cpu.share,然后依次对后代执行相同操作,依此类推。通常Kubernetes根节点对照组有三个子:system.sliceuser.slicekubepods。前两个子组用于在K8之外的关键系统负载和用户程序之间分配资源。最后一个- kubepods由Kubernetes创建,用于在Pod之间分配资源。

上图显示,第一和第二子组获得1024股,其中4096分配给kuberpod子组。这怎么可能:根组毕竟只有4096个可用份额,其后代的份额之和大大超过了这个数目(6144)?事实是该值具有逻辑意义,因此Linux Scheduler(CFS)使用它来按比例分配CPU资源。在我们的案例中,前两组获得了680股实际份额(占4096的16.6%),而kubepod则获得了剩余的2736份额。如果发生停机,前两个组将不使用分配的资源。

幸运的是,调度程序具有避免丢失未使用的CPU资源的机制。它将“空闲”容量转移到全局池,从中将它们分配到需要更多处理器容量的组中(分批转移以避免舍入损失)。类似的方法适用于所有后代。

该机制确保公平分配处理器能力,并确保没有进程“窃取”他人的资源。

CPU限制


尽管K8中的限制和请求配置看起来很相似,但它们的实现方式却根本不同:这是最容易引起误解和文档最少的部分。

K8s使用CFS配额机制来实现限制。它们的设置在文件cfs_period_uscfs_quota_uscgroup目录中指定(该文件也位于该目录中cpu.share)。

相反cpu.share,配额是基于一段时间而不是可用的处理器能力。cfs_period_us设置周期的持续时间(era)-始终为100,000μs(100 ms)。 K8s可以更改此值,但当前仅在Alpha版本中可用。调度程序使用时代来重新启动使用的配额。第二档cfs_quota_us,设置每个时代的可用时间(配额)。请注意,它也以微秒表示。配额可能超过了时代的期限;换句话说,它可能超过100毫秒。

让我们看一下16核计算机(在Omio中最常见的计算机类型)上的两种情况:


情况1:2个线程,限制为200毫秒。没有节流的


情况2:10个流,限制为200毫秒。经过20毫秒节流开始,访问处理器资源另一个80毫秒之后恢复。

假如你设定的CPU限制2芯; Kubernetes会将这个值转换为200毫秒。这意味着该容器最多可以使用200毫秒的CPU时间而不进行限制。

从这里开始乐趣。如上所述,可用配额为200毫秒。如果您在12核计算机上并行运行十个线程(请参阅场景2的图示),而所有其他Pod都处于空闲状态,则配额将仅用20毫秒(因为10 * 20毫秒= 200毫秒)耗尽,因此所有线程在接下来的80毫秒内,此舱的油门将被关闭。已经提到的调度程序错误加剧了这种情况,由于这种情况发生了过多的限制,并且容器甚至无法计算出现有的配额。

如何评估豆荚节流?


只是去荚跑cat /sys/fs/cgroup/cpu/cpu.stat

  • nr_periods -调度程序的总周期数;
  • nr_throttled-组合中的节流周期数nr_periods
  • throttled_time -累计节流时间(以纳秒为单位)。



到底是怎么回事?


结果,我们在所有应用程序中都获得了高节流。有时它比计算得出的强度大一倍

这会导致各种错误-准备检查失败,容器挂起,网络连接中断,服务调用内部超时。最终,这转化为增加的延迟和增加的错误。

决策与后果


这里的一切都很简单。我们放弃了CPU限制,并开始将群集中的OS内核更新为已修复该错误的最新版本。我们的服务中的错误数量(HTTP 5xx)立即显着下降:

HTTP错误5xx



一项关键服务的HTTP 5xx错误

P95响应时间



紧急服务请求延迟,95%

营运成本



花费的小时数

有什么收获?


如本文开头所述:

您可以用一个公共公寓做个比喻。Kubernetes充当房地产经纪人。但是,如何防止租户彼此冲突呢?例如,如果其中一个人决定占用卫生间半天怎么办?

这就是陷阱。一个过失的容器可以吸收机器上所有可用的处理器资源。如果您拥有智能应用程序堆栈(例如,正确配置了JVM,Go,Node VM),那么这不是问题:您可以在这种情况下长时间工作。但是,如果应用程序优化不佳或根本没有优化(FROM java:latest),情况可能会变得一发不可收拾。Omio我们已经为基本的Dockerfile自动化了,并为主要语言的堆栈提供了足够的默认设置,因此没有这种问题。

我们建议您监视USE指标(使用率,饱和度和错误),API延迟和错误率。确保结果符合预期。

参考文献


那是我们的故事。以下材料极大地帮助您了解正在发生的事情:


Kubernetes错误报告:


您在实践中是否遇到过类似的问题,或者在容器化生产环境中有节流的经验?在评论中分享您的故事!

译者的PS


另请参阅我们的博客:


All Articles