原文链接:
https://juejin.cn/post/7424522247791247394
凌晨4点,我被一阵刺耳的手机铃声惊醒。迷迷糊糊地摸索着手机,屏幕上赫然显示着"线上CPU告警"的字样。瞬间,我的困意全无,取而代之的是一阵冷汗和心跳加速。作为公司核心系统的负责人,我深知这意味着什么——用户体验受损、可能的数据丢失,更糟糕的是,我的年终绩效可能就此化为泡影。
我迅速起身,开始了一场与时间赛跑的故障排查之旅。
首先,我登录了服务器,使用top命令查看系统资源使用情况:
$ top
输出显示CPU使用率接近100%,load average远超服务器核心数。这确实是一个严重的问题。
接下来,我使用htop命令获取更详细的进程信息:
$ htop
我发现有几个Java进程占用了大量CPU资源。这些进程正是我们的核心服务。
确定了问题出在Java应用上,我开始进行JVM层面的分析。首先使用jstat命令查看GC情况:
$ jstat -gcutil [PID] 1000 10
输出显示Full GC频繁发生,这可能是导致CPU使用率高的原因之一。
接着,我使用jstack命令生成线程转储,查看线程状态:
$ jstack [PID] > thread_dump.txt
分析thread dump文件,我发现大量线程处于RUNNABLE状态,执行着相似的方法调用。
为了进一步定位热点方法,我使用了async-profiler工具:
$ ./profiler.sh -d 30 -f cpu_profile.svg [PID]
生成的火焰图清晰地显示了一个自定义的排序算法占用了大量CPU时间。
找到了罪魁祸首,我立即查看了相关代码。这是一个用于大量数据的自定义排序算法,原本设计用于小规模数据,但随着业务增长,它的性能问题暴露无遗。
我迅速重构了算法,使用Java 8的并行流进行优化:
List sortedData = data.parallelStream()
.sorted(Comparator.comparing(Data::getKey))
.collect(Collectors.toList());
同时,我添加了缓存机制,避免重复计算:
@Cacheable("sortedData")
public List getSortedData(){
// 优化后的排序逻辑
}
在排查过程中,我还发现了一些低效的数据库查询。使用explain命令分析SQL语句:
EXPLAINSELECT * FROM large_table WHEREstatus = 'ACTIVE';
结果显示这个查询导致了全表扫描。我立即添加了合适的索引: