容器CPU占用高?几个实用排查和优化方法帮你解决

最近在公司跑着一堆Docker容器,突然发现其中一台服务器的CPU使用率飙到了90%以上,查了一圈才发现是某个Java应用容器在“偷偷”吃资源。这种情况其实挺常见的,尤其在本地开发、测试环境或者小规模部署时,容器CPU占用高不仅影响性能,还可能导致服务卡顿甚至崩溃。

先看看到底是谁在“抢”CPU

别急着重启容器,先得搞清楚是哪个容器在作怪。最直接的方法就是用docker stats命令实时查看所有容器的资源占用情况:

docker stats --no-stream

这个命令会列出每个容器的CPU、内存、网络和磁盘使用情况。一眼就能看出哪个容器的CPU百分比异常高。比如你看到某个Nginx容器平时才1%,现在突然跑到70%,那问题大概率就出在它身上了。

进容器内部看看进程

找到目标容器后,下一步是进入容器内部,看看是哪个具体进程在疯狂占用CPU。假设你的容器ID是abc123,可以用下面的命令进入:

docker exec -it abc123 /bin/sh

进去之后运行tophtop(如果安装了的话),就能看到当前最耗CPU的进程。有时候你会发现是个死循环的脚本,或者某个Java线程一直在GC(垃圾回收),这就需要针对性处理了。

限制容器的CPU资源

如果你不想让某个容器无限制地占用CPU,可以在启动时就加上资源限制。比如限制一个容器最多使用一个CPU核心的50%:

docker run -d --cpus=0.5 your-image-name

或者更精细地控制CFS(完全公平调度器)的配额:

docker run -d --cpu-quota=25000 --cpu-period=100000 your-image-name

这样即使应用失控,也不会把整个主机的CPU拖垮,特别适合多容器共存的环境。

检查应用代码和配置

很多时候CPU飙高不是Docker的问题,而是应用本身有毛病。比如一个Node.js服务写了个无限轮询的定时任务,每10毫秒执行一次,那CPU不飙高才怪。又比如Spring Boot项目没调好JVM参数,堆内存太小导致频繁GC,也会让CPU持续高位运行。

这时候就得翻代码或者日志了。比如查看Java应用的GC日志:

docker logs your-container-name | grep -i 'gc'

如果发现大量GC记录,可能就得调整JVM的-Xmx-Xms参数,给足内存,减少回收频率。

避免共享宿主机的CPU陷阱

默认情况下,Docker容器是可以自由使用宿主机所有CPU资源的。这在开发阶段无所谓,但在生产或多人共用的服务器上就很危险。建议给每个关键容器都设置CPU限制,尤其是那些非核心的测试服务。

比如你同事拉了个Redis容器做测试,结果数据量一大就开始密集持久,瞬间把CPU打满,影响了你正在跑的API服务。这种“邻居效应”在实际运维中太常见了。

用监控工具长期观察

单次排查能解决问题,但想彻底避免,还得靠监控。像Prometheus + Grafana这套组合,可以长期跟踪每个容器的CPU、内存趋势。设置个告警规则,一旦某个容器CPU连续5分钟超过80%,就发邮件提醒,防患于未然。

哪怕不用复杂的监控系统,定期跑跑docker stats也比出事了再查强得多。毕竟等用户反映服务变慢了,问题早就扩散了。