Pinterest 工程师消除 CPU 僵尸进程,解决生产环境瓶颈
Pinterest解决了其Kubernetes机器学习平台PinCompute上由间歇性CPU资源饥饿引发的任务崩溃问题。根本原因在于基础镜像中一个未使用的AWS ECS代理在崩溃循环中泄漏了大量“僵尸”内存控制组,导致kubelet进程周期性独占CPU核心。通过禁用该代理并重启机器,团队恢复了系统
85
热度
90
质量
92
影响力
深度分析
一、问题背景与现象:一个“看不见”的幽灵故障
Pinterest的分布式机器学习平台PinCompute基于Kubernetes,承载了公司超过一半的离线ML工作负载。该平台面临了一个棘手的故障:机器学习训练任务间歇性失败,成功率在某些场景下下降超过25%。伴随而来的症状是间歇性网络故障和任务崩溃。
问题的隐蔽性极强:
- 表象正常,内里溃烂:传统的聚合监控仪表盘显示CPU总利用率一切正常,掩盖了底层严重的个别核心资源争夺。
- 连锁反应:问题最终表现为弹性网络适配器(ENA)设备重置和数据包丢失,但这只是表层现象。
二、排查过程:抽丝剥茧,定位内核饱和
工程师的排查路径体现了系统化的深度诊断思维:
- 从宏观监控转向微观分析:由于高级仪表盘无效,团队转向使用
mpstat进行逐核CPU使用分析,发现了关键线索:个别CPU内核的系统CPU使用率会持续数秒飙升至100%。 - 理解故障传导链:工程师将点连成线,构建了清晰的因果链:
- 内核饱和 → ENA网络中断处理的NAPI轮询线程受阻 → 触发ENA设备重置(一种5秒超时的自愈机制) → 网络连接中断 → Ray分布式任务崩溃。
- 精准捕获故障现场:团队利用在12小时重现窗口内每两分钟运行一次的性能数据捕获,并通过Netflix的Flamescope进行可视化。这让他们能精确观察到网络重置发生前一刹那的系统状态。
- 锁定可疑进程:可视化分析显示,在关键时刻,通常CPU占用不足1%的
kubelet进程飙升至约6.5%,且其绝大部分时间消耗在内核函数mem_cgroup_nr_lru_pages中。这指向了与内存控制组(cgroup) 相关的问题。
三、根本原因:一个“僵尸”代理制造的资源泄漏
调查的终极发现揭示了问题的本质,其根源远超应用层:
- 问题源头:用于创建节点的 AWS深度学习AMI(基础镜像) 中默认安装并启用了 Amazon ECS代理。然而,Pinterest的平台并未使用该代理。
- 关键机制:这个“无用”的代理在每次系统启动时都会陷入崩溃循环,并在崩溃过程中泄漏内存控制组(memcgs)。
- 量变引发质变:正常情况下活跃的memcgs仅约240个,但泄漏累积的 “僵尸”memcgs数量达到了近70,000个。
- 性能瓶颈:
kubelet进程需要定期同步cgroup状态。当它被迫遍历这个极度膨胀的列表时,就会独占一个CPU内核长达数秒,从而触发上述整个故障链。
简单来说:一个被遗忘在系统镜像里的、不断崩溃的默认服务,其“垃圾”日积月累,最终“淹”死了负责系统管理的关键进程。
四、解决方案与深层启示
1. 解决方法:简单但需洞察力
- 直接手段:在基础镜像中禁用了ECS代理的systemd服务单元,并重启受影响的节点以清理累积的“僵尸”cgroups。
- 立竿见影:此后,内存cgroup数量稳定,网络重置现象消失。