线上服务器CPU100%排查

测试代码:

```

package jdktest;

public class HoldCPUMain { //该车型简单占用cpu,4个用户线程,一个占用大量cpu资源,3个线程处于空闲状态
public static class HoldCPUTask implements Runnable {
@Override
public void run() {
while (true) {
double a = Math.random() * Math.random(); //大量占用cpu
}
}
}

public static class LazyTask implements Runnable {
@Override
public void run() {
try {
while(true) {
Thread.sleep(1000); //空闲线程
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
new Thread(new HoldCPUTask()).start(); //开启线程,占用cpu
new Thread(new LazyTask()).start(); //3个空闲线程
new Thread(new LazyTask()).start();
new Thread(new LazyTask()).start();
}
}

```

某服务器上部署了若干tomcat实例,即若干垂直切分的Java站点服务,以及若干Java微服务,突然收到运维的CPU异常告警。

问:如何定位是哪个服务进程导致CPU过载,哪个线程导致CPU过载,哪段代码导致CPU过载?

 

步骤一、找到最耗CPU的进程PID

工具top(可以配合Jps命令输出:13375 HoldCPUMain)

方法

· 执行top -c ,显示进程运行信息列表

· 键入P (大写p),进程按照CPU使用率排序(大写M按内存排序)

·  

输出:13375 root      20   0 2464304  21772  11488 S 98.7  1.2   6:31.28 java jdktest.HoldCPUMain 

 

步骤二:找到该进程内最耗CPU的线程PID(假设步骤一得到进程pid是13375)

工具top

方法

· top -Hp 13375 ,显示一个进程的线程运行信息列表

· 键入P (大写p),线程按照CPU使用率排序

输出:13386 root      20   0 2464304  21772  11488 R 99.0  1.2   7:20.99 java

 

也可以安装sysstat,yum install -y sysstat,然后使用pidstat工具监控进程及线程的性能情况:

pidstat -p 13375 1 3 -u -t,其中-p指定进程pid,参数1 3表示每秒采样1次,合计采样3次,-u表示对cpu使用率的监控,监视进程信息,加上-t进一步监视线程信息

```

Average: UID TGID TID %usr %system %guest %CPU CPU Command
Average: 0 13375 - 98.01 0.33 0.00 98.34 - java
Average: 0 - 13375 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13376 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13377 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13378 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13380 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13381 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13382 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13383 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13384 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13385 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13386 98.01 0.00 0.00 98.01 - |__java
Average: 0 - 13387 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13388 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 13389 0.00 0.00 0.00 0.00 - |__java
Average: 0 - 15131 0.00 0.00 0.00 0.00 - |__java

```

 

步骤三:将线程PID转化为16进制(假设步骤二得到线程pid是13386)

工具printf

方法printf  %x\\n  13386

这一步可以用计算器之所以要转化为16进制,是因为堆栈里,线程id是用16进制表示的。

 

步骤四:查看堆栈,找到线程在干嘛(步骤三输出的线程pid的16进制是344a,a是小写)

工具pstack/jstack/grep

方法jstack 13375 | grep  0x344a  -C5 --color

· 打印进程堆栈

· 通过线程id,过滤得到线程堆栈

 

找到了耗CPU高的线程对应的线程名称“Thread-0”,以及看到了该线程正在执行代码的堆栈。

```

"Thread-0" #8 prio=5 os_prio=0 tid=0x00007fa86c0c9800 nid=0x344a runnable [0x00007fa8497d1000]

  java.lang.Thread.State: RUNNABLE
  at jdktest.HoldCPUMain$HoldCPUTask.run(HoldCPUMain.java:9)
  at java.lang.Thread.run(Thread.java:748)

``` 

或使用jstack -l 13375 > /tmp/t.txt输出到文件

posted @ 2019-10-21 23:38  发挥哥  阅读(335)  评论(0编辑  收藏