传统方式排查
模拟CPU飙高的场景
Linux环境上运行测试Demo,模拟CPU飙高的场景
@RequestMapping("testCpu") public String testCpuCpuSurgesOperation(){ // 模拟占用CPU资源操作 while (true){ } }
top命令查找占用CPU高的进程
项目启动后,调用testCpu接口,通过top查看进程占用cpu情况,由下图可知进程号为15565的进程占用100.3%的CPU资源
根据进程号找到占用CPU高的线程
top -Hp -15565 找到进程中占用CPU高的线程
线程的转储信息输出到文件中
jstack -l 15565 >> stackdump.txt 用于生成线程转储信息的命令,并将其追加到名为 stackdump.txt 的文件中。
- jstack 是一个 Java 命令行工具,用于生成 JVM中所有线程的转储信息。
- -l 选项表示生成详细的线程转储信息,包括锁信息。
- 15565 是要生成线程转储的进程ID。
- >> 是重定向操作符,用于将输出追加到指定的文件中。
线程id转为为16进制
使用printf “%x
” 线程id将异常线程id转化为16进制
线程转储文件中找到对应的线程
打开线程转储文件(stackdump.txt),通过上面输出的16进制的线程id(3cf0)找到对应线程的堆栈信息,这时我们就可以定位到CPU飙高代码的具体位置。
arthas工具排查
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,大大提升线上问题排查效率。
官网:https://arthas.aliyun.com/doc/
arthas能为我们做什么?
下面我将介绍使用arthas工具排查CPU飙高和死锁的问题
下载并启动arthas
从官网下载完成后上传到服务器,使用 java -jar arthas-boot.jar 启动arthas
选择需要监控的进程
启动时arthas会把所有的运行的java进程列举出来,需要选择我们去需要监视的java进程,进程前有对应的标识选择数字,因为我的服务器只有一个正在运行的java进程,如下图所示只需选择1即可。
dashboard
dashboard:实时查看系统的运行状况。输入dashboard后能看到占用CPU 99.25%的线程。ctrl + c可以退出查看。
根据线程id找到代码块
thread:查看当前 JVM 的线程堆栈信息。从上图可知占用CPU大量资源的线程id为17,输出 thread 17就可以定位到CPU飙高代码的具体位置。
参数名称 | 参数说明 |
---|---|
thread -all | 显示所有的线程 |
thread -id | 显示指定线程的运行堆栈; |
thread -b | 找出当前阻塞其他线程的线程 |
thread -n 3 | 指定最忙的前 N 个线程并打印堆栈 |
模拟死锁的场景
@RequestMapping("testDeadLock") public void testDeadLockOperation(){ new Thread(()->{ // 线程A获取到资源A synchronized (sourceA){ System.out.println("Get resource A"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } // 尝试获取B资源 synchronized (sourceB){ System.out.println("try get resource B"); } } },"A").start(); new Thread(() ->{ synchronized (sourceB){ System.out.println("Get resource B"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } // 尝试获取A资源 synchronized (sourceA){ System.out.println("try get resource A"); } } },"B").start(); }
查询阻塞的线程
只需执行“thread -b”命令,找出当前阻塞其他线程的线程
总结:
- 通过对比以上两种排查问题的方式,arthas在定位CPU飙高和死锁的场景下更加方便和高效。
- 以上内容只是简单的介绍arthas的线程分析功能,它还有一些更加强大的功能,比如:内存分析、方法追踪、字节码注入等等…