k8s 中无声的性能杀手:cpu thorttling(限流)
k8s 中,每个 pod 使用 cpu request 和 limit 来申请和管理实际使用的资源。
request 仅作用于分配期,limit 才是运行期时真正限制的指标。
例如:一个 poc,cpu_request : 2000mi,cpu_limit : 4000mi (1000mi 接近一个 cpu 时间片,4000mi 代表 4cpu)
k8s 使用 linux 的 cfs 调度器来完成对 limit 限制的调度,保证 pod 不会使用超过 limit 限制的 cpu 资源。
cfs 调度器每 100ms 调度一次,如果进程在前 50ms 就用光了在这 100ms 分配的 cpu 时间片,后 50ms 就没有 cpu 可用,需要等待到下一个调度周期,这个过程就是 cpu thorttling , 中文名称是 cpu 限流/节流。笔者倾向于叫 cpu 限流。
从这上面看,一切都正常,设定了 limit,那么就按照设定的 limit 来运行。
问题来自于这些地方,并且非常严重:
linux kernel 的 cfs 有 bug,有一些不应该触发限流的场景,会触发限流。该问题在 k8s 的 repo 中有讨论,一部分 fix 合并到了 kernel 4.18 和 5.4 版本。但是依然有反馈还是存在会触发不必要的限流。#67577 #97445
使用 k8s 时,如果没有注意到 cpu thortlling 的监控,就会导致应用产生 cpu 限流,从而导致 rt 下降。一部分公司的私有云甚至根本不提供 cpu thorttling 监控。
信号堆叠问题,cfs 调度 100ms 一次,但是大多数监控都是分钟级别,少数能做到秒级,很难识别到 100ms 调度周期中 cpu limit usage 超过 100%的情况。大多数的表现是,cpu 使用率只有 25%-50%左右,但是应用性能却突然变差。
应用有突发流量翻倍/java 应用 gc 等场景,也都有可能导致 cpu 限流,从而影响性能。
k8s 中的 limit 目前在业界被认为是一个反模式,有 k8s 开发人员倾向于彻底取消 limit。但是没有其他可靠的配额限制手段时,取消 limit 还是太激进了。
cpu 限流的解决方案:
超额配置 limit,以保证突发 cpu 使用不会触发限流。该选项会导致资源浪费严重(因为高优先级 pod 的 limit=request),为了罕见情况超配资源。
cpu brust , cpu brust 功能可以实现,如果 pod 平时的使用的 cpu 小于 limit,差值的部分就可以积累下来,在该 pod 使用 cpu 超标时,从积累部分扣除,从而保证整体的 cpu 使用率平滑。在阿里的测试中,启用该选项可以降低 33%的限流(33%-->0%),rt 从 111ms 降低到 71ms。
目前社区有在讨论在高优先级(request = limit)的 pod 中取消 cfs,因为它的资源是完全充足的,不需要通过 cfs 来限制。
以上这些解决方案,都依赖针对 cpu thorlling 的监控,有了监控才能知道有没有问题,实施了解决方案以后有没有改善。
如果使用私有云,而云部门没有提供相关监控的话,可以在容器中使用以下命令查看 cpu 限流情况。
通过 nr_throttled / nr_periods 即可计算出限流率。
我们实际中的一个案例:cpu 密集型服务,cpu = 4c , 按分钟统计的 cpu 使用为 25%;流量:每小时会一次 qps 翻倍的情况。平均耗时为 12ms。调整 cpu=8c,平均耗时降低为 4ms.
cpu 最高使用率 60%,依然出现了很多 cpu 限流
版权声明: 本文为 InfoQ 作者【你头顶的那片星空】的原创文章。
原文链接:【http://xie.infoq.cn/article/398f267a16335362f7c5158e2】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论