Kubernetes:移除 CPU 限制,服务运行更快
原文:Kubernetes: Make your services faster by removing CPU limits
作者:ERIC KHUN
我们(Buffer)早在 2016 年就开始使用 Kubernetes 了。我们使用 kops 对 Kubernetes 集群进行管理,其中包含了大约 60 个运行在 AWS 的节点,运行着 1500 个左右的容器。我们的微服务迁移之路充满坎坷。在和 Kubernetes 相处多年以后,我们还是会时不时遭到它的毒打。本文接下来要讨论的案例就是这样——CPU Limit 是一头披着狼皮的羊。
CPU 限制和流控
Google 等公司强烈建议设置 CPU 限制。如果不进行这一限制,节点上的容器可能会耗尽所有 CPU 资源,这可能会引发多种意料之外的事故——例如导致 Kubernetes 关键进程(比如说 kubelet
)停止响应。因此理论上为容器设置 CPU 限制能够很好的对节点进行保护。
该特性能限制一个容器在给定周期内(缺省为 100 毫秒)能够消耗的最大 CPU 时间。受限的容器永远无法消耗超过限制的 CPU 资源。Kubernetes 使用 CFS 配额 技术对容器进行流控,制止其使用超限的 CPU 资源。也就是说 CPU 的使用受到了限制,会让容器变慢(可能增加响应时间)。
不设置 CPU 限制会怎样
我们很不幸地遭遇了这种情况,在每个节点上运行的 kubelet
进程停止响应。此时节点进入 NotReady
状态,并且其上运行的容器被重新调度到其它节点,又引发其它节点的问题——这可能不是我们希望的情况。
发现流控和延迟的问题
容器运行过程中又一个关键指标就是 throttling
。该指标显示了你的容器受到流控的次数。我们有一个奇怪的发现:不管容器的 CPU 消耗是否逼近了上限,都会遇到流控。下图是我们一个主要 API 的表现:
这里的 CPU 上限设置为 800m
,而实际运行的最大值仅为 200m
。如此一来我们似乎应该认为,CPU 资源足够,无需限流。实际情况呢?
这里可以看到,虽说 CPU 的消耗远没有达到上限附近,还是发生了限流。
我们找到一些资源(github issue、Zalando 的分享、omio 的帖子),都说到了 CPU 限流引起服务响应变慢的问题。
为什么在 CPU 消耗不多的时候还是触发了限流呢?,长话短说的话,这是一个 Linux 内核的 Bug,他会对设置了 CPU 限制的容器进行不必要的流控。如果对其中的细节感兴趣,我们推荐你看看 Dave Chiluk 的精彩演讲,相关的还有一篇文字稿,其中涉及到了更多细节。
移除 CPU 限制(有副作用)
经过多次讨论,我们决定删掉所有关键服务上的 CPU 限制。
事关集群稳定,这是一个艰难的决定。我们的在集群的测试中出现过一些不稳定的情况,部分服务占用过多资源,破坏了同一节点内的其它服务。
如何在去除限制之后保障集群稳定性
隔离不限制 CPU 的服务
因为有的服务会占用太多资源,导致节点进入 NotReady
状态。我们决定把一些这些服务放到特定节点上(taint
),如此一来,不受限的服务就不会干扰到受限服务,让我们可以轻易地分辨节点的故障原因。
为容器分配合适的 CPU 和内存 requests
我们最担心的事情就是服务占用太多资源导致节点不可用。然而我们使用 Datadog 让集群变得易于监控,我们花了几个月的时间,对每个我们希望放开限制的服务的运行情况进行观察,根据监控结果,我们将这些容器的 CPU 请求值设置为观测到的上限的 120%。这样就保障了容器的资源需求。
上图可见,CPU 用量的峰值为 242m
,我们就根据这个峰值来设置其 CPU 请求值。这个服务是面向用户的,因此其资源使用的波动和流量波动是相匹配的。
同样的方法可以用在内存的设置上。如果觉得还不放心,可以使用 HPA 来增强服务的弹性,并在节点资源不足时告警,或者使用集群的自动扩容能力。
这个操作客观上会降低容器密度。
结果
在几周的调整之后,我们得到了下表的结果,表格中可以看到,所有服务的延迟都大大降低了。
我们的着陆页面(buffer.com),其响应速度提高了 22 倍。
这个内核问题修复了么
4.19 或更高版本的 Linux 发行版已经纠正了该问题(再次感谢 Dave Chiluk 发现并解决了这个问题)。
然而直到 2020 年 9 月 2 号,阅读相关 Issue 时,我们还是看到很多 Linux 项目在引用这个问题,因此我猜测还有一些 LInux 发行版存在该问题。
如果你使用的 Linux 发行版使用的内核小于 4.19,建议为节点进行内核升级。但是任何情况下,我们都建议读者删掉 CPU 限制,看看监控中的流控数据。下面的列表并不完全:
- Debian:Buster 版本最近 进行了修复,可能有些早期版本也做了补丁。
- Ubuntu:Ubuntu Focal Fosa 20.04 已经修复。
- EKS 在 2019 年就修复了这个问题。如果版本落后的话,建议升级一下 AMI。
- kops 在 2020 年 6 月的
kops 1.18
中开始使用Ubuntu 20.04
作为缺省的主机镜像。然而如果使用的是低版本 kops,可能就需要等着补丁发布了(我们也在等)。 - GKE:在 2020 年 1 月 修复了这个问题。但是看起来这个情况还时有发生
这样就解决了么
我不确定是否完全解决。我希望拿到修复后的内核之后,尝试根据本文内容进行实现。
总结
- 如果你在 Linux 下运行 Docker容器(不管是Kubernetes/Mesos/Swarm),你可能会因为节流而导致容器表现不佳。
- 把你的发行版升级到最新版本,希望这个错误得到修复
- 取消 CPU 限制是解决这个问题的一个办法,但这是很危险的,应该格外小心(最好先升级你的内核,并先监控节流)。
- 如果你取消了 CPU 限制,请仔细监控节点中 CPU 和内存的使用情况,并确保你的 CPU 请求够大,一个安全的方法是,如果资源使用量大,就使用 HPA 来创建新的 Pod,这样 Kubernetes 就会安排在空间富余的节点中了。