开放问答
K8s 节点双路 32C 上 8 核 Pod 跨 NUMA 调度导致 P99 抖动,Topology Manager / cpuset manager 到底值不值得开?
该问题的正文、回答与评论。
提问者 苏若衡 · 状态 open
KubernetesNUMAcpusetTopologyManager性能调优
背景 我在一个 24 节点的 K8s 1.28 集群上跑一套 Go 1.21 的实时行情计算服务,节点规格是双路 32C(Intel 8358,2 个 NUMA node,每个 16C)/128G/512G NVMe,containerd 1.7,cgroup v1。服务单 Pod 规格 8C16G,4 副本,单副本峰值约 8k QPS,主链路是「拉取 → 聚合 → 计算 → 推送」,其中聚合阶段是 24 个 worker 线程并发处理共享的 ring buffer,对内存访问延迟敏感。
现象
最近一个月 P99 延迟从 45ms 漂移到 80~120ms,P50 基本不变(12~15ms),呈现典型的长尾抖动。用 perf stat -e LLC-miss 采样发现命中服务 Pod 的 LLC-miss 比同规格但调度到单 NUMA 节点的 Pod 高 3.2 倍;numastat -p <pid> 显示跨 NUMA 的 other-node 内存占比在 30~40% 波动。基本可以定性:kubelet 默认 shared cpuset,Pod 的 8 个 CPU quota 在两个 NUMA 间被 CFS 自由调度,ring buffer 的 cache line 在两个 NUMA 间乒乓。
已尝试的排查与结果
- 临时用
numactl --cpunodebind=0 --membind=0起容器验证:P99 稳定回到 45ms 以下,确认 NUMA 是主因(不是 GC、不是下游); - 查了 kubelet 的
--cgroup-manager:当前是 cgroupfs + 默认 shared pool,没开 cpuset manager; - 查了 Topology Manager:集群没启用,kubelet 启动参数里没有
--topology-manager-policy; - 没动应用层:Go runtime 本身是 M:P:G 模型,24 worker 线程在 8 核上复用,理论上绑核收益应该更明显,但没系统测过「绑核 + 线程数减半」的组合。
期望得到的答案形态 三个具体问题,希望有量化数据而不是「看情况」:
- kubelet 开 cpuset manager + Topology Manager single-socket 之后,你们线上 Pod 的调度失败率(Insufficient cpu / NUMA not available)大概是多少? 我担心的是:16 核一个 NUMA、Pod 要 8 核,两个 8C Pod 刚好塞满一个 NUMA,第三个就得跨 NUMA 或调度失败——这种碎片化在 24 节点里会不会变成常态?
- P99 改善幅度到底有多少? 我只有 numactl 单点的 45ms 数据,想知道在「多 Pod 混部 + 非独占节点」的真实场景下,绑核 vs 不绑核的 P99 差距是不是稳定在 30~50% 量级?有没有人测过「绑核但只绑 CPU 不绑内存」(--cpunodebind 不加 --membind)的中间态?
- 成本侧:开 Topology Manager 之后,CPU 碎片化导致的节点利用率下降大概多少(我猜 10~20%)?有没有人用「延迟敏感服务单独一个 NUMA 绑核节点池 + 其他服务共享池」的混合方案?落地成本(节点打标、调度器改、镜像重打)大概多少人天?
我倾向的答案形态:你们线上开了没、开了之后调度失败率和 CPU 利用率的真实数字、以及你们对「8 核以下 Pod 值不值得绑核」的判断依据。纯理论「应该开」的回答对我不太有帮助,需要落地成本数据。
评论
暂无评论。