本文发布时间已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。

Kubernetes 资源限制的案例:可预测性 vs. 效率

有很多帖子建议不使用 Kubernetes 资源限制可能是一件非常有用的事情(例如,看在上帝的份上,停止在 Kubernetes 上使用 CPU 限制Kubernetes:通过删除 CPU 限制使您的服务更快 )。那里提出的观点完全有效 - 为因限制而不会使用的计算能力付费没有多大意义,人为地增加延迟也没有意义。这篇文章试图论证限制也有其合法用途。

作为 Grafana Labs 平台团队的站点可靠性工程师,我主要负责维护和改进产品团队使用的内部基础设施和工具,我主要尝试使 Kubernetes 升级尽可能顺利。但我也花了很多时间深入研究各种有趣的 Kubernetes 问题。本文反映了我个人的意见,社区中的其他人可能不同意。

让我们把问题颠倒过来。Kubernetes 集群中的每个 Pod 都有固有的资源限制 - 它所运行的机器的实际 CPU、内存和其他资源。如果 Pod 达到了这些物理限制,它将体验到类似于达到 Kubernetes 限制所引起的节流。

问题

没有(或有慷慨的)限制的 Pod 可以轻松消耗节点上的额外资源。然而,这有一个隐藏的成本——可用的额外资源量通常在很大程度上取决于在特定节点上调度的 Pod 及其真实的负载。这些额外的资源使每个 Pod 在实际资源分配方面都成为一个特殊的个体。更糟糕的是,很难找出 Pod 在任何给定时刻拥有的资源——当然,如果不进行对特定节点上运行的 Pod、它们的资源消耗等进行繁琐的数据挖掘是做不到的。最后,即使我们克服了这个障碍,我们也只能以一定的速率采样数据,并且只能获得我们部分调用的配置文件。这可以扩大规模,但是生成的可观察性数据的数量可能会很容易达到收益递减的程度。因此,没有简单的方法可以判断 Pod 是否出现过快速峰值,并在短时间内使用了通常两倍的内存来处理请求突发。

现在,随着黑色星期五和网络星期一的临近,企业预计流量会激增。过去的良好性能数据/基准允许企业计划一些额外的容量。但是,有关没有限制的 Pod 的数据是否可靠?通过额外的资源处理内存或 CPU 的瞬间峰值,根据过去的数据,一切可能看起来都不错。但是,一旦 Pod 封装发生变化并且额外资源变得更加稀缺,一切都可能开始看起来不同——从请求延迟略有上升到请求缓慢累积并导致 Pod OOM 终止。虽然几乎没有人真正关心前者,但后者是一个严重的问题,需要立即增加容量。

配置限制

不使用限制需要权衡——如果有额外的可用资源,它会机会性地提高性能,但会降低性能的可预测性,这可能会在未来反弹。可以使用几种方法来再次提高可预测性。让我们选择其中两个进行分析

  • 将工作负载限制配置为比请求多固定(且小)的百分比——我将其称为固定比例余量。这允许使用一些额外的共享资源,但保持每个节点的过度提交限制,并可以用来指导工作负载的最坏情况估计。请注意,限制百分比越大,工作负载之间可能发生的性能差异就越大。
  • 配置 requests = limits 的工作负载。从某种角度来看,这等同于为每个 Pod 提供一台具有受限资源的微型机器;性能是相当可预测的。这也将 Pod 置于 Guaranteed QoS 类中,这使得它只有在节点资源压力下 BestEffortBurstable Pod 被驱逐后才会被驱逐(请参阅 Pod 的服务质量)。

也可以考虑其他一些情况,但这可能是最简单的两个讨论。

集群资源经济

请注意,在上面讨论的两种情况下,我们都在有效地阻止工作负载使用它所拥有的一些集群资源,代价是获得更高的可预测性——这听起来像是为更稳定的性能付出的一笔高昂代价。让我们尝试量化那里的影响。

装箱和集群资源分配

首先,让我们讨论一下装箱和集群资源分配。有一些固有的集群效率低下会发挥作用——很难在 Kubernetes 集群中实现 100% 的资源分配。因此,将会有一定百分比的资源未分配。

当配置固定比例余量限制时,Pod 将可以使用其中相应比例的资源。如果集群中未分配资源的百分比低于我们用于设置固定比例余量限制的常量(见图,第 2 行),则所有 Pod 加在一起理论上能够用完所有节点的资源;否则,将不可避免地浪费一些资源(见图,第 1 行)。为了消除不可避免的资源浪费,应配置固定比例余量限制的百分比,使其至少等于未分配资源的预期百分比。

Chart displaying various requests/limits configurations

对于 requests = limits (见图,第 3 行),情况并非如此:除非我们能够分配所有节点的资源,否则总会有一些不可避免的资源浪费。在没有任何调整 requests/limits 的旋钮的情况下,唯一合适的方法是通过配置正确的机器配置文件来确保节点上的高效装箱。这可以通过手动完成,也可以使用各种云服务提供商的工具完成,例如用于 EKS 的 KarpenterGKE 节点自动配置

优化实际资源利用率

空闲资源也可能来自其他 Pod 未使用的资源(例如,预留的 CPU 使用率与实际 CPU 使用率的差异等),而且它们的可用性无法以任何合理的方式预测。配置限制几乎不可能利用这些资源。从另一个角度来看,如果一个工作负载浪费了大量它所请求的资源,那么重新审视其自身的资源请求可能是一件公平的事情。查看过去的数据并选择更合适的资源请求可能有助于使资源打包更紧凑(尽管会以降低其性能为代价,例如增加长尾延迟)。

结论

优化资源请求和限制很困难。虽然设置限制时更容易出错,但这些错误可能有助于在以后通过提供更多关于工作负载在边缘条件下的行为的见解来防止灾难。在某些情况下,设置限制不太合理:批量工作负载(对延迟不敏感,例如非实时视频编码)、尽力而为的服务(不需要那么高的可用性并且可以被抢占)、设计上具有大量剩余资源的集群(各种特殊工作负载的情况,例如设计用于处理峰值的服务)。

另一方面,不应不惜一切代价避免设置限制——即使弄清楚限制的“正确”值更加困难,并且配置错误的值会产生更不利的后果。配置限制可以帮助您了解工作负载在极端情况下的行为,并且有一些简单的策略可以帮助您推断出正确的值。这是高效资源利用率和性能可预测性之间的权衡,应该这样看待。

资源使用具有峰值的工作负载还存在经济方面的问题。始终拥有“免费”资源并不能激励产品团队提高性能。足够大的峰值可能会轻易引发效率问题,甚至在试图捍卫产品 SLA 时出现问题——因此,在评估任何风险时,这可能是一个值得提及的点。