精细化 CPU 编排
koord-scheduler 为了提升 CPU 密集型工作负载的性能提供了精细化 CPU 编排能力。
Introduction
越来越多的系统利用 CPU 和硬件加速器的组合来支持实时计算和高吞吐的并行计算。 许多应用程序都需要高性能环境,包括电信、科学计算、机器学习、金融服务和数据分析。
但是,Kubernetes 集群中的 Pod 在多种资源维度上都是共享的,存在相互干扰的问题。 CPU 资源的共享几乎是不可避免的,例如 SMT 线程(即逻辑处理器)共享同一个物理核,同一个芯片中的物理核共享同一个 L3 缓存。 资源竞争会减慢这些对 CPU 敏感的工作负载的运行质量,从而导致延迟升高。
为了提高对 CPU 敏感的工作负载的性能,koord-scheduler 提供了一种精细化的 CPU 编排机制。 它增强了 Kubernetes 的 CPU 管理,并支持详细的 NUMA 局部性和 CPU 排除。
有关详细信息,请参阅设计:细粒度 CPU 编排。
设置
前置条件
- Kubernetes >= 1.18
- Koordinator >= 0.6
安装
请确保 Koordinator 组件已正确安装在你的集群中。 如果没有,请参考安装文档。
配置全局参数
精细化 CPU 编排能力是默认开启的。用户不需要额外的配置即可使用。
对于需要深入定制的用户,可以按需修改 Helm Chart 中的配置文件 koord-scheduler-config 设置精细化 CPU 编排的参数。
1. apiVersion: v1
2. kind: ConfigMap
3. metadata:
4. name: koord-scheduler-config
5. ...
6. data:
7. koord-scheduler-config: |
8. apiVersion: kubescheduler.config.k8s.io/v1
9. kind: KubeSchedulerConfiguration
10. profiles:
11. - schedulerName: koord-scheduler
12. - pluginConfig:
13. - name: NodeNUMAResource
14. args:
15. apiVersion: kubescheduler.config.k8s.io/v1
16. kind: NodeNUMAResourceArgs
17. # The default CPU Binding Policy. The default is FullPCPUs
18. # If the Pod belongs to LSE/LSR Prod Pods, and if no specific CPU binding policy is set,
19. # the CPU will be allocated according to the default core binding policy.
20. defaultCPUBindPolicy: FullPCPUs
21. # the scoring strategy
22. scoringStrategy:
23. # the scoring strategy ('MostAllocated', 'LeastAllocated')
24. # - MostAllocated(default): prefer the node with the least available resources
25. # - LeastAllocated: prefer the node with the most available resources
26. type: MostAllocated
27. # the weights of each resource type
28. resources:
29. - name: cpu
30. weight: 1
31. plugins:
32. # enable the NodeNUMAResource plugin
33. preFilter:
34. enabled:
35. - name: NodeNUMAResource
36. filter:
37. enabled:
38. - name: NodeNUMAResource
39. ...
40. score:
41. enabled:
42. - name: NodeNUMAResource
43. weight: 1
44. ...
45. reserve:
46. enabled:
47. - name: NodeNUMAResource
48. preBind:
49. enabled:
50. - name: NodeNUMAResource
koord-descheduler 是通过 Configmap 加载调度器配置的。因此需要通过重启调度器才能使用最新的配置。
| 字段 | 说明 | 版本 |
|---|---|---|
| --- | --- | --- |
| defaultCPUBindPolicy | 默认的 CPU 绑定策略。 默认值为 FullPCPUs。 如果 Pod 属于 LSE/LSR Prod Pod,并且没有设置具体的 CPU 绑定策略,CPU 则会按照默认的 CPU 绑定策略进行分配。 可选值为 FullPCPUs 和 SpreadByPCPUs | >= v0.6.0 |
| scoringStrategy | 打分策略,可选值为 MostAllocated 和 LeastAllocated | >= v0.6.0 |
按节点配置
用户可以单独的为节点设置不同的 CPU 绑定策略和 NUMA Node 选择策略。
CPU 绑定策略
Label node.koordinator.sh/cpu-bind-policy 约束了调度时如何按照指定的策略分配和绑定CPU。具体的值定义如下:
| 值 | 描述 | 版本 |
|---|---|---|
| --- | --- | --- |
| None or empty | 不执行任何策略。 | >= v0.6.0 |
| FullPCPUsOnly | 要求调度器必须分配完整的物理核。等价于 kubelet CPU manager policy option full-pcpus-only=true. | >= v0.6.0 |
| SpreadByPCPUs | 要求调度器必须按照物理核维度均匀的分配逻辑核。 | >= v1.1.0 |
如果节点 Label 上没有 node.koordinator.sh/cpu-bind-policy,调度器将会按照 Pod 指定的 CPU 绑定策略或者调度器配置的默认策略分配 CPU。
NUMA Node 选择策略
Label node.koordinator.sh/numa-allocate-strategy 表示调度时应该如何选择 NUMA Node。具体的值定义如下:
| 值 | 描述 | 版本 |
|---|---|---|
| --- | --- | --- |
| MostAllocated | MostAllocated 表示选择资源剩余最少的 NUMA Node。 | >= v.0.6.0 |
| LeastAllocated | LeastAllocated 表示选择资源剩余最多的NUMA Node。 | >= v.0.6.0 |
如果 node.koordinator.sh/numa-allocate-strategy 和 kubelet.koordinator.sh/cpu-manager-policy 都设置了, 优先使用 node.koordinator.sh/numa-allocate-strategy。
使用精细化 CPU 编排
- 按照下面的 YAM了 创建 Deployment
nginx。
使用精细化 CPU 编排时,Pod 需要在 Label 中指定具体的 QoSClass 并指定具体的绑定策略。
1. apiVersion: apps/v1
2. kind: Deployment
3. metadata:
4. name: nginx-lsr
5. labels:
6. app: nginx-lsr
7. spec:
8. replicas: 3
9. selector:
10. matchLabels:
11. app: nginx-lsr
12. template:
13. metadata:
14. name: nginx-lsr
15. labels:
16. app: nginx-lsr
17. koordinator.sh/qosClass: LSR # set the QoS class as LSR, the binding policy is FullPCPUs by default
18. # in v0.5, binding policy should be specified.
19. # e.g. to set binding policy as FullPCPUs (prefer allocating full physical CPUs of the same core):
20. #annotations:
21. #scheduling.koordinator.sh/resource-spec: '{"preferredCPUBindPolicy": "FullPCPUs"}'
22. spec:
23. schedulerName: koord-scheduler # use the koord-scheduler
24. containers:
25. - name: nginx
26. image: nginx
27. resources:
28. limits:
29. cpu: '2'
30. requests:
31. cpu: '2'
32. priorityClassName: koord-prod
- 创建
nginxdeployment 并检查调度结果。
1. $ kubectl create -f nginx-deployment.yaml
2. deployment/nginx-lsr created
3. $ kubectl get pods -o wide | grep nginx
4. nginx-lsr-59cf487d4b-jwwjv 1/1 Running 0 21s 172.20.101.35 node-0 <none> <none>
5. nginx-lsr-59cf487d4b-4l7r4 1/1 Running 0 21s 172.20.101.79 node-1 <none> <none>
6. nginx-lsr-59cf487d4b-nrb7f 1/1 Running 0 21s 172.20.106.119 node-2 <none> <none>
- 检查 Pod 的 CPU 分配结果
scheduling.koordinator.sh/resource-status.
1. $ kubectl get pod nginx-lsr-59cf487d4b-jwwjv -o jsonpath='{.metadata.annotations.scheduling\.koordinator\.sh/resource-status}'
2. {"cpuset":"2,54"}
我们可以看到 Pod nginx-lsr-59cf487d4b-jwwjv 绑定了 2 个逻辑核,对应的逻辑核 ID 分别是 2 和 54,这两个逻辑核属于同一个物理核。
- 更改
nginxdeployment 的 CPU 绑定策略。
1. apiVersion: apps/v1
2. kind: Deployment
3. metadata:
4. name: nginx-lsr
5. labels:
6. app: nginx-lsr
7. spec:
8. replicas: 3
9. selector:
10. matchLabels:
11. app: nginx-lsr
12. template:
13. metadata:
14. name: nginx-lsr
15. labels:
16. app: nginx-lsr
17. koordinator.sh/qosClass: LSR # set the QoS class as LSR
18. annotations:
19. # set binding policy as SpreadByPCPUs (prefer allocating physical CPUs of different cores)
20. scheduling.koordinator.sh/resource-spec: '{"preferredCPUBindPolicy": "SpreadByPCPUs"}'
21. spec:
22. schedulerName: koord-scheduler # use the koord-scheduler
23. containers:
24. - name: nginx
25. image: nginx
26. resources:
27. limits:
28. cpu: '2'
29. requests:
30. cpu: '2'
31. priorityClassName: koord-prod
- 更新
nginxdeployment 并检查调度结果。
1. $ kubectl apply -f nginx-deployment.yaml
2. deployment/nginx-lsr created
3. $ kubectl get pods -o wide | grep nginx
4. nginx-lsr-7fcbcf89b4-rkrgg 1/1 Running 0 49s 172.20.101.35 node-0 <none> <none>
5. nginx-lsr-7fcbcf89b4-ndbks 1/1 Running 0 49s 172.20.101.79 node-1 <none> <none>
6. nginx-lsr-7fcbcf89b4-9v8b8 1/1 Running 0 49s 172.20.106.119 node-2 <none> <none>
- 检查 Pod 最新的 CPU 分配结果
scheduling.koordinator.sh/resource-status。
1. $ kubectl get pod nginx-lsr-7fcbcf89b4-rkrgg -o jsonpath='{.metadata.annotations.scheduling\.koordinator\.sh/resource-status}'
2. {"cpuset":"2-3"}
现在我们可以看到 Pod nginx-lsr-59cf487d4b-jwwjv 绑定了两个逻辑核,对应的 ID 分别是 2,3, 属于两个不同的物理核。
- (可选) 高级配置.
1. labels:
2. # koordinator QoS class of the pod. (use 'LSR' or 'LSE' for binding CPUs)
3. koordinator.sh/qosClass: LSR
4. annotations:
5. # `resource-spec` indicates the specification of resource scheduling, here we need to set `preferredCPUBindPolicy`.
6. # `preferredCPUBindPolicy` indicating the CPU binding policy of the pod ('None', 'FullPCPUs', 'SpreadByPCPUs')
7. # - None: perform no exclusive policy
8. # - FullPCPUs(default): a bin-packing binding policy, prefer allocating full physical cores (SMT siblings)
9. # - SpreadByPCPUs: a spread binding policy, prefer allocating logical cores (SMT threads) evenly across physical cores (SMT siblings)
10. scheduling.koordinator.sh/resource-spec: '{"preferredCPUBindPolicy": "FullPCPUs"}'
