如何优化生产环境下的Kubernetes资源分配

okzhchy 2018-12-26

我在使用Kubernetes的头一天将应用程序Docker容器化,并部署到生产集群。我将Buffer的其中一个最高吞吐量(和低风险)端点从整体式应用程序迁移出来。这个端点造成了越来越大的麻烦,偶尔会影响优先级更高的其他流量。

如何优化生产环境下的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)可通过资源和限制来实现――最佳的QoS配置取决于工作负载的要求。

如何优化生产环境下的Kubernetes资源分配

图1

4.保证的QoS

保证的QoS可通过仅设置限制来实现。这意味着容器可以使用调度程序为其配置的所有资源。对于受CPU限制且相对可预测的工作负载来说,比如处理请求的Web服务器,这是很好的QoS。

如何优化生产环境下的Kubernetes资源分配

图2

5.可突发式QoS

可突发式QoS通过同时设置请求和限制(请求低于设置)来配置。这意味着可以保证容器使用最多是配置请求的资源,如果某个节点上有,可以使用资源的全部配置限额。这对于短暂使用资源或需要密集初始化过程的工作负载来说很有用。一个例子就是构建Docker容器的worker节点或运行未经过优化的JVM进程的容器。

如何优化生产环境下的Kubernetes资源分配

图3

6.尽力式QoS

尽力式QoS通过既不设置请求也不设置限制来配置。这意味着容器可以使用计算机上的任何可用资源。从调度程序的角度来看,这是优先级最低的任务,会在突发式QoS和保证式QoS配置之前被终止。这对于可中断、低优先级的工作负载(比如迭代运行的幂等优化过程)来说很有用。

如何优化生产环境下的Kubernetes资源分配

图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测试逐渐增加负载,直到服务在不堪重负而失效或测试完成。

如何优化生产环境下的Kubernetes资源分配

图5

如果ramp-up测试突然失败,这表明资源限制过于苛严。观察到性能突然变化时,将资源限制增加一倍、重复测试,直到测试成功完成。

如何优化生产环境下的Kubernetes资源分配

图6

资源限制接近最优时(至少对于Web风格的服务来说),性能会逐渐稳定地下降。

如何优化生产环境下的Kubernetes资源分配

图7

如果负载增加时性能没有变化,可能为工作负载分配了太多的资源。

2.持续时间测试

运行ramp-up测试并调整限制后,可以进行持续时间测试了。持续时间测试是指在一段延长的时间内(至少10分钟,但越长越好)添加一致的负载,但又恰好在断点之下。

如何优化生产环境下的Kubernetes资源分配

图8

该测试的目的是识别在短暂的ramp-up测试中发现不了的内存泄漏和隐藏的队列机制。如果在此阶段进行调整,它们应该很小(变化>105)。好的结果将表明性能在测试持续期间保持稳定。

如何优化生产环境下的Kubernetes资源分配

图9

3.保留失效日志

进行测试阶段时,记录服务失败时的执行情况至关重要。可以将故障模式添加到运行手册(run book)和说明文档,排查生产环境中的问题时很有用。我们在测试时发现了一些观察到的故障模式:

  • 内存慢慢增加
  • CPU固定在100%
  • 500s
  • 响应时间长
  • 请求丢弃
  • 响应时间差异大

将日志保存起来,以备不时之需,因为有一天它们可以为你或同事在排查问题时帮大忙。

三、实用的工具

虽然可以使用Apache Bench之类的工具添加负载、使用cAdvisor之类的工具直观地显示资源利用率,但一些工具更适合设置资源限制。

1.Loader.IO

Loader.io是一种托管的负载测试服务。它让你可以配置ramp-up测试和持续时间测试,测试运行时直观地显示应用程序的性能和负载,并迅速开始和停止测试。测试结果历史记录存储起来,因此资源限制变化时很容易比较结果。

如何优化生产环境下的Kubernetes资源分配

图10

2.Kubescope CLI

Kubescope CLI这款工具在Kubernetes中(或本地)运行,可直接从Docker收集和直观显示容器度量指标。它使用cAdvisor之类的工具或另一项集群指标收集服务,每秒(而不是每隔10秒至15秒)收集一次指标。由于间隔10秒至15秒,你在测试期间大有时间错过瓶颈。若使用cAdvisor,你得为每次测试寻找新的pod,因为Kubernetes在超过资源限制时终止pod。Kubescope CLI直接从Docker收集指标(可以设置自己的间隔),并使用正则表达式来选择和过滤想要直观显示的容器,从而解决了这个问题。

如何优化生产环境下的Kubernetes资源分配

图11

结论

只有在你知道一项服务何时坏掉、如何坏掉,它才准备好用于生产环境,对此我深有体会。希望你能从我的错误中吸取教训,利用其中一些方法对部署的环境设置资源限制和请求。这将为你的系统增添弹性和可预测性,从而使客户满意,但愿帮助你高枕无忧。

作者:布加迪编译

原文:http://developer.51cto.com/art/201812/588884.htm

相关推荐