先分清真忙与限速
容器 CPU 占用高的排查要分两步:先定位到具体容器与进程,再判断是「真的在计算」还是「被限速」。这是最容易混淆的一点:被限速时进程并不会崩溃,只是在每个周期内被暂停一部分时间,表现为响应变慢,而 CPU 使用率看起来仍然接近上限。cgroup 的 cpu.stat 能直接给出限流次数与累计限流时长。
基本信息
| 定位容器 | docker stats --no-stream,或集群侧的用量视图 |
|---|---|
| 定位进程 | docker top 看容器内进程,或在容器内按 CPU 排序查看 |
| 限流检查 | cgroup 的 cpu.stat,关注限流次数与累计限流时间 |
| 常见根因 | 死循环与忙等、正则回溯、GC 频繁、日志风暴、密集加解密 |
| 抓现场手段 | 线程栈与语言级性能剖析工具,用于还原热点 |
| 宿主侧干扰 | CPU 争抢指标偏高说明宿主资源被其他负载占用 |
指标读法
| 指标 | 含义 | 判断方式 |
|---|---|---|
| CPU 使用率贴近配额 | 容器长期贴着上限运行 | 需进一步区分真忙还是被限速 |
| 限流次数 | 累计被限流的周期次数 | 持续增长说明配额不足或存在突发 |
| 累计限流时间 | 被限流的总时长 | 与运行总时长对比可判断影响程度 |
| 宿主争抢时间 | 被其他负载占用的 CPU 时间 | 容器内看不到,只能在宿主侧观察 |
| 上下文切换次数 | 线程与进程切换频率 | 切换高而 CPU 不高时方向要另查 |
典型使用场景
- 单个容器突然打满 CPU,导致同宿主其他服务变慢
- 服务响应变慢但 CPU 看起来不高,怀疑被限速
- 集群节点整体负载高,需要把压力归因到具体容器
- 压测过程中定位瓶颈,判断是配额不足还是代码热点
- 批处理与定时任务占用 CPU,影响在线服务的响应时间
排查命令
排查命令
docker stats --no-stream myapp # 容器级用量
docker top myapp # 容器内进程(宿主视角)
docker exec myapp sh -c 'ps aux --sort=-%cpu | head -10'
docker exec myapp cat /sys/fs/cgroup/cpu.stat 2>/dev/null | head # 限流指标
docker inspect -f '{{.HostConfig.NanoCpus}}' myapp # 确认 CPU 配额
top -bn1 | head -5 # 宿主侧看负载与争抢CPU 突刺也可能是宿主资源争抢:这类指标在容器内看不到,需要在宿主侧观察。共享宿主的场景尤其常见,容器指标正常但业务变慢,答案往往在宿主那层。
把限流当成故障会误导方向:被限速时进程不会崩、日志里没有报错,只有「CPU 打满」这一个信号。看到高占用先确认是限流还是真在计算,再决定是调整配额还是改代码。