Alibaba Java诊断工具Arthas简单介绍 :
当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:
1.这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
2.我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
3.遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
4.线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
5.是否有一个全局视角来查看系统的运行状况?
6.有什么办法可以监控到JVM的实时运行状态?
Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。
一、快速安装
这里我们使用官网推荐的arthas-boot
下载arthas-boot.jar,然后用java -jar的方式启动:
wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
打印帮助信息:
java -jar arthas-boot.jar -h
二、简单使用
1.下载官方提供的Demo并启动
arthas-demo是一个简单的程序,每隔一秒生成一个随机数,再执行质因式分解,并打印出分解结果。
wget https://alibaba.github.io/arthas/arthas-demo.jar
java -jar arthas-demo.jar
2.重新java -jar启动下载好的arthas jar包
java -jar arthas-boot.jar
启动完将看到:
➜ githubTools java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.1.0
[INFO] Found existing java process, please choose one and hit RETURN.
* [1]: 6419 arthas-demo.jar
[2]: 823
3.选择应用java进程
Demo进程是第1个,则输入1,再输入回车/enter。Arthas会attach到目标进程上,并输出日志:
[INFO] arthas home: /Users/zhangboqing/.arthas/lib/3.1.0/arthas
[INFO] Try to attach process 6419
[INFO] Attach process 6419 success.
[INFO] arthas-client connect 127.0.0.1 3658
,---. ,------. ,--------.,--. ,--. ,---. ,---.
/ O \ | .--. ''--. .--'| '--' | / O \ ' .-'
| .-. || '--'.' | | | .--. || .-. |`. `-.
| | | || |\ \ | | | | | || | | |.-' |
`--' `--'`--' '--' `--' `--' `--'`--' `--'`-----' wiki: https://alibaba.github.io/arthas
version: 3.1.0
pid: 6419
time: 2019-02-16 23:22:11 $
这样就进入到对应的进程中了,接下来的操作都是在当前进程中的
3.简单命令介绍
1)dashboard
输入dashboard,按回车/enter,会展示当前进程的信息,按ctrl+c可以中断执行。
ID NAME GROUP PRIORITY STATE %CPU TIME INTERRUPTED DAEMON
21 Timer-for-arthas-dashboard-b47de3b0-268b-4d6 system 10 RUNNABLE 76 0:0 false true
15 nioEventLoopGroup-3-1 system 10 RUNNABLE 23 0:0 false false
11 AsyncAppender-Worker-arthas-cache.result.Asy system 9 WAITING 0 0:0 false true
9 Attach Listener system 9 RUNNABLE 0 0:0 false true
3 Finalizer system 8 WAITING 0 0:0 false true
2 Reference Handler system 10 WAITING 0 0:0 false true
4 Signal Dispatcher system 9 RUNNABLE 0 0:0 false true
19 as-command-execute-daemon system 10 TIMED_WAITING 0 0:0 false true
13 job-timeout system 9 TIMED_WAITING 0 0:0 false true
1 main main 5 TIMED_WAITING 0 0:0 false false
14 nioEventLoopGroup-2-1 system 10 RUNNABLE 0 0:0 false false
18 nioEventLoopGroup-2-2 system 10 RUNNABLE 0 0:0 false false
16 pool-1-thread-1 system 5 TIMED_WAITING 0 0:0 false false
17 pool-2-thread-1 system 5 WAITING 0 0:0 false false Memory used total max usage GC
heap 39M 123M 1820M 2.16% gc.ps_scavenge.count 3
ps_eden_space 28M 32M 672M 4.20% gc.ps_scavenge.time(ms) 32
ps_survivor_space 4M 5M 5M 99.38% gc.ps_marksweep.count 0
ps_old_gen 6M 85M 1365M 0.45% gc.ps_marksweep.time(ms) 0
nonheap 19M 20M -1 96.34%
code_cache 4M 4M 240M 1.78%
metaspace 13M 13M -1 96.48%
compressed_class_space 1M 1M 1024M 0.16%
direct 0K 0K - Infinity%
Runtime
os.name Mac OS X
os.version 10.14
java.version 1.8.0_112
java.home /Library/Java/JavaVirtualMachines/jdk1.8.0_1
12.jdk/Contents/Home/jre
systemload.average 1.69
processors 4
2)thread
通过thread命令来获取到arthas-demo进程的Main Class
thread 1会打印线程ID 1的栈,通常是main函数的线程。
$ thread 1
"main" Id=1 TIMED_WAITING
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at demo.MathGame.main(MathGame.java:17) Affect(row-cnt:0) cost in 17 ms.
3)jad
通过jad来反编译Main Class
$ jad demo.MathGame ClassLoader:
+-sun.misc.Launcher$AppClassLoader@6bc7c054
+-sun.misc.Launcher$ExtClassLoader@7e97d617 Location:
/Users/zhangboqing/Software/githubTools/arthas-demo.jar /*
* Decompiled with CFR 0_132.
*/
package demo; import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit; public class MathGame {
private static Random random = new Random();
public int illegalArgumentCount = 0; public static void main(String[] args) throws InterruptedException {
MathGame game = new MathGame();
do {
game.run();
TimeUnit.SECONDS.sleep(1L);
} while (true);
} public void run() throws InterruptedException {
try {
int number = random.nextInt() / 10000;
List<Integer> primeFactors = this.primeFactors(number);
MathGame.print(number, primeFactors);
}
catch (Exception e) {
System.out.println(String.format("illegalArgumentCount:%3d, ", this.illegalArgumentCount) + e.getMessage());
}
} public static void print(int number, List<Integer> primeFactors) {
StringBuffer sb = new StringBuffer("" + number + "=");
Iterator<Integer> iterator = primeFactors.iterator();
while (iterator.hasNext()) {
int factor = iterator.next();
sb.append(factor).append('*');
}
if (sb.charAt(sb.length() - 1) == '*') {
sb.deleteCharAt(sb.length() - 1);
}
System.out.println(sb);
} public List<Integer> primeFactors(int number) {
if (number < 2) {
++this.illegalArgumentCount;
throw new IllegalArgumentException("number is: " + number + ", need >= 2");
}
ArrayList<Integer> result = new ArrayList<Integer>();
int i = 2;
while (i <= number) {
if (number % i == 0) {
result.add(i);
number /= i;
i = 2;
continue;
}
++i;
}
return result;
}
} Affect(row-cnt:1) cost in 830 ms.
$
4)watch
通过watch命令来查看demo.MathGame#primeFactors函数的返回值:
watch demo.MathGame primeFactors returnObj
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 59 ms.
ts=2019-02-16 23:31:38; [cost=1.710847ms] result=null
ts=2019-02-16 23:31:39; [cost=0.079354ms] result=null
ts=2019-02-16 23:31:40; [cost=0.251734ms] result=@ArrayList[
@Integer[2],
@Integer[2],
@Integer[2],
@Integer[2],
@Integer[2],
@Integer[2],
@Integer[2],
@Integer[2],
@Integer[5],
@Integer[109],
]
4.退出arthas
如果只是退出当前的连接,可以用quit或者exit命令。Attach到目标进程上的arthas还会继续运行,端口会保持开放,下次连接时可以直接连接上。
如果想完全退出arthas,可以执行shutdown命令。
附录:
Arthas 用户文档:https://alibaba.github.io/arthas/quick-start.html
Arthas github地址: https://github.com/alibaba/arthas