开会时CPU 飙升100%同事们都手忙脚乱记一次应急处理过程

开会时CPU 飙升100%同事们都手忙脚乱记一次应急处理过程
最新回答
浅谈失去的回忆

2026-05-13 12:39:34

一次线上服务CPU飙升至100%的应急处理过程记录如下:

告警阶段
  • 现象:正在开会时,钉钉告警声不断响起,市场人员反馈客户投诉系统无法登录,报504错误。查看钉钉告警信息,发现几台业务服务器节点的CPU使用率均超过告警阈值,达到100%。
  • 初步检查:从会议中抽身,通过SSH登录服务器,使用top命令查看,发现几个Java进程的CPU占用率极高,达到180%-190%,这些进程对应同一个业务服务的几个Pod(或容器)。
定位阶段
  • 容器资源查看:

    使用docker stats命令查看本节点容器资源使用情况。

    对占用CPU高的容器,使用docker exec -it <容器ID> bash命令进入容器内部。

  • 进程与线程定位:

    在容器内部执行top命令,定位到占用CPU高的进程ID。

    使用top -Hp <进程ID>命令,进一步定位到占用CPU高的线程ID。

  • 线程栈信息获取:

    使用jstack <进程ID> > jstack.txt命令,将进程的线程栈打印输出到文件。

    退出容器,使用docker cp <容器ID>:/usr/local/tomcat/jstack.txt ./命令,将jstack文件复制到宿主机,以便查看。

    获取到jstack信息后,重启服务以恢复其可用性。

  • 线程ID转换与定位:

    使用printf '%xn' <线程ID>命令,将线程ID转换为十六进制形式。

    在jstack.txt文件中定位到nid=0x<十六进制线程ID>的位置,该位置即为占用CPU高线程的执行栈信息。

  • 问题确认:

    与同事确认,发现高CPU占用与使用一个框架的excel导出功能有关。该功能未设置分页和限制,一次导出50万条数据,且每条数据都需要进行转换计算。操作者因导出无响应而连续点击,几分钟内发起了10多次导出请求,导致CPU被打满,服务崩溃。

解决阶段
  • 限制措施:对耗资源的操作设置相应限制,如限制请求量、控制最大分页大小、限制访问频率(如同一用户一分钟内最多请求次数)。
再次发生与处理
  • 现象:服务重启后恢复,但下午又有一台服务器节点CPU告警。
  • 定位:

    依前面步骤定位到占用CPU高的线程,发现与GC任务线程相关。

    使用jstat -gcutil <进程ID> 2000 10命令查看GC情况。

  • 发现Full GC次数达到1000多次,且还在不断增长,同时Eden区和Old区已被占满。
  • 内存分析:

    使用jmap -heap <进程ID>查看堆内存各区的占用情况。

    使用jmap -dump:format=b,file=./jmap.dump <进程ID>命令将内存使用情况dump出来。

    退出容器,使用docker cp <容器ID>:/usr/local/tomcat/jmap.dump ./命令将dump文件复制到宿主机目录,下载到本地。

    使用MemoryAnalyzer工具打开dump文件进行分析。

  • 发现占用内存最多的是char[]和String对象,通过内存泄露报告页面定位到疑似泄露点。

  • 点开“see stacktrace”链接,进入线程栈页面,确认问题与excel导出功能相关,数据量过大导致内存溢出,进而引发频繁GC和CPU飙升。

总结
  • 处理方法参考:本文通过实战过程示例了在遇到Java服务造成服务器CPU消耗过高或内存溢出时的一般处理方法,包括告警响应、问题定位、解决措施和再次发生时的处理流程。
  • 开发考虑:在开发实现功能时,需要考虑得更深远一些,不能仅停留在解决当前场景,还需考虑数据量不断增大时实现的适用性。