如何优化生产环境下的Kubernetes资源分配
我们用curl进行一番手动测试之后,决定开始将流量转移到Kubernetes上的新服务。负载为1%时,一切看起来很棒;然后提高到10%,依然很棒;之后提高到50%,服务突然开始陷入崩溃循环。我的第一反应是,将服务从4个副本增加到20个。这有点帮助,服务处理流量,但pod仍然陷入崩溃循环。
我使用kubectl describe进行一些调查后了解到,由于OOMKilled即内存不足,Kubelet在终止pod。我深入探究后意识到,我从另一个部署复制粘贴YAML时,设置了一些限制性过强的内存限制。这段经历让我开始思考如何有效地设置请求和限额。
一、请求vs限制
Kubernetes允许对CPU、内存和本地短暂存储(v1.12中的测试版功能)之类的资源设置可配置的请求和限制。CPU等资源是可压缩的,这意味着可以使用CPU管理策略来限制容器。内存等其他资源由Kubelet监控,如果超过限制就被终止。使用请求和限制的不同配置,就可以针对每个工作负载实现不同的服务质量。
1.限制
限制是允许工作负载消耗的上限。超过请求的限制阈值将触发Kubelet终止pod。如果未设置限制,工作负载就会消耗某个节点上的所有资源。如果运行的多个工作负载没有限制,将按照尽力原则分配资源。
2.请求
调度程序使用请求为工作负载分配资源。工作负载可以使用所有请求的资源,无需Kubernetes的干预。如果未设置限制且超过请求阈值,容器将受限制,只能使用请求的资源。如果设置了限制但未设置任何请求,请求的资源将与请求的限制相匹配。
3.服务质量
有三种基本的服务质量(QoS)可通过资源和限制来实现DD最佳的QoS配置取决于工作负载的要求。
图1
4.保证的QoS
保证的QoS可通过仅设置限制来实现。这意味着容器可以使用调度程序为其配置的所有资源。对于受CPU限制且相对可预测的工作负载来说,比如处理请求的Web服务器,这是很好的QoS。
图2
5.可突发式QoS
可突发式QoS通过同时设置请求和限制(请求低于设置)来配置。这意味着可以保证容器使用最多是配置请求的资源,如果某个节点上有,可以使用资源的全部配置限额。这对于短暂使用资源或需要密集初始化过程的工作负载来说很有用。一个例子就是构建Docker容器的worker节点或运行未经过优化的JVM进程的容器。
图3
6.尽力式QoS
尽力式QoS通过既不设置请求也不设置限制来配置。这意味着容器可以使用计算机上的任何可用资源。从调度程序的角度来看,这是优先级最低的任务,会在突发式QoS和保证式QoS配置之前被终止。这对于可中断、低优先级的工作负载(比如迭代运行的幂等优化过程)来说很有用。
图4
二、设置请求和限制
要设置合理的请求和限制,关键是找到单个pod的断点(breaking point)。若使用几种不同的负载测试方法,可以在应用程序进入到生产环境之前了解其不同的故障模式。被推向极限时,几乎每个应用程序都有各自的一组故障模式。
要准备测试,确保将副本计数设为1,并从一组保守的限制开始,比如:
# limits might look something like replicas: 1 ... cpu: 100m # ~1/10th of a core memory: 50Mi # 50 Mebibytes
注意,在此过程中使用限制很重要,以便清楚地看到结果(内存使用率高时遏制CPU和终止pod)。测试迭代完成后,一次更改一个资源限制(CPU或内存)。
1.Ramp-up测试
ramp-up测试逐渐增加负载,直到服务在不堪重负而失效或测试完成。
图5
如果ramp-up测试突然失败,这表明资源限制过于苛严。观察到性能突然变化时,将资源限制增加一倍、重复测试,直到测试成功完成。
图6
资源限制接近最优时(至少对于Web风格的服务来说),性能会逐渐稳定地下降。
图7
如果负载增加时性能没有变化,可能为工作负载分配了太多的资源。
2.持续时间测试
运行ramp-up测试并调整限制后,可以进行持续时间测试了。持续时间测试是指在一段延长的时间内(至少10分钟,但越长越好)添加一致的负载,但又恰好在断点之下。
图8
该测试的目的是识别在短暂的ramp-up测试中发现不了的内存泄漏和隐藏的队列机制。如果在此阶段进行调整,它们应该很小(变化>105)。好的结果将表明性能在测试持续期间保持稳定。
图9
3.保留失效日志
进行测试阶段时,记录服务失败时的执行情况至关重要。可以将故障模式添加到运行手册(run book)和说明文档,排查生产环境中的问题时很有用。我们在测试时发现了一些观察到的故障模式:
- 内存慢慢增加
- CPU固定在100%
- 500s
- 响应时间长
- 请求丢弃
- 响应时间差异大
将日志保存起来,以备不时之需,因为有一天它们可以为你或同事在排查问题时帮大忙。
三、实用的工具
虽然可以使用Apache Bench之类的工具添加负载、使用cAdvisor之类的工具直观地显示资源利用率,但一些工具更适合设置资源限制。
1.Loader.IO
Loader.io是一种托管的负载测试服务。它让你可以配置ramp-up测试和持续时间测试,测试运行时直观地显示应用程序的性能和负载,并迅速开始和停止测试。测试结果历史记录存储起来,因此资源限制变化时很容易比较结果。
图10
2.Kubescope CLI
Kubescope CLI这款工具在Kubernetes中(或本地)运行,可直接从Docker收集和直观显示容器度量指标。它使用cAdvisor之类的工具或另一项集群指标收集服务,每秒(而不是每隔10秒至15秒)收集一次指标。由于间隔10秒至15秒,你在测试期间大有时间错过瓶颈。若使用cAdvisor,你得为每次测试寻找新的pod,因为Kubernetes在超过资源限制时终止pod。Kubescope CLI直接从Docker收集指标(可以设置自己的间隔),并使用正则表达式来选择和过滤想要直观显示的容器,从而解决了这个问题。
图11
结论