版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mingyundezuoan/article/details/84844891
CPU负载120%
概述
- 背景:生产环境服务响应缓慢,出现RPC接口超时
- 排查:
- 服务双机部署,登录两台日志机器,登录两台部署机器
- 查看部署机器服务负载,
- top 查看,同一台机器上部署三个服务
- 其中A服务,CPU 120%
- 查看刚出现 CPU 负载过高的时间,运维提供监控日志显示上午,查看日志,这期间发生的疑似操作
- 定位问题,近期优化的一个批量初始化数据到缓存中的功能被触发了多次,且该功能为了快速响应,建立线程池,核心线程数10,最大线程数20,用户进行了多次点击,每一次的数据请求量都很大,上一次操作没有完成,下一次的请求即开始了
堆栈信息1
- 查看负载高的进程
- 进入部署服务器
- top , 按 P ,记录CPU负载高的进程编号
- 查看负载高的进程
- top -Ph pid 进程编号,按P ,记录CPU负载高的线程编号
- 线程编号转为十六进制,通过windows提供的科学计算器
- 查看堆栈信息
- jstack pid | grep “0xtid”
异常信息
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000073e4aa000> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:359)
at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:925)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(10, 20,
300, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1000),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}, new ThreadPoolExecutor.CallerRunsPolicy());
根据堆栈信息配置源码跟踪问题原因定位于
服务器CPU数量 2 个,A服务中存在不同的多个线程池,功能运行过程中交叉多个线程池的运行,每个线程在规定的时间内都没有得到反馈,每个线程都在执行SQL查询,没有得到数据响应,线程挂起;不断创建新的线程执行挂起的任务,发生资源争抢,导致CPU负载过高
异常反思
- 线程池使用要根据服务器性能合理设置,创建数量过多会导致CPU负载过高