锋利的开罐器-Arthas

官网:https://arthas.aliyun.com/
github:https://github.com/alibaba/arthas

做什么的?

Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。

具体的引用场景

  • CPU飙高,什么原因造成的?
  • 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  • 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  • 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  • 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  • 是否有一个全局视角来查看系统的运行状况?
  • 有什么办法可以监控到 JVM 的实时运行状态?
  • 怎么快速定位应用的热点,生成火焰图?
  • 怎样直接从 JVM 内查找某个类的实例?
- base64 - base64 编码转换,和 linux 里的 base64 命令类似
[arthas@70070]$ echo 'abc' > /tmp/test.txt
[arthas@70070]$ cat /tmp/test.txt
abc
[arthas@70070]$ base64 /tmp/test.txt
YWJjCg==

基础命令

- cat - 打印文件内容,和 linux 里的 cat 命令类似
- cls - 清空当前屏幕区域
- echo - 打印参数,和 linux 里的 echo 命令类似
- grep - 匹配查找,和 linux 里的 grep 命令类似
- help - 查看命令帮助信息
- history - 打印命令历史
- pwd - 返回当前的工作目录,和 linux 命令类似
- reset - 重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
- session - 查看当前会话的信息
[arthas@19836]$ session
 Name        Value
--------------------------------------------------
 JAVA_PID    19836
 SESSION_ID  d864f3f9-a139-473d-951c-0fa8039ea901
- quit - 退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
- stop - 关闭 Arthas 服务端,所有 Arthas 客户端全部退出
- tee - 复制标准输入到标准输出和指定的文件,和 linux 里的 tee 命令类似
- version - 输出当前目标 Java 进程所加载的 Arthas 版本号
- - keymap - Arthas 快捷键列表及自定义快捷键

image.png

JVM相关命令

- dashboard - 当前系统的实时数据面板🔥

image.png
image.png

- thread - 查看当前 JVM 的线程堆栈信息🔥

image.png

- jvm - 查看当前 JVM 的信息🔥
- sysprop - 查看和修改 JVM 的系统属性
- sysenv - 查看 JVM 的环境变量
- vmoption - 查看和修改 JVM 里诊断相关的 option
- getstatic - 查看类的静态属性
- ognl - 执行 ognl 表达式
ognl '@java.lang.System@out.print("wangzijian")'

[arthas@19836]$ ognl '@demo.MathGame@random'
@Random[
    serialVersionUID=@Long[3905348978240129619],
    seed=@AtomicLong[7988179685469],
    multiplier=@Long[25214903917],
    addend=@Long[11],
    mask=@Long[281474976710655],
    DOUBLE_UNIT=@Double[1.1102230246251565E-16],
    BadBound=@String[bound must be positive],
    BadRange=@String[bound must be greater than origin],
    BadSize=@String[size must be non-negative],
    seedUniquifier=@AtomicLong[199880078823418412],
    nextNextGaussian=@Double[0.0],
    haveNextNextGaussian=@Boolean[false],
    serialPersistentFields=@ObjectStreamField[][isEmpty=false;size=3],
    unsafe=@Unsafe[sun.misc.Unsafe@64911ac2],
    seedOffset=@Long[24],
]
- heapdump - dump java heap, 类似 jmap 命令的 heap dump 功能
- logger - 查看和修改 logger
- mbean - 查看 Mbean 的信息
- memory - 查看 JVM 的内存信息
- perfcounter - 查看当前 JVM 的 Perf Counter 信息
- vmtool - 从 jvm 里查询对象,执行 forceGc

Class、ClassLoader相关命令

- sc(Search Class) - 查看 JVM 已加载的类信息
[arthas@19836]$ sc demo.MathGame -d
 class-info        demo.MathGame
 code-source       /D:/arthas/math-game.jar
 name              demo.MathGame
 isInterface       false
 isAnnotation      false
 isEnum            false
 isAnonymousClass  false
 isArray           false
 isLocalClass      false
 isMemberClass     false
 isPrimitive       false
 isSynthetic       false
 simple-name       MathGame
 modifier          public
 annotation
 interfaces
 super-class       +-java.lang.Object
 class-loader      +-sun.misc.Launcher$AppClassLoader@5c647e05
                     +-sun.misc.Launcher$ExtClassLoader@28d93b30
 classLoaderHash   5c647e05
- sm(Search Method) - 查看已加载类的方法信息
[arthas@19836]$ sm  java.lang.Integer
java.lang.Integer <init>(I)V
java.lang.Integer <init>(Ljava/lang/String;)V
java.lang.Integer numberOfLeadingZeros(I)I
java.lang.Integer numberOfTrailingZeros(I)I
java.lang.Integer bitCount(I)I
java.lang.Integer equals(Ljava/lang/Object;)Z
java.lang.Integer toString(II)Ljava/lang/String;
java.lang.Integer toString()Ljava/lang/String;
java.lang.Integer toString(I)Ljava/lang/String;
java.lang.Integer hashCode(I)I
java.lang.Integer hashCode()I
java.lang.Integer min(II)I
java.lang.Integer max(II)I
- jad - 反编译指定已加载类的源码🔥
[arthas@19836]$ jad demo.MathGame print

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@5c647e05
  +-sun.misc.Launcher$ExtClassLoader@28d93b30

Location:
/D:/arthas/math-game.jar

       public static void print(int number, List<Integer> primeFactors) {
           StringBuffer sb = new StringBuffer(number + "=");
/*34*/     for (int factor : primeFactors) {
/*35*/         sb.append(factor).append('*');
           }
/*37*/     if (sb.charAt(sb.length() - 1) == '*') {
/*38*/         sb.deleteCharAt(sb.length() - 1);
           }
/*40*/     System.out.println(sb);
       }

Affect(row-cnt:1) cost in 97 ms.
- mc - 内存编译器,内存编译.java文件为.class文件
- redefine - 加载外部的.class文件,redefine 到 JVM 里🔥❗
- classloader - 查看 classloader 的继承树,urls,类加载信息,使用 classloader 去 getResource
- dump - dump 已加载类的 byte code 到特定目录
- retransform - 加载外部的.class文件,retransform 到 JVM 里

http://zjyun.cc/wordpress/2809435016662