本文已发布超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
功能亮点:CPU 管理器
这篇博客文章介绍了 CPU 管理器,这是 Kubernetes 中的一个测试版功能。CPU 管理器功能通过为某些 Pod 容器分配独占 CPU,使得 Kubelet(Kubernetes 节点代理)能够更好地放置工作负载。
听起来不错!但是 CPU 管理器能帮到我吗?
这取决于您的工作负载。Kubernetes 集群中的单个计算节点可以运行多个 Pod,其中一些 Pod 可能正在运行 CPU 密集型工作负载。在这种情况下,Pod 可能会争用该计算节点中可用的 CPU 资源。当这种争用加剧时,工作负载可能会移动到不同的 CPU,具体取决于 Pod 是否被节流以及调度时 CPU 的可用性。也可能存在工作负载对上下文切换敏感的情况。在上述所有情况下,工作负载的性能都可能受到影响。
如果您的工作负载对这种情况敏感,则可以启用 CPU 管理器,通过为您的工作负载分配独占 CPU 来提供更好的性能隔离。
CPU 管理器可能有助于具有以下特征的工作负载
- 对 CPU 节流效应敏感。
- 对上下文切换敏感。
- 对处理器缓存未命中敏感。
- 受益于共享处理器资源(例如,数据和指令缓存)。
- 对跨插槽内存流量敏感。
- 敏感或需要来自同一物理 CPU 核心的超线程。
好的!我该如何使用它?
使用 CPU 管理器很简单。首先,在集群的计算节点上运行的 Kubelet 中使用 Static 策略启用 CPU 管理器。然后将您的 Pod 配置为处于有保障的服务质量 (QoS) 类。为需要独占核心的容器请求整数个 CPU 核心(例如,1000m
、4000m
)。像以前一样创建您的 Pod(例如,kubectl create -f pod.yaml
)。瞧,CPU 管理器将根据它们的 CPU 请求为 Pod 中的每个容器分配独占 CPU。
apiVersion: v1
kind: Pod
metadata:
name: exclusive-2
spec:
containers:
- image: quay.io/connordoyle/cpuset-visualizer
name: exclusive-2
resources:
# Pod is in the Guaranteed QoS class because requests == limits
requests:
# CPU request is an integer
cpu: 2
memory: "256M"
limits:
cpu: 2
memory: "256M"
请求两个独占 CPU 的 Pod 规范。
嗯……CPU 管理器是如何工作的?
对于 Kubernetes 和本博客文章的目的,我们将讨论大多数 Linux 发行版中可用的三种 CPU 资源控制类型。前两个是 CFS 份额(我在该系统上获得的 CPU 时间的加权公平份额是多少)和 CFS 配额(我在一个周期内获得的 CPU 时间的硬上限是多少)。CPU 管理器使用第三个控制,称为 CPU 亲和性(我允许在哪些逻辑 CPU 上执行)。
默认情况下,Kubernetes 集群的计算节点上运行的所有 Pod 和容器都可以在系统中的任何可用核心上执行。可分配的份额和配额的总量受显式为 Kubernetes 和系统守护进程保留的 CPU 资源的限制。但是,可以使用 Pod 规范中的 CPU 限制指定 CPU 时间的使用限制。Kubernetes 使用 CFS 配额来对 Pod 容器强制执行 CPU 限制。
当使用“静态”策略启用 CPU 管理器时,它会管理一个共享的 CPU 池。最初,这个共享池包含计算节点中的所有 CPU。当 Kubelet 创建具有有保障 Pod 中整数 CPU 请求的容器时,该容器的 CPU 将从共享池中删除,并在容器的生命周期内独占分配。其他容器将从这些独占分配的 CPU 中迁移出去。
所有非独占 CPU 容器(突发、尽力而为和具有非整数 CPU 的有保障容器)都在共享池中剩余的 CPU 上运行。当具有独占 CPU 的容器终止时,其 CPU 会被添加回共享 CPU 池。
请提供更多详细信息……
上图显示了 CPU 管理器的结构。CPU 管理器使用容器运行时接口的 UpdateContainerResources
方法来修改容器可以运行的 CPU。管理器会定期使用 cgroupfs
来协调每个正在运行的容器的 CPU 资源的当前状态。
CPU 管理器使用 策略来决定 CPU 的分配。有两种已实施的策略:None 和 Static。默认情况下,从 Kubernetes 1.10 版本开始,CPU 管理器启用的是 None 策略。
Static 策略将独占 CPU 分配给请求整数 CPU 的有保障 QoS 类中的 Pod 容器。在尽力而为的基础上,静态策略尝试按以下顺序拓扑分配 CPU
- 如果可用且容器请求至少一个插槽的 CPU,则分配同一处理器插槽中的所有 CPU。
- 如果可用且容器请求一个完整的核心的 CPU,则分配同一物理 CPU 核心的所有逻辑 CPU(超线程)。
- 分配任何可用的逻辑 CPU,并优先从同一插槽获取 CPU。
CPU 管理器如何提高性能隔离?
启用 CPU 管理器静态策略后,工作负载可能会因以下原因之一而性能更好
- 独占 CPU 可以分配给工作负载容器,但不分配给其他容器。这些容器不共享 CPU 资源。因此,当涉及到攻击者或位于同一位置的工作负载时,由于隔离,我们期望获得更好的性能。
- 由于我们可以在工作负载之间划分 CPU,因此工作负载使用的资源之间的干扰减少了。这些资源可能还包括缓存层次结构和内存带宽,而不仅仅是 CPU。这有助于提高工作负载的整体性能。
- CPU 管理器在尽力而为的基础上按拓扑顺序分配 CPU。如果整个插槽是空闲的,则 CPU 管理器会将空闲插槽中的 CPU 独占分配给工作负载。这可以通过避免任何跨插槽流量来提高工作负载的性能。
- 有保障 QoS Pod 中的容器会受到 CFS 配额的限制。非常突发的工作负载可能会被调度,在周期结束前耗尽它们的配额,并被节流。在此期间,使用这些 CPU 可能有也可能没有有意义的工作可做。由于 CPU 配额和静态策略分配的独占 CPU 数量之间的资源计算方式一致,因此这些容器不受 CFS 节流的约束(配额等于配额周期内最大可能的 CPU 时间)。
好的!好的!你有任何结果吗?
很高兴你问了!为了了解在 Kubelet 中启用 CPU 管理器功能所提供的性能改进和隔离,我们在一个启用了超线程的双插槽计算节点(英特尔至强 CPU E5-2680 v3)上进行了实验。该节点包含 48 个逻辑 CPU(24 个物理核心,每个核心具有 2 路超线程)。在这里,我们使用基准测试和三个不同场景的真实世界工作负载来演示 CPU 管理器功能提供的性能优势和隔离。
我应该如何解释这些图表?
对于每个场景,我们都会显示箱线图,说明启用和禁用 CPU 管理器的情况下运行基准测试或真实世界工作负载的标准化执行时间及其可变性。运行的执行时间被标准化为性能最佳的运行(y 轴上的 1.00 表示性能最佳的运行,越低越好)。箱线图的高度显示了性能的变化。例如,如果箱线图是一条线,则表示运行之间的性能没有变化。在箱线图中,中间线是中位数,上线是第 75 个百分位数,下线是第 25 个百分位数。箱线图的高度(即第 75 个百分位数和第 25 个百分位数之间的差值)定义为四分位间距 (IQR)。须线显示该范围之外的数据,点显示异常值。异常值定义为分别低于下四分位数或高于上四分位数的任何数据 1.5 倍 IQR。每个实验运行十次。
防止攻击性工作负载
我们运行了来自 PARSEC 基准测试套件 的六个基准测试(受害者工作负载),这些测试与启用了和未启用 CPU 管理器功能的 CPU 压力容器(攻击者工作负载)并置。CPU 压力容器作为 Pod 在 Burstable QoS 类中运行,使用 --cpus 48
标志请求 23 个 CPU。(作为 Pod) 这些基准测试作为 Pod 运行,并在 Guaranteed QoS 类中请求一个完整插槽的 CPU(在此系统上为 24 个 CPU)。下图绘制了在启用和未启用 CPU 管理器静态策略的情况下,运行与压力 Pod 并置的基准测试 Pod 的归一化执行时间。我们看到,在所有测试用例中,启用静态策略后,性能得到改善,性能变化减少。
并置工作负载的性能隔离
在本节中,我们将演示 CPU 管理器如何在并置工作负载场景中为多个工作负载带来好处。在下面的箱线图中,我们展示了来自 PARSEC 基准测试套件的两个基准测试(Blackscholes 和 Canneal)在 Guaranteed (Gu) 和 Burstable (Bu) QoS 类中彼此并置运行时的性能,并对比启用和未启用 CPU 管理器静态策略的情况。
从左上角开始,顺时针方向,我们分别展示了在 Bu QoS 类中 Blackscholes 的性能(左上),在 Bu QoS 类中 Canneal 的性能(右上),在 Gu QoS 类中 Canneal 的性能(右下)以及在 Gu QoS 类中 Blackscholes 的性能(左下)。在每种情况下,它们分别与 Gu QoS 类中的 Canneal(左上)、Gu QoS 类中的 Blackscholes(右上)、Bu QoS 类中的 Blackscholes(右下)和 Bu QoS 类中的 Canneal(左下)并置,按顺时针方向从左上角开始。例如,Bu-blackscholes-Gu-canneal 图(左上)显示了当 Blackscholes 在 Bu QoS 类中运行时,与在 Gu QoS 类中运行的 Canneal 并置时的性能。在每种情况下,Gu QoS 类中的 Pod 请求一个完整插槽的 CPU 核心(即 24 个 CPU),而 Bu QoS 类中的 Pod 请求 23 个 CPU。
在所有测试中,并置的两个工作负载的性能都更好,性能变化更小。例如,考虑 Bu-blackscholes-Gu-canneal(左上)和 Gu-canneal-Bu-blackscholes(右下)的情况。它们显示了在启用和未启用 CPU 管理器的情况下同时运行 Blackscholes 和 Canneal 的性能。在这个特定案例中,由于 Canneal 属于 Gu QoS 类并请求整数个 CPU 核心,因此它通过 CPU 管理器获得独占核心。但 Blackscholes 也获得了独占的 CPU 集,因为它是共享池中唯一的工作负载。因此,由于 CPU 管理器,Blackscholes 和 Canneal 都获得了一些性能隔离的好处。
独立工作负载的性能隔离
本节展示了 CPU 管理器为独立的真实世界工作负载提供的性能改进和隔离。我们使用了来自 TensorFlow official models 的两个工作负载:wide and deep 和 ResNet。我们分别使用 census 和 CIFAR10 数据集用于 wide and deep 和 ResNet 模型。在每种情况下, Pod(wide and deep, ResNet)请求 24 个 CPU,这对应于一个完整插槽的核心。如图所示,CPU 管理器在这两种情况下都实现了更好的性能隔离。
限制
用户可能希望在靠近连接到外部设备(例如加速器或高性能网卡)的总线的插槽上分配 CPU,以避免跨插槽流量。CPU 管理器尚不支持这种类型的对齐。由于 CPU 管理器尽最大努力分配属于插槽和物理核心的 CPU,因此它容易受到极端情况的影响,并可能导致碎片化。CPU 管理器不考虑 isolcpus Linux 内核引导参数,尽管据报道这对于某些低抖动用例是常见的做法。
鸣谢
感谢为该功能做出贡献或提供反馈的社区成员,包括 WG-Resource-Management 和 SIG-Node 的成员。cmx.io(用于有趣的绘图工具)。
声明和免责声明
性能测试中使用的软件和工作负载可能仅针对 Intel 微处理器进行了性能优化。SYSmark 和 MobileMark 等性能测试是使用特定的计算机系统、组件、软件、操作和功能进行测量的。对任何这些因素的任何更改都可能导致结果发生变化。您应该查阅其他信息和性能测试,以帮助您充分评估您计划购买的产品,包括该产品与其他产品组合时的性能。有关更多信息,请访问 www.intel.com/benchmarks。
英特尔技术的功能和优势取决于系统配置,可能需要启用硬件、软件或服务激活。性能因系统配置而异。没有计算机系统可以绝对安全。请咨询您的系统制造商或零售商,或在 intel.com 上了解更多信息。
工作负载配置:https://gist.github.com/balajismaniam/fac7923f6ee44f1f36969c29354e3902 https://gist.github.com/balajismaniam/7c2d57b2f526a56bb79cf870c122a34c https://gist.github.com/balajismaniam/941db0d0ec14e2bc93b7dfe04d1f6c58 https://gist.github.com/balajismaniam/a1919010fe9081ca37a6e1e7b01f02e3 https://gist.github.com/balajismaniam/9953b54dd240ecf085b35ab1bc283f3c
系统配置:CPU 架构:x86_64 CPU 操作模式:32 位,64 位 字节顺序:小端 CPU(s):48 在线 CPU(s)列表:0-47 每个核心的线程数:2 每个插槽的核心数:12 插槽数:2 NUMA 节点数:2 供应商 ID:GenuineIntel 型号名称:Intel(R) Xeon(R) CPU E5-2680 v3 内存 256 GB 操作系统/内核 Linux 3.10.0-693.21.1.el7.x86_64
英特尔、英特尔徽标、至强是英特尔公司或其子公司在美国和/或其他国家/地区的商标。
*其他名称和品牌可能是其他方的财产。© 英特尔公司。