Kubernetes:通过消除CPU限制提高服务速度

2020-09-03 18:27:12

在Buffer,我们从2016年开始使用Kubernetes。我们一直在使用KOPS管理我们的K8(Kubernetes)集群,它有大约60个节点(在AWS上),运行大约1500个容器。我们向微服务架构的过渡充满了试验和错误。即使在运行了几年的K8之后,我们仍然在学习它的秘密。这篇文章将讨论一些我们认为是好事,但最终并不像我们想象的那么好的事情:CPU限制。

一般建议设置CPU限制。谷歌和其他公司强烈推荐它。不设置CPU限制的危险在于,在节点中运行的容器可能会耗尽所有可用的CPU。这可能会触发一系列不需要的事件,例如让关键的Kubernetes进程(如kubelet)变得无响应。因此,从理论上讲,设置CPU限制以保护您的节点是一件很棒的事情。

CPU Limits是容器在给定时间段(默认为100ms)可以使用的最大CPU时间。容器的CPU使用率永远不会超过您指定的限制。Kubernetes使用一种名为CFS配额的机制来限制容器,以防止CPU使用率超过限制。这意味着CPU将受到人为限制,从而降低容器的性能(在延迟方面会变得更慢)。

不幸的是,我们经历了这个问题。在每个节点上运行并负责管理节点中的容器(Pod)的kubelet进程变得没有响应。该节点将变为NotReady状态,并且原来存在的容器(Pod)将被重新调度到其他地方,并在新节点中产生问题。肯定不是很理想,不是吗?

运行容器时需要检查的一个关键指标是节流。这表示您的容器已被节流的次数。有趣的是,我们发现无论CPU使用率是否接近极限,很多容器都有节流功能。下面是我们的一个主要API的示例:

您可以在动画中看到,CPU限制设置为800M(0.8核,一个核的80%),峰值使用率最高为200M(一个核的20%)。看过之后,我们可能会认为我们有足够的CPU让服务在停止之前运行,对吗?现在来看看这个:

您可以注意到,即使CPU使用率低于CPU限制,也会发生CPU限制。最大CPU使用率甚至没有接近CPU限制。

然后,我们找到了一些资源(gihub问题、zanado talk、omio post),讨论节流如何导致您的服务的性能和延迟变差。

为什么我们在CPU使用率低的时候看到CPU节流?tldr基本上是Linux内核中的一个错误,它限制了CPU不必要的容器。如果你对它的性质感到好奇,我邀请你去看看戴夫·奇卢克的伟大演讲,还有一个书面版本。

经过多次长时间的讨论,我们决定取消对所有直接或间接位于用户关键路径上的服务的CPU限制。

这不是一个容易的决定,因为我们重视集群的稳定性。过去,我们在集群中进行了一些不稳定的实验,服务使用了过多的资源,并中断了同一节点中存在的所有其他服务。那一次有点不同,我们更了解我们的服务需要什么,并有一个很好的战略来推出这一点。

在过去,我们看到一些节点进入NotReady状态,主要是因为一些服务在节点中使用了太多资源。

我们决定将这些服务放在一些特定的节点(受污染的节点)上,这样这些服务就不会中断所有的“有界”服务。我们拥有更好的控制能力,如果某个节点出现任何问题,我们可以更轻松地进行识别。我们通过污染一些节点并向“无界”的服务添加容忍度来做到这一点。请查看文档,了解如何做到这一点。

我们主要担心的是服务使用了太多的资源,导致节点变得没有响应。因为我们现在对集群中运行的所有服务(使用Datadog)都有可靠的可观察性,所以我已经分析了我们想要“解除绑定”的每个服务的几个月的使用情况。我只是将最大CPU使用率指定为CPU请求。这将确保在节点中分配了空间。如果K8不会尝试调度该节点中的任何其他服务。

您可以在该图中看到峰值cpu使用率为242mcpu core(0.242 cpu core)。只需取此数字并使其稍高一点即可成为CPU请求。您可以注意到,由于服务是面向用户的,因此峰值CPU使用率与峰值流量时间相匹配。

对您的内存使用和请求执行相同的操作,您就可以完成所有工作了!

即使您的服务将消耗比请求更多的CPU使用量,给定节点中所有服务的“松弛”组合应该可以补偿突发。

缺点是我们损失了“容器密度”,即可以在单个节点中运行的容器数量。在流量较低的时候,我们可能会出现大量的“松弛”。您也可能会遇到一些CPU使用率较高的问题,但是节点自动伸缩应该会帮助您解决这个问题。

经过几周的实验,我很高兴公布了非常棒的结果,我们已经看到我们修改的所有服务的延迟都有了很大的改善:

最好的结果出现在我们的主登陆页面(Buffer.com),在那里我们的服务速度提高了22倍!

该错误已经修复,并合并到运行4.19或更高版本的Linux发行版内核中(再次向Dave Chiluk致敬,感谢他发现并修复了该错误)。

然而,至于2020年9月2日,当我们阅读Kubernetes问题时,我们可以看到各种Linux项目不断地引用这个问题,所以我猜一些Linux发行版仍然有这个错误,并且正在努力集成修复程序。

如果您使用的是内核版本低于4.19的Linux发行版,我建议您为您的节点升级到最新的Linux发行版,但无论如何,您都应该尝试取消CPU限制,看看是否有任何限制。下面是各种托管Kubernetes服务或Linux发行版的非穷尽列表:

Debian:最新版本的Buster已经修复了,它看起来相当新(2020年8月)。某些以前版本可能已经打了补丁

EKS自2019年12月开始修复。如果您的AMI版本低于该版本,请升级您的AMI。

Kops:从2020年6月开始,Kops 1.18+将开始使用Ubuntu 20.04作为默认主机镜像。如果您使用的是较低版本的Kops,则可能需要等待修复。我们目前正处于这种情况。

GKE(Gogle Cloud):我不太确定它的状态是什么,但我相信它可能已经被修复了。

PS:我不完全确定确切的日期,如果你有更准确的信息,请随意评论。

我不确定是否完全解决了这个问题。一旦我们找到一个已经实现了修复的内核版本,我会试一试,并会相应地更新这篇文章。如果有人升级了,我很想知道他们的结果。

如果您在Linux(不管是Kubernetes/Mesos/Sarm)下运行Docker容器,您的容器可能会因为节流而表现不佳。

如果您的容器需要快速运行,请始终关注它们的CPU节流指标。

我希望这篇文章能帮助您在运行的容器上获得性能提升。如果是这样的话,请毫不犹豫地分享或评论,总是有一些难看的评论