控制节点上的拓扑管理策略
Kubernetes v1.27 [稳定]
越来越多的系统利用 CPU 和硬件加速器结合来支持对延迟敏感的执行和高吞吐量的并行计算。这些系统包括电信、科学计算、机器学习、金融服务和数据分析等领域的工作负载。这些混合系统构成了高性能环境。
为了获得最佳性能,需要进行与 CPU 隔离、内存和设备局部性相关的优化。然而,在 Kubernetes 中,这些优化由一组不相关的组件处理。
_拓扑管理器_是 kubelet 的一个组件,旨在协调负责这些优化的组件集合。
准备工作
你需要有一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与你的集群通信。建议在至少有两个节点(不作为控制平面主机)的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者使用这些 Kubernetes 游乐场之一
你的 Kubernetes 服务器版本必须是 v1.18 或更高。要检查版本,请输入 kubectl version
。
拓扑管理器工作原理
在引入拓扑管理器之前,Kubernetes 中的 CPU 和设备管理器彼此独立地做出资源分配决策。这可能导致多套接字系统上出现不良分配,并且性能/延迟敏感的应用程序将因此类不良分配而受到影响。这里所说的“不良”是指例如 CPU 和设备从不同的 NUMA 节点分配,从而导致额外的延迟。
拓扑管理器是一个 kubelet 组件,它充当事实来源,以便其他 kubelet 组件可以做出拓扑对齐的资源分配选择。
拓扑管理器为组件(称为_提示提供者_)提供了一个接口,用于发送和接收拓扑信息。拓扑管理器拥有一组节点级策略,下文将进行解释。
拓扑管理器从_提示提供者_接收拓扑信息,该信息以位掩码形式表示可用的 NUMA 节点和首选分配指示。拓扑管理器策略对提供的提示执行一组操作,并根据策略确定的提示进行收敛以给出最佳结果。如果存储了不合意的提示,则提示的首选字段将设置为 false。在当前策略中,首选是最小的首选掩码。选定的提示作为拓扑管理器的一部分进行存储。根据配置的策略,pod 可以根据选定的提示被节点接受或拒绝。然后将该提示存储在拓扑管理器中,供_提示提供者_在做出资源分配决策时使用。
Windows 支持
Kubernetes v1.32 [alpha]
(默认禁用)通过使用 `WindowsCPUAndMemoryAffinity` 特性门,可以在 Windows 上启用拓扑管理器支持,并且它需要容器运行时的支持。
拓扑管理器范围和策略
拓扑管理器目前
- 对齐所有 QoS 类别的 Pod。
- 对齐提示提供者提供拓扑提示的请求资源。
如果满足这些条件,拓扑管理器将对齐请求的资源。
为了自定义此对齐的执行方式,拓扑管理器提供了两个不同的选项:`scope` 和 `policy`。
`scope` 定义了执行资源对齐的粒度,例如在 `pod` 或 `container` 级别。而 `policy` 定义了用于执行对齐的实际策略,例如 `best-effort`、`restricted` 和 `single-numa-node`。有关当今可用的各种 `scopes` 和 `policies` 的详细信息可在下文中找到。
注意
要使 Pod 规约中的 CPU 资源与其他请求资源对齐,应在节点上启用 CPU 管理器并配置适当的 CPU 管理器策略。请参阅 控制节点上的 CPU 管理策略。注意
要使 Pod 规约中的内存(和 Hugepages)资源与其他请求资源对齐,应在节点上启用内存管理器并配置适当的内存管理器策略。请参阅 内存管理器 文档。拓扑管理器作用域
拓扑管理器可以在几个不同的作用域内处理资源的对齐:
- `container` (默认)
pod
可以在 kubelet 启动时通过在 kubelet 配置文件 中设置 `topologyManagerScope` 来选择任一选项。
`container` 作用域
默认使用 `container` 作用域。你也可以在 kubelet 配置文件 中将 `topologyManagerScope` 显式设置为 `container`。
在此作用域内,拓扑管理器执行一系列顺序资源对齐,即为每个容器(在 Pod 中)计算单独的对齐。换句话说,对于这个特定的作用域,没有将容器分组到特定 NUMA 节点集的概念。实际上,拓扑管理器执行单个容器到 NUMA 节点的任意对齐。
在以下作用域(例如 `pod` 作用域)中,分组容器的概念得到了认可并有意识地实现。
`pod` 作用域
要选择 `pod` 作用域,请将 kubelet 配置文件 中的 `topologyManagerScope` 设置为 `pod`。
此作用域允许将 Pod 中的所有容器分组到一组共同的 NUMA 节点。也就是说,拓扑管理器将一个 Pod 视为一个整体,并尝试将整个 Pod(所有容器)分配到一个单个 NUMA 节点或一组共同的 NUMA 节点。以下示例说明了拓扑管理器在不同情况下产生的对齐方式:
- 所有容器都可以并已分配到单个 NUMA 节点;
- 所有容器都可以并已分配到一组共享的 NUMA 节点。
整个 Pod 的特定资源的总需求量根据有效请求/限制公式计算,因此,此总值等于以下各项的最大值:
- 所有应用容器请求的总和,
- 初始容器请求的最大值,
针对某个资源。
将 `pod` 作用域与 `single-numa-node` 拓扑管理器策略结合使用,对于对延迟敏感的工作负载或执行 IPC 的高吞吐量应用程序特别有价值。通过结合这两个选项,你可以将 Pod 中的所有容器放置到单个 NUMA 节点上;因此,可以消除该 Pod 的 NUMA 间通信开销。
在 `single-numa-node` 策略的情况下,只有当可能的分配中存在合适的 NUMA 节点集时,Pod 才会被接受。重新考虑上面的例子:
- 一个只包含单个 NUMA 节点的集合——这将导致 Pod 被接纳,
- 而一个包含多个 NUMA 节点的集合——这将导致 Pod 被拒绝(因为需要两个或更多 NUMA 节点而不是一个 NUMA 节点来满足分配)。
总而言之,拓扑管理器首先计算一组 NUMA 节点,然后根据拓扑管理器策略对其进行测试,这将导致 Pod 的拒绝或接纳。
拓扑管理器策略
拓扑管理器支持四种分配策略。你可以通过 kubelet 标志 `--topology-manager-policy` 设置策略。支持以下四种策略:
- `none`(默认)
best-effort
restricted
single-numa-node
注意
如果拓扑管理器配置了 **pod** 作用域,那么被策略考虑的容器将反映整个 Pod 的要求,因此 Pod 中的每个容器都将得到**相同的**拓扑对齐决策。`none` 策略
这是默认策略,不执行任何拓扑对齐。
`best-effort` 策略
对于 Pod 中的每个容器,kubelet 在采用 `best-effort` 拓扑管理策略时,会调用每个提示提供者来发现其资源可用性。利用这些信息,拓扑管理器会存储该容器的首选 NUMA 节点亲和性。即使亲和性不是首选,拓扑管理器也会存储此信息并仍然接纳 Pod 到该节点。
然后,_提示提供者_可以在做出资源分配决策时使用此信息。
`restricted` 策略
对于 Pod 中的每个容器,kubelet 在采用 `restricted` 拓扑管理策略时,会调用每个提示提供者以发现其资源可用性。利用这些信息,拓扑管理器会存储该容器的首选 NUMA 节点亲和性。如果亲和性不是首选,拓扑管理器将拒绝该 Pod 从该节点上运行。这将导致 Pod 进入 `Terminated` 状态,并出现 Pod 入场失败。
一旦 Pod 进入 `Terminated` 状态,Kubernetes 调度器将**不会**尝试重新调度该 Pod。建议使用 ReplicaSet 或 Deployment 来触发 Pod 的重新部署。也可以实现一个外部控制循环来触发具有 `Topology Affinity` 错误的 Pod 的重新部署。
如果 Pod 被接纳,_提示提供者_可以在做出资源分配决策时使用此信息。
`single-numa-node` 策略
对于 Pod 中的每个容器,kubelet 在采用 `single-numa-node` 拓扑管理策略时,会调用每个提示提供者来发现其资源可用性。利用这些信息,拓扑管理器会判断是否可能实现单个 NUMA 节点亲和性。如果可能,拓扑管理器将存储此信息,然后_提示提供者_可以在做出资源分配决策时使用此信息。然而,如果不可能,拓扑管理器将拒绝该 Pod 从该节点上运行。这将导致 Pod 进入 `Terminated` 状态,并出现 Pod 入场失败。
一旦 Pod 进入 `Terminated` 状态,Kubernetes 调度器将**不会**尝试重新调度该 Pod。建议使用带有副本的 Deployment 来触发 Pod 的重新部署。也可以实现一个外部控制循环来触发具有 `Topology Affinity` 错误的 Pod 的重新部署。
拓扑管理器策略选项
对拓扑管理器策略选项的支持要求启用 `TopologyManagerPolicyOptions` 特性门(默认已启用)。
你可以使用以下特性门控根据其成熟度级别来开启或关闭选项组:
- `TopologyManagerPolicyBetaOptions` 默认启用。启用后显示 Beta 级别的选项。
- `TopologyManagerPolicyAlphaOptions` 默认禁用。启用后显示 Alpha 级别的选项。
你仍然需要使用 `TopologyManagerPolicyOptions` kubelet 选项来启用每个选项。
prefer-closest-numa-nodes
`prefer-closest-numa-nodes` 选项自 Kubernetes 1.32 起已普遍可用。在 Kubernetes 1.34 中,只要启用了 `TopologyManagerPolicyOptions` 特性门,此策略选项默认可见。
拓扑管理器默认不感知 NUMA 距离,在做出 Pod 准入决策时也不考虑它们。这种限制在多套接字以及单套接字多 NUMA 系统中都会出现,如果拓扑管理器决定在非相邻 NUMA 节点上对齐资源,可能会导致对延迟敏感的执行和高吞吐量应用程序的性能显著下降。
如果你指定 `prefer-closest-numa-nodes` 策略选项,`best-effort` 和 `restricted` 策略在做出准入决策时会优先选择 NUMA 节点之间距离更短的集合。
你可以通过在拓扑管理器策略选项中添加 `prefer-closest-numa-nodes=true` 来启用此选项。
默认情况下(不带此选项),拓扑管理器在单个 NUMA 节点上对齐资源,或者在需要多个 NUMA 节点的情况下,使用最少数量的 NUMA 节点。
`max-allowable-numa-nodes` (Beta)
`max-allowable-numa-nodes` 选项自 Kubernetes 1.31 起为 Beta 版。在 Kubernetes 1.34 中,只要启用了 `TopologyManagerPolicyOptions` 和 `TopologyManagerPolicyBetaOptions` 特性门,此策略选项默认可见。
Pod 入场所需的时间与物理机器上的 NUMA 节点数量有关。默认情况下,Kubernetes 不会在检测到超过 8 个 NUMA 节点的(Kubernetes)节点上运行启用拓扑管理器的 kubelet。
注意
如果你选择 `max-allowable-numa-nodes` 策略选项,则允许拥有超过 8 个 NUMA 节点的节点运行启用拓扑管理器的 kubelet。Kubernetes 项目关于在拥有超过 8 个 NUMA 节点的(Kubernetes)节点上使用拓扑管理器的影响的数据有限。由于缺乏数据,不**建议**在 Kubernetes 1.34 中使用此策略选项,后果自负。你可以通过在拓扑管理器策略选项中添加 `max-allowable-numa-nodes=true` 来启用此选项。
设置 `max-allowable-numa-nodes` 的值本身不会影响 Pod 入场延迟,但将 Pod 绑定到具有多个 NUMA 的(Kubernetes)节点确实会产生影响。Kubernetes 未来的潜在改进可能会改善 Pod 入场性能以及随着 NUMA 节点数量增加而出现的高延迟。
Pod 与拓扑管理器策略的交互
考虑以下 Pod 清单中的容器:
spec:
containers:
- name: nginx
image: nginx
由于未指定资源 `requests` 或 `limits`,此 Pod 运行在 `BestEffort` QoS 等级中。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
由于请求小于限制,此 Pod 运行在 `Burstable` QoS 类别中。
如果选择的策略不是 `none`,拓扑管理器将考虑这些 Pod 规约。拓扑管理器会咨询提示提供者以获取拓扑提示。在 `static` 策略的情况下,CPU 管理器策略将返回默认拓扑提示,因为这些 Pod 没有明确请求 CPU 资源。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
example.com/device: "1"
requests:
memory: "200Mi"
cpu: "2"
example.com/device: "1"
该 Pod 具有整数 CPU 请求,运行在 `Guaranteed` QoS 等级中,因为 `requests` 等于 `limits`。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "300m"
example.com/device: "1"
requests:
memory: "200Mi"
cpu: "300m"
example.com/device: "1"
此 Pod 具有共享 CPU 请求,运行在 `Guaranteed` QoS 类中,因为 `requests` 等于 `limits`。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
example.com/deviceA: "1"
example.com/deviceB: "1"
requests:
example.com/deviceA: "1"
example.com/deviceB: "1"
此 Pod 运行在 `BestEffort` QoS 等级中,因为它没有 CPU 和内存请求。
拓扑管理器将考虑上述 Pod。拓扑管理器将咨询提示提供者(即 CPU 和设备管理器)以获取 Pod 的拓扑提示。
对于具有整数 CPU 请求的 `Guaranteed` Pod,`static` CPU 管理器策略将返回与独占 CPU 相关的拓扑提示,而设备管理器将返回所请求设备的提示。
对于具有共享 CPU 请求的 `Guaranteed` Pod,`static` CPU 管理器策略将返回默认拓扑提示,因为没有独占 CPU 请求,并且设备管理器将返回所请求设备的提示。
在上述两种 `Guaranteed` Pod 的情况下,`none` CPU 管理器策略将返回默认拓扑提示。
对于 `BestEffort` Pod,`static` CPU 管理器策略将返回默认拓扑提示,因为没有 CPU 请求,并且设备管理器将返回每个请求设备的提示。
利用这些信息,拓扑管理器计算 Pod 的最佳提示并存储此信息,供提示提供者在分配资源时使用。
已知限制
拓扑管理器允许的最大 NUMA 节点数量为 8。如果 NUMA 节点超过 8 个,当尝试枚举可能的 NUMA 亲和性并生成其提示时,将发生状态爆炸。有关更多选项,请参阅`max-allowable-numa-nodes`(Beta)。
调度器不感知拓扑,因此 Pod 可能会在某个节点上被调度,然后因为拓扑管理器而失败。