加入收藏 | 设为首页 | 会员中心 | 我要投稿 宁德站长网 (https://www.0593zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 云计算 > 正文

增加K8S CPU limit会降低服务性能?

发布时间:2022-04-15 15:09:33 所属栏目:云计算 来源:互联网
导读:众所周知,Kubernetes QOS 分为三个级别: Guaranteed:Pod 里的每个容器都必须有内存/CPU 限制和请求,而且值必须相等。如果一个容器只指明limit而未设定request,则request的值等于limit值。 Burstable:Pod 里至少有一个容器有内存或者 CPU 请求且不满足 G
  众所周知,Kubernetes QOS 分为三个级别:
 
  Guaranteed:Pod 里的每个容器都必须有内存/CPU 限制和请求,而且值必须相等。如果一个容器只指明limit而未设定request,则request的值等于limit值。
 
  Burstable:Pod 里至少有一个容器有内存或者 CPU 请求且不满足 Guarantee 等级的要求,即内存/CPU 的值设置的不同。
 
  BestEffort:容器必须没有任何内存或者 CPU 的限制或请求。
 
  谷歌的最佳实践告诉你,重要服务一定要配置 Guaranteed 的,这样在资源不足的时候可以保证你的重要服务不被驱逐。
 
  最佳实践要求你这样配置是从运维和后期运营的角度来说的,团队刚起步,不设置资源请求和限制的情况下基本可以正常工作,但随着团队和项目的增长,您将开始遇到稳定性问题。服务之间相互影响,这时候可能需要为服务添加限制,并且可以让您免于遇到许多令人头疼的问题。
 
  这里我们应该已经清楚,通过遵循最佳实践,使整个集群具有更大的灵活性和可靠性。
 
  但是当涉及到 CPU 限制时,事情就变得有趣了。CPU 是可压缩资源。如果您的应用开始达到 CPU 限制,Kubernetes 就会开始限制您的容器。这意味着 CPU 将受到人为限制,使您的应用程序性能可能更差!
 
  1. 为什么会这样呢?
 
  因为当你在容器编排器中设置硬 CPU 限制时,内核使用完全公平调度程序 (CFS) Cgroup来强制执行这些限制。CFS Cgroup 机制使用两个设置来管理 CPU 分配:配额和周期。当应用程序在给定时间段内使用超过其分配的 CPU 配额时,它会受到限制,直到下一个时间段。
 
  cgroup 的所有 CPU 指标都位于​​/sys/fs/cgroup/cpu,cpuacct/<container>​​. 配额和期间设置位于​​cpu.cfs_quota_us​​和中​​cpu.cfs_period_us​​。
 
  您还可以查看限制指标 cpu.stat。在里面 cpu.stat 你会发现:
 
  nr_periods– cgroup 任何线程可运行的周期数
 
  nr_throttled– 应用程序使用其全部配额并受到限制的可运行周期数
 
  throttled_time– 控制 cgroup 中各个线程的总时间
 
  2. 举个简单的例子
 
  单线程应用程序在具有 cgroup 约束的 CPU 上运行。此应用程序需要 200 毫秒的处理时间来完成一个请求。不受约束,它的响应看起来如下图。
 
  没有配置限制的请求
 
  现在,假设我们为应用程序分配了 0.4 CPU 的 CPU 限制。这意味着应用程序每 100 毫秒周期获得 40 毫秒的运行时间——即使这些时间 CPU 没有其他工作要做。200 毫秒的请求现在需要 440 毫秒才能完成。
 
  配置限制的请求
 
  这个时候你查看下所在容器路径下的 cpu.stat throttled_time 你会发现被限制了 240ms(对于每 100 毫秒的周期,应用程序只能运行 40 毫秒,并被限制 60 毫秒。它已被限制了 4 个周期,因此 4 * 60 = 240 毫秒。)
 
  换一个通俗点的说法,当您要求 1 个 CPU 时,这意味着您的应用程序每秒可以使用 1 个 CPU 内核。如果它是一个单线程,它将能够一直使用一个内核。但是,如果它有 2 个线程,则每秒可以无限制地使用 2 个核心秒。因此,有了这个限制,它可以在 1/2 秒内完全使用 2 个核心,然后会受到限制。(虽然这并不是真正以秒为单位来衡量的,实际是us,但我发现这样更容易理解)。
 
  看到这里,你可能会说,这只是一种约束,超出范围的资源,就是不能使用,否则将被限制。
 
  3. 什么原因导致的呢?
 
  本质上来说,这个问题是 linux 内核导致,具体可以看下这个视频:​​​​https://www.youtube.com/watch?v=UE7QX98-kO0​​​​
 
  这个视频大概意思是这样的。
 
  这里有一个多线程守护进程的例子,它有两个工作线程,每个工作线程都固定在自己的核心上。如下图,第一个图显示了 cgroup 在一段时间内的全局配额。这从 20ms 的配额开始,这与 0.2 CPU 相关。中间的图表显示分配给每个 CPU 队列的配额,底部的图表显示实际工作线程在其 CPU 上运行的时间。
 
  在 10 毫秒:
 
  Worker 1 收到了一个请求。
 
  一部分配额从全局配额转移到 CPU 1 的每个 CPU 队列。
 
  Worker 1 需要 5ms 来处理和响应请求。
 
  在 17 毫秒:
 
  Worker 2 收到了一个请求。
 
  一部分配额从全局配额转移到 CPU 2 的每个 CPU 队列。
 
  Worker 1 需要精确 5 毫秒来响应请求的机会是非常不现实的。如果请求需要其他一些处理时间会发生什么?

 
  在 30 毫秒:
 
  Worker 1 收到了一个请求。
 
  Worker 1 只需要 1 毫秒来处理请求,而 CPU 1 的每个 CPU 存储桶上还剩下 4 毫秒。
 
  由于每个 CPU 运行队列上还有剩余时间,但 CPU 1 上没有更多可运行线程,因此设置了一个计时器以将 slack 配额返回给全局存储桶。这个定时器在worker 1停止运行后设置为7ms。
 
  在 38 毫秒:
 
  CPU 1 上设置的 slack 计时器触发并将除 1 ms 之外的所有配额返回到全局配额池。
 
  这会在 CPU 1 上留下 1 毫秒的配额。
 
  在 41 毫秒:
 
  Worker 2 收到一个长请求。
 
  所有剩余时间都从全局存储桶转移到 CPU 2 的 per-CPU 存储桶,Worker 2 使用所有时间。
 
  在 49 毫秒:
 
  CPU 2 上的 Worker 2 现在在未完成请求的情况下受到限制。
 
  尽管 CPU 1 仍有 1ms 的配额,但仍会发生这种情况。
 
  虽然 1 毫秒可能对双核机器没有太大影响,但这些毫秒在高核数机器上加起来。如果我们在 88 核 (n) 机器上遇到此行为,我们可能会在每个周期内耗费 87 (n-1) 毫秒。那可能无法使用的 87 毫秒或 0.87 CPU(每个Container)。这就是我们通过过度节流来达到低配额使用的方式。在最好的情况下,如果修复,使受影响的应用程序的每个实例的可用 CPU 增加 0.87,或者所需的 CPU 配额相应减少。这些优势将在我们的集群中提高应用程序密度并缩短应用程序响应时间。
 
  当 8 核和 10 核机器这个问题基本上没有引起注意。现在核心数量风靡一时,这个问题变得更加明显。这就是为什么我们注意到在更高核心数的机器上运行同一应用程序时会增加限制。
 
  总结来说,时钟偏差限制问题,这导致每个时期的配额都受到严格限制。这个问题一直是存在的,至少自提交 512ac999 和内核 v4.18 以来,它就是这样工作的。
 

(编辑:宁德站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!