CPU Manager 作为 Kubelet 的一个模块,用于为 Container 提供绑核的能力。绑核的能力启动时(--cpu-manager-policypolicy=static 或 kubelet-config-file 中配置),Pod 声明为 Guaranteed 且其中的 Container CPU 为整数时,该 Containter 将独占 CPU。非整数 CPU 的 Container 依然通过 CFS 使用 Shared Pool 中的 CPUs。
绑核的利弊
- 【利】Container 独占 CPU 的真正核数,其他 Container 无法调度在这些这些CPU。适用于如下场景
- 对 CPU 限流敏感,CFS 追求的“全面公平”会导致在重调度周期下,上一轮占用时长较多的进程在本轮调度周期下会被限制
- 对上下文切换敏感,Contianter 使用 Shared Pool 的 CPUs 时,由于是共享的,OS 会做加载新调度过来的任务的状态(寄存器状态,计数器值等),并产生一定时间损耗
- 处理器缓存命中率敏感
- 跨Socket的内存流量敏感
- 【弊】资源利用率低
- 【弊】在 NUMA 架构下,未考虑 CPU 亲和性反而会导致性能下降
Numa CPU Topolgy
- 1个主机有多个 Socket
- 一个 Socket 有多个 Numa 节点
- Numa 节点有多个 CPU 核
如何工作
CPU Manager 工作时也会参考 CPU topology 通过 cpuset.cpus 来实现 CPU 亲和性。
- 最初,CPU Manager 将所有的 CPU 放入 Shared Pool 管理。
- 当有非 Guaranteed Pod Container 或者 Guaranteed Pod 且其中 CPU 非整数的 Containter 被 Kubelet 分配时,CPU Manager 通过 CFS 从 Shared Pool 中分配 CPU
- 当有 Guaranteed Pod 且其中 CPU 整数的 Containter 被 Kubelet 分配时。
- 当 Shared Pool 有足够的空闲 CPU,该CPU会被移除 Shared Pool,并被 Pod Container 长期占用,直到 Pod 退出
- 当 Shared Pool 空闲 CPU 不足时,
- 空闲 CPU 会被移出 Shared Pool 分配给 Container
- CPU Manager 会尝试寻找有“富余算力”的CPU,在下个调度周期让其他进程看不见该CPU,使其一个空闲 CPU 并移出 Shared Pool,给 Container 独占。
如何查看
- 查看主机CPU情况
lscpu
- 发布绑核容器组并查看 CPU 分配情况
kind: Pod
apiVersion: v1
metadata:
name: pod-with-cpu-manager
namespace: default
labels:
app: pod-with-cpu-manager
spec:
containers:
- name: container
image: nginx:latest
resources:
limits:
cpu: 2
memory: 1Gi
requests:
cpu: 2
memory: 1Gi
获取Pid
docker info | grep 'Docker Root Dir' | awk '{print $NF}'
docker ps | grep pod-with-cpu-manager | grep -v pause | awk '{print $1}'
docker inspect ab120e612a5d | grep Id
cat /mnt/paas/runtime/containers/ab120e612a5d7e6562f8f257b54304306b0f1f39989d9e9638982d1bf583d03a/config.v2.json | grep Pid
查看 CPU 分配情况
cat /proc/10942/cgroup
cat /sys/fs/cgroup/cpuset/kubepods/poda1e85149-f352-49e6-b7d4-4f3cc46c5da2/ab120e612a5d7e6562f8f257b54304306b0f1f39989d9e9638982d1bf583d03a/cpuset.cpus
- 分布非绑核容器组并查看 CPU 分配情况
kind: Pod
apiVersion: v1
metadata:
name: pod-without-cpu-manager
namespace: default
labels:
app: pod-with-cpu-manager
spec:
containers:
- name: container
image: nginx:latest
resources:
limits:
cpu: 0.5
memory: 1Gi
requests:
cpu: 0.5
memory: 1Gi
获取Pid
docker ps | grep pod-without-cpu-manager | grep -v pause | awk '{print $1}'
docker inspect ed44ac22c006 | grep Id
cat /mnt/paas/runtime/containers/ed44ac22c006030510c8a6a969c607e3efc0a383fc1a342bc8ebf96898908bc0/config.v2.json | grep Pid
查看 CPU 分配情况,
cat /proc/23813/cgroup
cat /sys/fs/cgroup/cpuset/kubepods/pod6699d6ba-cc50-4780-abe3-413dc3a91917/ed44ac22c006030510c8a6a969c607e3efc0a383fc1a342bc8ebf96898908bc0/cpuset.cpus
- 再分布非绑核容器组并查看 CPU 分配情况
kind: Pod
apiVersion: v1
metadata:
name: pod-without-cpu-manager-another
namespace: default
labels:
app: pod-with-cpu-manager
spec:
containers:
- name: container
image: nginx:latest
resources:
limits:
cpu: 0.5
memory: 1Gi
requests:
cpu: 0.5
memory: 1Gi
CPU 分配如pod-without-cpu-manager 一样共享 0-1,4-7
- 再发布绑核容器组查看 CPU 分配情况
kind: Pod
apiVersion: v1
metadata:
name: pod-with-cpu-manager-another
namespace: default
labels:
app: pod-with-cpu-manager
spec:
containers:
- name: container
image: nginx:latest
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
CPU 会从 0-1,4-7 中分配出来一个
原pod-without-cpu-manager 和 pod-without-cpu-manager-another 共享的 CPU 将发生变化,1 被移出Shared Pool