在节点上控制拓扑管理策略
Kubernetes v1.27 [stable]
越来越多的系统利用 CPU 和硬件加速器的组合来支持延迟敏感的执行和高吞吐的并行计算。这些工作负载涵盖了电信、科学计算、机器学习、金融服务和数据分析等领域。这些混合系统构成了高性能环境。
为了获得最佳性能,需要进行 CPU 隔离、内存和设备局部性相关的优化。然而,在 Kubernetes 中,这些优化由一组不相关的组件处理。
拓扑管理器(Topology Manager) 是一个 kubelet 组件,旨在协调负责这些优化的组件集。
开始之前
你需要拥有一个 Kubernetes 集群,并且 kubectl 命令行工具已被配置为与你的集群通信。建议在至少有两个非控制平面主机节点的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者可以使用以下任一 Kubernetes 沙箱环境:
你的 Kubernetes 服务器版本必须是 v1.18 或更高。要检查版本,输入 kubectl version
。
拓扑管理器的工作原理
在引入拓扑管理器之前,Kubernetes 中的 CPU 和设备管理器是相互独立地做出资源分配决策的。这可能导致在多插槽系统上出现不理想的分配,性能/延迟敏感的应用会因此受到影响。在这种情况下,不理想意味着,例如,CPU 和设备从不同的 NUMA 节点分配,从而引入额外的延迟。
拓扑管理器是一个 kubelet 组件,它充当事实来源,以便其他 kubelet 组件可以做出拓扑对齐的资源分配选择。
拓扑管理器为被称为 Hint Provider 的组件提供了一个接口,用于发送和接收拓扑信息。拓扑管理器有一套节点级别的策略,下面将对其进行解释。
拓扑管理器从 Hint Provider 接收拓扑信息,这些信息是一个表示可用 NUMA 节点的位掩码和一个首选分配指示。拓扑管理器策略对提供的提示执行一系列操作,并根据策略确定的提示进行收敛,以获得最佳结果。如果存储了不理想的提示,则该提示的 `preferred` 字段将被设置为 false。在当前策略中,preferred 是最窄的首选掩码。选定的提示作为拓扑管理器的一部分进行存储。根据配置的策略,Pod 可能因为选定的提示而被节点接受或拒绝。然后将此提示存储在拓扑管理器中,供 Hint Provider 在做出资源分配决策时使用。
Windows 支持
Kubernetes v1.32 [alpha]
(默认启用: false)可以通过使用 WindowsCPUAndMemoryAffinity
Feature Gate 在 Windows 上启用拓扑管理器支持,并且这需要容器运行时的支持。
拓扑管理器 scope 和 policy
拓扑管理器目前
- 对齐所有 QoS 类的 Pod。
- 对齐 Hint Provider 为其提供拓扑提示的请求资源。
如果满足这些条件,拓扑管理器将对齐请求的资源。
为了定制如何执行此对齐,拓扑管理器提供了两个不同的选项:scope
和 policy
。
scope
定义了您希望执行资源对齐的粒度,例如,在 pod
或 container
级别。policy
定义了用于执行对齐的实际策略,例如 best-effort
、restricted
和 single-numa-node
。有关当前可用的各种 scope
和 policy
的详细信息,请参见下文。
注意
为了将 CPU 资源与 Pod spec 中的其他请求资源对齐,应启用 CPU Manager 并在节点上配置适当的 CPU Manager policy。请参阅控制节点上的 CPU 管理策略。注意
为了将内存(和大页)资源与 Pod spec 中的其他请求资源对齐,应启用 Memory Manager 并在节点上配置适当的 Memory Manager policy。请参阅Memory Manager 文档。拓扑管理器 scope
拓扑管理器可以在几个不同的 scope 中处理资源的对齐
container
(默认)pod
可以在 kubelet 启动时通过在kubelet 配置文件中设置 topologyManagerScope
来选择其中任何一个选项。
container
scope
默认使用 container
scope。您也可以在kubelet 配置文件中显式地将 topologyManagerScope
设置为 container
。
在此 scope 内,拓扑管理器执行一系列顺序的资源对齐,即,对于每个容器(在 pod 中),计算单独的对齐方式。换句话说,对于此特定的 scope,没有将容器分组到特定 NUMA 节点集的概念。实际上,拓扑管理器执行将单个容器任意对齐到 NUMA 节点的操作。
在接下来的 scope(例如 pod scope)中,对容器进行分组的概念得到了认可并有意实现。
pod
scope
要选择 pod
scope,请在kubelet 配置文件中将 topologyManagerScope
设置为 pod
。
此 scope 允许将一个 pod 中的所有容器分组到一个共同的 NUMA 节点集。也就是说,拓扑管理器将一个 pod 作为一个整体对待,并尝试将整个 pod(所有容器)分配到单个 NUMA 节点或一组共同的 NUMA 节点。以下示例说明了拓扑管理器在不同情况下生成的对齐方式
- 所有容器可以且被分配到单个 NUMA 节点;
- 所有容器可以且被分配到一组共享的 NUMA 节点。
整个 pod 所需的特定资源的总量根据有效请求/限制公式计算,因此,此总值等于以下各项中的最大值
- 所有应用容器请求的总和,
- init 容器请求的最大值,
对于一个资源。
将 pod
scope 与 single-numa-node
拓扑管理器 policy 结合使用对于延迟敏感的工作负载或执行 IPC 的高吞吐量应用特别有价值。通过结合这两个选项,您能够将一个 pod 中的所有容器放在单个 NUMA 节点上;因此,可以消除该 pod 的 NUMA 间通信开销。
在 single-numa-node
policy 的情况下,仅当可能分配中存在合适的 NUMA 节点集时,pod 才会被接受。重新考虑上面的例子
- 仅包含单个 NUMA 节点的一组 - 导致 pod 被准入,
- 而包含多个 NUMA 节点的一组 - 导致 pod 被拒绝(因为需要两个或多个 NUMA 节点而不是一个 NUMA 节点来满足分配)。
总结一下,拓扑管理器首先计算一组 NUMA 节点,然后根据拓扑管理器 policy 对其进行测试,这将导致 pod 被拒绝或被准入。
拓扑管理器 policy
拓扑管理器支持四种分配 policy。您可以通过 kubelet flag --topology-manager-policy
设置 policy。支持以下四种 policy
none
(默认)best-effort
restricted
single-numa-node
注意
如果拓扑管理器配置为 pod scope,policy 考虑的容器反映了整个 pod 的需求,因此 pod 中的每个容器将得出相同的拓扑对齐决策。none
policy
这是默认 policy,不执行任何拓扑对齐。
best-effort
policy
对于 Pod 中的每个容器,kubelet 在 best-effort
拓扑管理 policy 下,调用每个 Hint Provider 来发现其资源可用性。利用此信息,拓扑管理器存储该容器的首选 NUMA 节点 affinity。如果 affinity 不是首选的,拓扑管理器仍会存储此信息并准入该 pod 到节点。
然后 Hint Provider 在做出资源分配决策时可以使用此信息。
restricted
policy
对于 Pod 中的每个容器,kubelet 在 restricted
拓扑管理 policy 下,调用每个 Hint Provider 来发现其资源可用性。利用此信息,拓扑管理器存储该容器的首选 NUMA 节点 affinity。如果 affinity 不是首选的,拓扑管理器将拒绝该 pod 从节点。这将导致 pod 进入 Terminated
状态,并伴随 pod 准入失败。
一旦 pod 处于 Terminated
状态,Kubernetes 调度器将不会尝试重新调度该 pod。建议使用 ReplicaSet 或 Deployment 来触发 pod 的重新部署。也可以实现一个外部控制循环来触发出现 Topology Affinity
错误的 pod 的重新部署。
如果 pod 被准入,然后 Hint Provider 在做出资源分配决策时可以使用此信息。
single-numa-node
policy
对于 Pod 中的每个容器,kubelet 在 single-numa-node
拓扑管理 policy 下,调用每个 Hint Provider 来发现其资源可用性。利用此信息,拓扑管理器确定是否可以实现单个 NUMA 节点 affinity。如果可以,拓扑管理器将存储此信息,然后 Hint Provider 在做出资源分配决策时可以使用此信息。但是,如果这不可能,那么拓扑管理器将拒绝该 pod 从节点。这将导致 pod 处于 Terminated
状态,并伴随 pod 准入失败。
一旦 pod 处于 Terminated
状态,Kubernetes 调度器将不会尝试重新调度该 pod。建议使用带副本的 Deployment 来触发 Pod 的重新部署。也可以实现一个外部控制循环来触发出现 Topology Affinity
错误的 pod 的重新部署。
拓扑管理器 policy 选项
对拓扑管理器 policy 选项的支持需要启用 TopologyManagerPolicyOptions
Feature Gate(它默认是启用的)。
您可以根据其成熟度级别使用以下 Feature Gate 开启或关闭选项组
TopologyManagerPolicyBetaOptions
默认启用。启用以显示 beta 级别选项。TopologyManagerPolicyAlphaOptions
默认禁用。启用以显示 alpha 级别选项。
您仍然需要使用 TopologyManagerPolicyOptions
kubelet 选项来启用每个选项。
prefer-closest-numa-nodes
prefer-closest-numa-nodes
选项自 Kubernetes 1.32 起已正式发布 (GA)。在 Kubernetes 1.33 中,如果 TopologyManagerPolicyOptions
Feature Gate 被启用,则此 policy 选项默认可见。
拓扑管理器默认不知道 NUMA 距离,并且在做出 Pod 准入决策时不会考虑它们。此限制在多插槽以及单插槽多 NUMA 系统中均会出现,如果拓扑管理器决定将资源对齐到非相邻的 NUMA 节点,则可能在延迟敏感执行和高吞吐量应用中导致显著的性能下降。
如果您指定 prefer-closest-numa-nodes
policy 选项,则 best-effort
和 restricted
policy 在做出准入决策时会倾向于选择 NUMA 节点之间距离更短的集合。
您可以通过将 prefer-closest-numa-nodes=true
添加到拓扑管理器 policy 选项来启用此选项。
默认情况下(不带此选项),拓扑管理器将资源对齐到单个 NUMA 节点,或者在需要多个 NUMA 节点的情况下,使用最少数量的 NUMA 节点进行对齐。
max-allowable-numa-nodes
(beta)
max-allowable-numa-nodes
选项自 Kubernetes 1.31 起处于 beta 阶段。在 Kubernetes 1.33 中,如果 TopologyManagerPolicyOptions
和 TopologyManagerPolicyBetaOptions
Feature Gate 被启用,则此 policy 选项默认可见。
准入 pod 的时间与物理机器上的 NUMA 节点数量相关。默认情况下,Kubernetes 不会在检测到超过 8 个 NUMA 节点的任何(Kubernetes)节点上运行启用了拓扑管理器的 kubelet。
注意
如果您选择max-allowable-numa-nodes
policy 选项,则允许具有超过 8 个 NUMA 节点的节点运行启用了拓扑管理器的 kubelet。Kubernetes 项目对于在超过 8 个 NUMA 节点的(Kubernetes)节点上使用拓扑管理器的影响只有有限的数据。由于缺乏数据,在 Kubernetes 1.33 中使用此 policy 选项不推荐,风险自负。您可以通过将 max-allowable-numa-nodes=true
添加到拓扑管理器 policy 选项来启用此选项。
设置 max-allowable-numa-nodes
的值本身不会影响 pod 准入的延迟,但将 Pod 绑定到具有许多 NUMA 的(Kubernetes)节点确实有影响。未来 Kubernetes 潜在的改进可能会提升 Pod 准入性能,并改善随着 NUMA 节点数量增加而产生的高延迟。
Pod 与拓扑管理器 policy 的交互
考虑以下 Pod manifest 中的容器
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 类中。
如果选择的 policy 不是 none
,拓扑管理器将考虑这些 Pod spec。拓扑管理器将咨询 Hint Provider 以获取拓扑提示。在 static
模式下,CPU Manager policy 将返回默认拓扑提示,因为这些 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"
此带有整数 CPU 请求的 pod 运行在 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"
此带有共享 CPU 请求的 pod 运行在 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"
由于没有 CPU 和内存请求,此 pod 运行在 BestEffort
QoS 类中。
拓扑管理器将考虑上述 pod。拓扑管理器将咨询 Hint Provider,即 CPU Manager 和 Device Manager,以获取 pod 的拓扑提示。
对于带有整数 CPU 请求的 Guaranteed
pod,static
CPU Manager policy 将返回与独占 CPU 相关的拓扑提示,Device Manager 将返回请求的设备的提示。
对于带有共享 CPU 请求的 Guaranteed
pod,static
CPU Manager policy 将返回默认拓扑提示,因为没有独占 CPU 请求,Device Manager 将返回请求的设备的提示。
在上述两个 Guaranteed
pod 的情况下,none
CPU Manager policy 将返回默认拓扑提示。
对于 BestEffort
pod,static
CPU Manager policy 将返回默认拓扑提示,因为没有 CPU 请求,Device Manager 将返回每个请求设备的提示。
利用此信息,拓扑管理器计算出 pod 的最佳提示并存储此信息,供 Hint Provider 在进行资源分配时使用。
已知限制
拓扑管理器允许的最大 NUMA 节点数量为 8。如果 NUMA 节点数量超过 8 个,在尝试枚举可能的 NUMA affinity 并生成其提示时,将出现状态爆炸。有关更多选项,请参见
max-allowable-numa-nodes
(beta)。调度器不感知拓扑,因此可能发生被调度到节点上,但由于拓扑管理器而失败的情况。