问题现象

某日收到告警,线上服务器CPU使用率持续飙升且居高不下,严重影响业务响应速度。于是立即登录服务器展开排查。

排查过程

1. 定位进程

首先使用 top 命令查看系统整体资源占用情况:

bash
top

观察发现某个Java进程的CPU占用率异常高,记录下该进程的PID。

2. 确认程序来源

拿到PID后,通过以下命令确认该进程对应的具体程序:

bash
ps -ef | grep <pid>

确认是Java应用程序出现了问题。

3. 定位问题线程

进一步查看该进程内部各线程的CPU占用情况:

bash
top -H -p <pid>

找到CPU占用最高的线程,记录其线程ID(即 nid,十进制格式)。

4. 转储线程快照

使用 jstack 导出进程的所有线程栈信息,以便后续分析:

bash
jstack <pid> > thread_dump.log

5. 换算线程ID格式

jstack 输出的线程快照中,线程ID使用的是十六进制格式,需要将之前记录的十进制 nid 转换为十六进制:

bash
printf "%x\n" <nid>

6. 在快照中定位线程

用转换后的十六进制ID在 thread_dump.log 中查找对应线程。发现CPU占用高的是一组 GC 线程(Gang worker),共计8个左右,说明问题可能出在JVM堆内存上。

7. 查看GC实时状态

使用 jstat 实时监控JVM的GC情况:

bash
jstat -gcutil <pid> 1000 10

将输出的GC日志喂给AI进行分析,结果发现:

  • 老年代(Old Generation)使用率始终为100%
  • 频繁触发Full GC,但内存始终无法回收

结合GC线程持续高占用的情况,初步推断存在 内存泄漏

8. 导出堆快照

为深入分析内存占用情况,使用 jmap 导出当前堆内存快照:

bash
jmap -dump:live,format=b,file=/root/heapdump.hprof <pid>

9. MAT分析堆快照

heapdump.hprof 文件下载到本地,使用 MAT(Memory Analyzer Tool) 打开进行内存分析。

通过MAT的 Leak Suspects 报告发现:大部分内存被某个数据库查询的结果集对象(ResultSet)占满

10. 定位具体代码

在MAT中查看该对象的 Path to GC Root,追踪其引用链,发现该对象被一个名为 superior-platform-reboot-push-threat-pool1 的线程所持有。

回到之前的 thread_dump.log 线程快照,搜索该线程名,查看其当前栈信息。在栈帧中逐层查找,最终定位到项目自身的业务代码,发现是一个 Service 方法中的 MyBatis-Plus 的 Wrapper 对象没有设置任何查询条件

问题原因

java
// 问题代码示例
LambdaQueryWrapper<Entity> wrapper = new LambdaQueryWrapper<>();
// 忘记添加 .eq(...) 等条件
List<Entity> list = mapper.selectList(wrapper);  // 全表查询!

由于 Wrapper 对象缺少条件约束,selectList 执行了全表扫描,将整个表的数据一次性加载到内存中。数据量过大导致堆内存被撑爆,频繁触发 Full GC 且无法回收,最终引发CPU飙升。

解决方案

Wrapper 对象补充正确的查询条件:

java
LambdaQueryWrapper<Entity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Entity::getStatus, 1)
       .ge(Entity::getCreateTime, startTime)
       .le(Entity::getCreateTime, endTime);
List<Entity> list = mapper.selectList(wrapper);

总结与反思

  1. 编写查询代码时务必谨慎:尤其是使用 MyBatis-Plus 的 Wrapper 或 JPA 的 Example 等工具,空条件可能导致全表查询。
  2. 大表查询必须加限制:对于数据量大的表,应配合分页(Page)或限制返回条数。
  3. 监控告警要完善:CPU、GC频率、堆内存使用率等指标都应配置告警,尽早发现问题。
  4. 排查思路固化:进程 → 线程 → GC → 堆快照 → 引用链 → 代码定位,这条链路在类似问题中非常高效。

希望这次排查记录能对遇到类似问题的同学有所帮助。