背景
我负责的其中一个项目在空负载的情况下, CPU 占用率依然保持着 100% 左右, 线上, 测试, 开发的服务都一样; 是什么导致的呢? 在开发环境我查看了请求流量, 这个流量可以忽略但 CPU 占用率一直在 60%-100% 之间浮动.
分析问题
流量可以忽略, 但 CPU 占用依然极其高说明不是请求多导致的资源占用, 原因应该是项目本身自发导致的; 自发包括定时任务与死循环, 而具体哪一段代码现在也确定不了. 现在我们就可以借助原生的 jdk 分析工具来定位是项目哪块出现了问题 (你可以用更高级的 jprofilter 等, 一连接, 问题一目了然), 以下我就采用 jdk 自带工具 jstack,jstat ,jmap 等来逐步定位.
定位问题
在 Linux 环境下用 top 查看 CPU, 内存等资源占用情况 (可采用: top -p pid 具体查看某个应用). 发现 pid=4179 的 java 应用占用 CPU 很高
查看 pid=4179 的应用各个线程占用 CPU 的时间片情况: ps -mp 4179 -o THREAD,tid,time (ps -mp pid -o THREAD,tid,time). 发现 tid =4528 的线程一直长时间占有着 CPU 并且占用率达 100%
将 4528 转为 16 进制, 便于在堆栈信息中查询定位代码块: printf "%x\n" 4528, 转成 16 进制为 11b0
在堆栈信息中定位报错代码块: jstack 4179|grep 11b0 -A 30 ( jstack pid|grep TID(16 进制) -A 30 )
总结
从堆栈信息中我们可以看到是 WAITING 导致, 这个说明有一个线程长时间占用资源, 而其他线程一直处于等待的状态. 最终定位出是在一个分布式锁实现的模块中有一个保持锁的代码块有问题. 然后通过优化这个分布式锁最终解决了这个问题. 通过此次优化, 大大节省出了服务器资源 (目前这个系统在线上是 4 台集群, 相当于节省了 1*4 个 CPU, 如果是一个上百甚至上千的集群, 那么这个资源占用是无法想象的), 最主要的是避免了这种情况对系统本身的影响, 避免了对正常请求的阻塞.
来源: https://www.cnblogs.com/wind-june/p/10212609.html