Arthas-监控诊断工具

1. 简介

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

Arthas(阿尔萨斯)能为你做什么?

Arthas 是 Alibaba 开源的 Java 诊断工具,当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

  1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  4. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  5. 是否有一个全局视角来查看系统的运行状况?
  6. 有什么办法可以监控到 JVM 的实时运行状态?
  7. 怎么快速定位应用的热点,生成火焰图?
  8. 怎样直接从 JVM 内查找某个类的实例?

Arthas 支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

工商银行打造在线诊断平台的探索与实践

2.安装和使用 

-- 下载arthas工具包

curl -O https://arthas.aliyun.com/arthas-boot.jar

-- 启动arthas工具包

java -jar arthas-boot.jar

 

公司内网需要下载arthas全量包,然后手工上传至服务器,下载地址:https://arthas.aliyun.com/download/latest_version?mirror=aliyun

3.常用命令

3.1 基础命令

3.3.1 help (重要)

功能:显示所有arthas命令,每个命令都可用使用-h参数,查看命令帮助信息

 

[arthas@31278]$ dashboard -h

USAGE:

dashboard [-h] [-i <value>] [-n <value>]

SUMMARY:

Overview of target jvm's thread, memory, gc, vm, tomcat info.

EXAMPLES:

dashboard

dashboard -n 10

dashboard -i 2000

WIKI:

https://arthas.aliyun.com/doc/dashboard

OPTIONS:

-h, --help this help

-i, --interval <value> The interval (in ms) between two executions, default is 5000 ms.

-n, --number-of-execution <value> The number of times this command will be executed.

3.3.2 cat

功能:显示文件内容,和 linux 里的 cat 命令类似

3.3.3 grep

功能:匹配查找,和 linux 里的 grep 命令类似

3.3.4 pwd

功能:返回当前的工作目录,和 linux 命令类似

 

[arthas@31278]$ pwd

/Users/**/Downloads/jacoco-0.8.9/lib

3.3.5 cls(重要)

功能: 清空当前屏幕区域

3.3.6 session

功能:查看当前会话的信息

 

[arthas@31278]$ session

Name Value

--------------------------------------------------

JAVA_PID 31278

SESSION_ID d5d6476d-21da-4f2f-acef-c018fdd5bfb6

3.3.7 base64

功能:base64 编码转换,和 linux 里的 base64 命令类似

  • 对文件进行base64编码
 

[arthas@31278]$ echo 'abcd' > /tmp/test.txt

[arthas@31278]$ cat /tmp/test.txt

abcd

[arthas@31278]$ base64 /tmp/test.txt

YWJjZAo=

  • 对文件进行 base64 编码并把结果保存到文件里
 

[arthas@31278]$ base64 --input /tmp/test.txt --output /tmp/result.txt

[arthas@31278]$ cat /tmp/result.txt

YWJjZAo=

  • 用 base64 解码文件
 

[arthas@31278]$ base64 -d /tmp/result.txt

abcd

  • 用 base64 解码文件并保存结果到文件里
 

[arthas@31278]$ base64 -d /tmp/result.txt --output /tmp/resut2.txt

[arthas@31278]$ cat /tmp/resut2.txt

abcd

3.3.8 version

功能:输出当前目标 Java 进程所加载的 Arthas 版本号

 

[arthas@31278]$ version

3.6.6

3.3.9 echo

功能:打印参数,和 linux 里的 echo 命令类似

3.3.10 history(重要)

功能:打印命令历史

 

[arthas@31278]$ history 5

35 version

36 echo "hello"

37 history

38 history -h

39 history 5

3.3.11 keymap

功能:Arthas 快捷键列表及自定义快捷键

 

[arthas@31278]$ keymap

Shortcut Description Name

"\C-a" Ctrl + a beginning-of-line

"\C-e" Ctrl + e end-of-line

"\C-f" Ctrl + f forward-word

"\C-b" Ctrl + b backward-word

"\e[D" Left arrow backward-char

"\e[C" Right arrow forward-char

"\e[A" Up arrow history-search-backward

"\e[B" Down arrow history-search-forward

3.3.12 quit(重要)

功能:退出当前 Arthas 客户端,其他 Arthas 客户端不受影响

 

[arthas@31278]$ quit

**deMacBook-Pro:arthas_demo **$

3.3.13 stop(重要)

功能:关闭 Arthas 服务端,所有 Arthas 客户端全部退出

 

[arthas@31278]$ stop

Resetting all enhanced classes ...

Affect(class count: 0 , method count: 0) cost in 6 ms, listenerId: 0

Arthas Server is going to shutdown...

[arthas@31278]$ session (acbf60b7-9cf6-4f50-b030-b861c0f64ca6) is closed because server is going to shutdown.

3.3.14 reset

功能:重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类

 

[arthas@31278]$ reset

Affect(class count: 0 , method count: 0) cost in 0 ms, listenerId: 0

3.2 jvm相关命令

3.2.1 dashboard(重要)

功能:当前系统的实时数据面板,可以显示线程、内存、堆栈、GC、Runtime等信息,刷新实时数据的时间间隔 (ms),默认 5000ms

 

[arthas@31278]$ dashboard

ID NAME GROUP PRIORITY STATE %CPU DELTA_TI TIME INTERRUP DAEMON

-1 C2 CompilerThread0 - -1 - 0.0 0.000 0:7.844 false true

-1 C2 CompilerThread1 - -1 - 0.0 0.000 0:7.694 false true

35 DestroyJavaVM main 5 RUNNABLE 0.0 0.000 0:6.029 false false

-1 VM Periodic Task Thread - -1 - 0.0 0.000 0:5.781 false true

-1 C1 CompilerThread2 - -1 - 0.0 0.000 0:3.371 false true

18 Catalina-utility-2 main 1 TIMED_WA 0.0 0.000 0:0.752 false false

17 Catalina-utility-1 main 1 WAITING 0.0 0.000 0:0.740 false false

-1 VM Thread - -1 - 0.0 0.000 0:0.657 false true

33 http-nio-9091-Poller main 5 RUNNABLE 0.0 0.000 0:0.443 false true

20 mysql-cj-abandoned-connect main 5 TIMED_WA 0.0 0.000 0:0.294 false true

-1 GC task thread#2 (Parallel - -1 - 0.0 0.000 0:0.264 false true

-1 GC task thread#0 (Parallel - -1 - 0.0 0.000 0:0.239 false true

-1 GC task thread#1 (Parallel - -1 - 0.0 0.000 0:0.230 false true

83 arthas-NettyHttpTelnetBoot system 5 RUNNABLE 0.0 0.000 0:0.228 false true

-1 GC task thread#3 (Parallel - -1 - 0.0 0.000 0:0.227 false true

90 arthas-NettyHttpTelnetBoot system 5 RUNNABLE 0.0 0.000 0:0.108 false true

93 arthas-NettyHttpTelnetBoot system 5 RUNNABLE 0.0 0.000 0:0.094 false true

91 arthas-command-execute system 5 TIMED_WA 0.0 0.000 0:0.051 false true

Memory used total max usage GC

heap 79M 341M 1820M 4.34% gc.ps_scavenge.count 12

ps_eden_space 50M 234M 657M 7.65% gc.ps_scavenge.time(ms) 196

ps_survivor_space 0K 10240K 10240K 0.00% gc.ps_marksweep.count 3

ps_old_gen 28M 97M 1365M 2.11% gc.ps_marksweep.time(ms) 490

nonheap 81M 85M -1 95.49%

code_cache 15M 15M 240M 6.30%

metaspace 58M 61M -1 95.05%

compressed_class_space 7M 8M 1024M 0.74%

direct 0K 0K - 0.00%

mapped 0K 0K - 0.00%

Runtime

os.name Mac OS X

os.version 10.16

java.version 1.8.0_181

java.home /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Co

ntents/Home/jre

systemload.average 4.72

processors 4

3.2.2 thread(重要)

功能:查看当前线程信息,显示线程堆栈

  • thread -n 2 -i 5000:展示当前进程中5s内最忙的前2个线程并打印堆栈信息
 

[arthas@31278]$ thread -n 2 -i 5000

"arthas-command-execute" Id=91 cpuUsage=0.87% deltaTime=1ms time=128ms RUNNABLE

at sun.management.ThreadImpl.dumpThreads0(Native Method)

at sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:448)

at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:206)

at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:122)

at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)

at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)

at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)

at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)

at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)

at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)

at java.util.concurrent.FutureTask.run(FutureTask.java:266)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

at java.lang.Thread.run(Thread.java:748)

"C1 CompilerThread2" [Internal] cpuUsage=0.68% deltaTime=1ms time=3662ms

  • 展示所有线程信息,默认按照cpu增量时间降序排列,只显示第一页数据 (thread --all显示所有匹配线程)
 

[arthas@31278]$ thread

Threads Total: 48, NEW: 0, RUNNABLE: 11, BLOCKED: 0, WAITING: 21, TIMED_WAITING: 6, TERMINATED: 0, Internal t

hreads: 10

ID NAME GROUP PRIORITY STATE %CPU DELTA_TI TIME INTERRUP DAEMON

91 arthas-command-execute system 5 RUNNABLE 1.31 0.002 0:0.142 false true

-1 C1 CompilerThread2 - -1 - 0.9 0.001 0:3.685 false true

-1 VM Periodic Task Thread - -1 - 0.05 0.000 0:6.240 false true

-1 C2 CompilerThread1 - -1 - 0.03 0.000 0:7.726 false true

-1 C2 CompilerThread0 - -1 - 0.01 0.000 0:7.896 false true

2 Reference Handler system 10 WAITING 0.0 0.000 0:0.011 false true

3 Finalizer system 8 WAITING 0.0 0.000 0:0.020 false true

4 Signal Dispatcher system 9 RUNNABLE 0.0 0.000 0:0.000 false true

  • 显示指定线程详情(thread id)
 

[arthas@31278]$ thread 21

"Druid-ConnectionPool-Create-1961176822" Id=21 WAITING on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@7d67b0d8

at sun.misc.Unsafe.park(Native Method)

- waiting on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@7d67b0d8

at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)

at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)

at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2813)

  • 显示当前阻塞其他线程的线程 (thread -b)
  • thread -i 1000 : 统计最近 1000ms 内的线程 CPU 时间。
  • thread -n 3 -i 1000 : 列出 1000ms 内最忙的 3 个线程栈
  • thread --state [state] ,查看指定状态的线程 state in (NEW, RUNNABLE, TIMED_WAITING, WAITING, BLOCKED, TERMINATED )

3.2.3 jvm

功能:查看当前 JVM 的信息

  • jvm: 查看当前jvm信息,包含
    • RUNTIME
  • CLASS-LOADING
  • COMPIATION
  • GARBAGE-COLLECTORS
  • MEMORY_MANAGERS
  • MEMORY
  • OPERATING-SYSTEM
  • THREAD
    • COUNT: JVM 当前活跃的线程数
  • DAEMON-COUNT: JVM 当前活跃的守护线程数
  • PEAK-COUNT: 从 JVM 启动开始曾经活着的最大线程数
  • STARTED-COUNT: 从 JVM 启动开始总共启动过的线程次数
  • DEADLOCK-COUNT: JVM 当前死锁的线程数
  • FILE_DESCRIPTOR(文件描述)
    • MAX-FILE-DESCRIPTOR-COUNT:JVM 进程最大可以打开的文件描述符数
  • OPEN-FILE-DESCRIPTOR-COUNT:JVM 当前打开的文件描述符数

3.2.4 sysprop

功能:查看当前JVM系统属性,也可以修改某个属性

  • sysprop:查询所有属性
  • sysprop | grep java :查询java命名相关所有属性
 

[arthas@31278]$ sysprop | grep java

java.specification.v 1.8

java.class.path spring_security_test-0.0.1-SNAPSHOT.jar

java.vm.vendor Oracle Corporation

java.vendor.url http://java.oracle.com/

java.vm.specificatio 1.8

java.home /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre

  • sysprop java.version: 查看单个属性
  • sysprop user.country CN:修改单个属性

3.2.5 sysenv

功能:查看jvm环境变量

  • sysenv: 查询所有环境变量
  • sysenv USER : 查询环境变量USER值

3.2.6 vmoption

功能:查看和更新jvm里诊断相关的option

  • vmoption : 查看所有的vm option
 

[arthas@31278]$ vmoption

KEY VALUE ORIGIN WRITEABLE

-------------------------------------------------------------------------------------------------------------

HeapDumpBeforeFullGC false DEFAULT true

HeapDumpAfterFullGC false DEFAULT true

HeapDumpOnOutOfMemoryErro false DEFAULT true

r

HeapDumpPath DEFAULT true

PrintGC false DEFAULT true

  • vmoption PrintGC : 查看指定的option
 

[arthas@31278]$ vmoption PrintGC

KEY VALUE ORIGIN WRITEABLE

-------------------------------------------------------------------------------------------------------------

PrintGC false DEFAULT true

vmoption PrintGC true : 更新指定的option值

 

[arthas@31278]$ vmoption PrintGC true

Successfully updated the vm option.

NAME BEFORE-VALUE AFTER-VALUE

------------------------------------

PrintGC false true

3.2.7 memory(重要)

功能:查看jvm内存信息

 

[arthas@31278]$ memory

Memory used total max usage

heap 101M 341M 1820M 5.60%

ps_eden_space 73M 234M 657M 11.13%

ps_survivor_space 0K 10240K 10240K 0.00%

ps_old_gen 28M 97M 1365M 2.11%

nonheap 83M 86M -1 95.95%

code_cache 16M 16M 240M 6.87%

metaspace 59M 61M -1 95.38%

compressed_class_space 7M 8M 1024M 0.74%

direct 0K 0K - 0.00%

mapped 0K 0K - 0.00%

3.2.8 heapdump

功能:类似jmap命令heap dump功能

  • heapdump /tmp/dump.hprof : dump到指定目录
  • heapdump --live /tmp/dump.hprof : 只dump live对象到指定目录
  • heapdump : dump到临时文件

3.2.9 logger

功能:查看logger信息,并可更新logger level

  • logger:查看logger信息
  • logger -n org.springframework.web : 查看指定包目录/类的logger信息
  • logger --name ROOT --level debug : 更新指定logger的level等级

3.2.10 ongl

功能:指定ongl表达式,参考:ognl | arthas

3.3 class/classloader相关

3.3.1 classloader(重要)

功能:查看 classloader 的继承树,urls,类加载信息,使用 classloader 去 getResource

  • classloader : 按类加载类型查询统计信息
  • classloader -t :查看classloader的继承树
 

[arthas@31278]$ classloader -t

+-BootstrapClassLoader

+-sun.misc.Launcher$ExtClassLoader@2cdf8d8a

+-com.taobao.arthas.agent.ArthasClassloader@1d11ffe5

+-com.taobao.arthas.agent.ArthasClassloader@10a41d80

+-sun.misc.Launcher$AppClassLoader@55f96302

+-org.springframework.boot.loader.LaunchedURLClassLoader@6267c3bb

Affect(row-cnt:6) cost in 8 ms.

3.3.2 sc

功能:serach class的简写,查看 JVM 已加载的类信息

  • sc com.example.spring_security.service.* : 根据包名模糊搜索包路径下所有类
 

[arthas@31278]$ sc com.example.spring_security.service.*

com.example.spring_security.service.SygPermissionService

com.example.spring_security.service.SygUserService

com.example.spring_security.service.impl.SygPermissionServiceImpl

com.example.spring_security.service.impl.SygUserServiceImpl

  • sc -d com.example.spring_security.service.impl.SygPermissionServiceImpl : 打印类的详细信息
  • sc -d -f com.example.spring_security.service.impl.SygPermissionS : 打印类的详细信息 + 打印出field信息
 

[arthas@67574]$ sc -d -f com.example.spring_security.service.impl.SygPermissionS

class-info com.example.spring_security.service.impl.SygPermissionServic

eImpl

code-source file:/Users/##/Downloads/jacoco-0.8.9/lib/spring_sec

urity_test-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/

name com.example.spring_security.service.impl.SygPermissionServic

eImpl

isInterface false

isAnnotation false

isEnum false

isAnonymousClass false

isArray false

isLocalClass false

isMemberClass false

isPrimitive false

isSynthetic false

simple-name SygPermissionServiceImpl

modifier public

annotation org.springframework.stereotype.Service

interfaces com.example.spring_security.service.SygPermissionService

super-class +-java.lang.Object

class-loader +-org.springframework.boot.loader.LaunchedURLClassLoader@626

7c3bb

+-sun.misc.Launcher$AppClassLoader@55f96302

+-sun.misc.Launcher$ExtClassLoader@2cdf8d8a

classLoaderHash 6267c3bb

fields name LOGGER

type org.slf4j.Logger

modifier final,private,static

value Logger[com.example.spring_security.service.impl.Sy

gPermissionServiceImpl]

name permissionMapper

type com.example.spring_security.dao.SygPermissionMap

per

modifier private

annotation org.springframework.beans.factory.annotation.Aut

owired

3.3.3 sm

功能:search method的简写,查询已加载类的方法信息

  • sm java.lang.String : 查询展示类中所有的方法
 

[arthas@67574]$ sm java.lang.String

java.lang.String <init>([BII)V

java.lang.String <init>([BLjava/nio/charset/Charset;)V

java.lang.String <init>([BLjava/lang/String;)V

java.lang.String equals(Ljava/lang/Object;)Z

java.lang.String toString()Ljava/lang/String;

java.lang.String hashCode()I

java.lang.String compareTo(Ljava/lang/Object;)I

。。。。

java.lang.String copyValueOf([C)Ljava/lang/String;

java.lang.String intern()Ljava/lang/String;

Affect(row-cnt:93) cost in 32 ms.

  • sm -d java.lang.String toString : 查询展示方法的详细信息
 

[arthas@67574]$ sm -d java.lang.String toString

declaring-class java.lang.String

method-name toString

modifier public

annotation

parameters

return java.lang.String

exceptions

classLoaderHash null

Affect(row-cnt:1) cost in 19 ms.

3.3.4 jad(重要)

功能:反编译指定以已加载类的源码,即将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码

  • jad java.lang.String : 反编译某个类源码
  • jad --source-only java.lang.String : 反编译时只显示源代码,配合mc/retransform命令结合使用
  • jad java.lang.String trim : 反编译指定函数
  • jad java.lang.String trim --lineNumber false : 反编译时不显示行号
 

[arthas@67574]$ jad java.lang.String trim --lineNumber false

ClassLoader:

Location:

public String trim() {

int n;

int n2 = this.value.length;

char[] cArray = this.value;

for (n = 0; n < n2 && cArray[n] <= ' '; ++n) {

}

while (n < n2 && cArray[n2 - 1] <= ' ') {

--n2;

}

return n > 0 || n2 < this.value.length ? this.substring(n, n2) : this;

}

Affect(row-cnt:2) cost in 891 ms.

  • jad org.apache.log4j.Logger -c 69dcaba4 : 反编译可以指定classloader hashcode,指定classloader加载的类

3.3.5 mc

功能:memory compiler 内存编译器,编辑java文件生成class文件

  • mc /tmp/Test.java : 内存编译
  • mc -c 327a647b /tmp/Test.java : 指定classloader hashcode编辑
  • mc -d /tmp/output /tmp/ClassA.java : 通过-d 参数指定输出目录

3.3.6 retransform

功能:加载外部class文件,加载到jvm中

  • retransform -c 6267c3bb /tmp/com/example/spring_security/controller/LoginController.class : 根据指定classloader重新加载类信息
 

-- 第一步:反编译class文件成java文件

[arthas@67574]$ jad --source-only com.example.spring_security.controller.LoginController --lineNumber false > /tmp/LoginController.java

-- 第二步:编辑LoginController.java文件

-- 第三步:指定classloader编译java文件成class文件

[arthas@67574]$ mc -c 6267c3bb /tmp/LoginController.java -d /tmp/

Memory compiler output:

/tmp/com/example/spring_security/controller/LoginController.class

Affect(row-cnt:1) cost in 1151 ms

-- 第四步:指定classloader重新加载class文件 (加载成功后可以使用jad查询是否更新成功)

[arthas@67574]$ retransform -c 6267c3bb /tmp/com/example/spring_security/controller/LoginController.class

retransform success, size: 1, classes:

com.example.spring_security.controller.LoginController

使用mc命令来编译jad的反编译的代码有可能失败。可以在本地修改代码,编译好后再上传到服务器上。有的服务器不允许直接上传文件,可以使用base64命令来绕过。

 

-- 第一步:生成类.class文件进行base64编码文件

[arthas@98006]$ base64 --input /Users/**/workspace/spring_security/target/classes/com/example/spring_security/controller/LoginController.class --output /tmp/LoginController_base64.txt

-- 第二步:上传到服务器上

-- 第三步:把base64编码文件反编译成类.class文件

[arthas@98006]$ base64 -d /tmp/LoginController_base64.txt --output /tmp/LoginController.class

-- 第四步:指定classloader重新加载class文件 (加载成功后可以使用jad查询是否更新成功)

[arthas@98006]$ retransform -c 6267c3bb /tmp/LoginController.class

retransform success, size: 1, classes:

com.example.spring_security.controller.LoginController

备注:第一二三步骤可以合并成一步,直接上传本地class文件

  • retransform -l : 查看retransform记录列表
 

[arthas@67574]$ retransform -l

Id ClassName TransformCount LoaderHash LoaderClassName

1 com.example.spr 1 6267c3bb null

ing_security.co

ntroller.LoginC

ontroller

2 com.example.spr 1 6267c3bb null

ing_security.co

ntroller.LoginC

ontroller

  • retransform -d 1 : 根据指定id删除retransform
  • retransform --deleteAll : 删除所有retransform记录(备注:如果不清除掉所有的 retransform entry,并重新触发 retransform ,则 arthas stop 时,retransform 过的类仍然生效。)

3.4 监控相关

请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 stop 或将增强过的类执行 reset 命令

3.4.1 monitor

功能:方法执行监控,monitor 命令是一个非实时返回命令,是不断的等待目标 Java 进程返回信息,直到用户输入 Ctrl+C 为止。匹配 class-pattern 类名表达式匹配/method-pattern 方法名表达式匹配/condition-express 条件表达式 的类、方法的调用进行监控。

  • monitor com.example.spring_security.controller.LoginController showLogin -n 10 --cycle 10 : -n 表示次数, --cycle / -c 表示周期,单位为秒
 

[arthas@67574]$ monitor com.example.spring_security.controller.LoginController showLogin -n 10 --cycle 10

Press Q or Ctrl+C to abort.

Affect(class count: 1 , method count: 1) cost in 573 ms, listenerId: 1

timestamp class method tota succe fail avg- fail

l ss rt(m -rat

s) e

--------------------------------------------------------------------------------

2022-11-17 com.example.sprin showLogin 2 2 0 1.73 0.00

15:55:20 g_security.contro %

ller.LoginControl

ler

可使用arthas插件直接生成monitor监控命令

 

  • monitor -c 5 com.example.spring_security.controller.LoginController showLogin "params[0] <= 2" :计算条件表达式过滤统计结果(方法执行完毕之后)
  • monitor -b -c 5 com.example.spring_security.controller.LoginController showLogin "params[0] <= 2" :计算条件表达式过滤统计结果(方法执行完毕之前)

3.4.2 stack

功能:输出当前方法被调用的调用路径

  • stack com.example.spring_security.controller.LoginController showLogin -n 5 : -n表示统计次数
 

$ stack demo.MathGame primeFactors

Press Ctrl+C to abort.

Affect(class-cnt:1 , method-cnt:1) cost in 36 ms.

ts=2018-12-04 01:32:19;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69

@demo.MathGame.run()

at demo.MathGame.main(MathGame.java:16)

  • stack com.example.spring_security.controller.LoginController showLogin '#cost>5000' : 根据时间过滤,单位毫秒
  • 过滤条件包含
    • target : the object
  • clazz : the object's class
  • method : the constructor or method
  • params : the parameters array of method
  • params[0..n] : the element of parameters array
  • returnObj : the returned object of method
  • throwExp : the throw exception of method
  • isReturn : the method ended by return
  • isThrow : the method ended by throwing exception
  • #cost : the execution time in ms of method invocation

3.4.3 trace

功能:方法内部调用路径,并输出方法路径上的每个节点上耗时

  • trace com.example.spring_security.controller.LoginController showLogin -n 5 --skipJDKMethod false : -n 表示次数; --skipJDKMethod <value> skip jdk method trace, default value true.
 

[arthas@67574]$ trace com.example.spring_security.controller.LoginController showLogin -n 5 --skipJDKMethod false

Press Q or Ctrl+C to abort.

Affect(class count: 1 , method count: 1) cost in 86 ms, listenerId: 5

---ts=2022-11-17 16:21:24;thread_name=http-nio-9091-exec-7;id=1c;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@3bb9a3ff

---[1.289843ms] com.example.spring_security.controller.LoginController:showLogin()

`---[20.84% 0.268813ms ] com.example.spring_security.util.LoggerUtil:info() #26

3.4.4 tt(重要)

功能:Time Tunnel,方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测

  • tt -t com.example.spring_security.controller.LoginController showLogin -n 5 : -t 记录方法的每次执行情况; -n记录次数
 

[arthas@67574]$ tt -t com.example.spring_security.controller.LoginController showLogin -n 5

Press Q or Ctrl+C to abort.

Affect(class count: 1 , method count: 1) cost in 95 ms, listenerId: 7

IND TIMESTAMP COST( IS- IS OBJECT CLASS METHOD

EX ms) RET -E

XP

--------------------------------------------------------------------------------

100 2022-11-17 0.955 tru fa 0x153e05 LoginController showLogin

0 16:27:57 693 e ls 63

e

100 2022-11-17 0.309 tru fa 0x153e05 LoginController showLogin

1 16:28:09 833 e ls 63

e

参数说明

  • INDEX 时间片段记录编号,每一个编号代表着一次调用,后续 tt 还有很多命令都是基于此编号指定记录操作,非常重要。
  • TIMESTAMP 方法执行的本机时间,记录了这个时间片段所发生的本机时间
  • COST(ms) 方法执行的耗时
  • IS-RET 方法是否以正常返回的形式结束
  • IS-EXP 方法是否以抛异常的形式结束
  • OBJECT 执行对象的hashCode(),注意,曾经有人误认为是对象在 JVM 中的内存地址,但很遗憾他不是。但他能帮助你简单的标记当前执行方法的类实体
  • CLASS 执行的类名
  • METHOD 执行的方法名
  • tt -t *Test print params.length==1 或 tt -t *Test print 'params[1] instanceof Integer' : 可解决方法重载问题
  • tt -t *Test print params[0].mobile=="13989838402" 可根据指定参数记录
  • tt -l :检索调用记录
  • tt -s 'method.name=="showLogin"' : 根据指定的方法名称搜索执行记录
  • tt -i 1001 : 查看具体时间片段信息
 

[arthas@67574]$ tt -i 1001

INDEX 1001

GMT-CREATE 2022-11-17 16:28:09

COST(ms) 0.309833

OBJECT 0x153e0563

CLASS com.example.spring_security.controller.LoginController

METHOD showLogin

IS-RETURN true

IS-EXCEPTION false

RETURN-OBJ @String[login]

Affect(row-cnt:1) cost in 114 ms.

  • tt -i 1001 -p : 根据时间片段id重新执行,可通过 --replay-times 指定 调用次数,通过 --replay-interval 指定多次调用间隔(单位 ms, 默认 1000ms)
 

[arthas@67574]$ tt -i 1001 -p

RE-INDEX 1001

GMT-REPLAY 2022-11-17 16:41:53

OBJECT 0x153e0563

CLASS com.example.spring_security.controller.LoginController

METHOD showLogin

IS-RETURN true

IS-EXCEPTION false

COST(ms) 19.28108

RETURN-OBJ @String[login]

Time fragment[1001] successfully replayed 1 times.

3.4.4 watch(重要)

功能:函数执行数据观测

  • watch com.example.spring_security.controller.LoginController showLogin '{params,returnObj,throwExp}' -n 5 -x 3 :-x表示遍历深度,可以调整来打印具体的参数和结果内容,默认值是 1,最大值是4。
 

[arthas@67574]$ watch com.example.spring_security.controller.LoginController showLogin '{params,returnObj,throwExp}' -n 5 -x 3

Press Q or Ctrl+C to abort.

Affect(class count: 1 , method count: 1) cost in 77 ms, listenerId: 9

method=com.example.spring_security.controller.LoginController.showLogin location=AtExit

ts=2022-11-17 16:55:30; [cost=1.14587ms] result=@ArrayList[

@Object[][isEmpty=true;size=0],

@String[login],

null,

]

  • watch 命令定义了 4 个观察事件点,即 -b 函数调用前,-e 函数异常后,-s 函数返回后,-f 函数结束后
  • 4 个观察事件点 -b、-e、-s 默认关闭,-f 默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出
  • watch demo.MathGame primeFactors "{params[0],throwExp}" -e -x 2 : -e 只观测接口异常场景
  • watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0" :增加条件表达式,条件为第一个参数小于0
  • watch demo.MathGame primeFactors '{params, returnObj}' '#cost>200' -x 2 : 按照耗时来过滤,单位为毫秒

4.arthas idea插件及其使用

下载地址:arthas idea - IntelliJ IDEs Plugin | Marketplace 下载完成后本地安装arthas插件

 

 

5.热部署插件

热部署组件支持一键将编辑器中修改的 Java 源码快速编译,并更新到远端应用服务中,免去手动 dump、mc 的过程。此外,也可以一键还原 retransform 的类文件。

热更新(HotSwap)可以在 Java 程序运行时,更新部分 class 文件,而无需重启应用。应用观测器的热部署组件支持一键将编辑器中修改的 Java 源码快速编译,并更新到远端应用服务中,免去构建、打包和重部署的过程,帮助开发者快速验证修复方案的有效性。

适用场景

  • 将编辑器内修改的 Java 源代码更新到远端应用里,快速验证修复方法的有效性,而免去耗时的构建、集成和部署过程;
  • 对于本地无法搭建运行环境的应用,可以结合应用观测和热部署功能实现远程调试和修复验证。

安装Alibaba Cloud Toolkit

 

5.1 使用IntelliJ IDEA部署应用到Linux服务器

问题:现有部署流程,需要先本地打包,然后上传到服务器,再执行重启服务脚本,此流程需要在各种运维工具中切换使用,流程比较长并且比较耗时,并且可能出现错误,可以通过Cloud Toolkit一键部署到服务器上!!

 

 

启动脚本demo,命名为restartup.sh,存储在/Users/***/Downloads/spring_alibaba_toolkit/目录中,并需要给restartup.sh赋予执行权限,chmod -R 777 restartup.sh

 

killall java

java -jar /Users/**/Downloads/spring_alibaba_toolkit/spring_security_test-0.0.1-SNAPSHOT.jar

备注:慎用 killall java,需要查询出指定服务进程,然后通过kill查杀指定进程服务!

After deploy启动脚本参数 配置demo:

 

sh /Users/**/Downloads/spring_alibaba_toolkit/restartup.sh

然后点击RUN即可自动部署服务到指定服务器目录中,并启动服务

添加服务器操作demo

 

备注:mac电脑需要先开启ssh远程访问,配置地址在共享-远程登录,打开即可; linux可以通过命令开通,自行百度下

5.2 Alibaba Cloud Toolkit使用arthas诊断功能

 

备注:第一次使用Diagnostic Tools诊断时,会自动安装并初始化Arthas。您需要等待约一分钟后即可开始使用。

 

然后使用同在服务器上面使用arthas诊断工具操作

备注:通过Aibaba Cloud View标签页面,也可以看出Actions中有多个功能,上传:上传本地文件进服务器;终端:打通终端命令窗口;执行命令:可预设值多条命令,直接选择某条命令直接执行;应用观察:此功能由bug😓;属性:查询链接属性;远端文件:查询服务器上所有文件;诊断:使用arthas诊断工具;移除:删除此ip地址。

5.3 代码监测

Cloud Toolkit集成了Java代码检查功能。该功能基于《阿里巴巴Java开发手册》中的代码规约,执行Java代码的静态检查,帮助您在编译前快速发现代码异常,并提供修改建议。

 

 

5.4 热部署

步骤一:进入热部署页面

  • 方式一:快捷入口打开方式二:工程中右键打开

  • 方式二:工程中右键打开

 

 

步骤二:选择目标主机和目标进程进行链接

 

选择主机和目标进程后,点击链接后进行链接

 

备注:

1.请确保已安装 JDK 并在 ~/.bashrc 里面配置 JAVA_HOME,此外必须存在 JAVA_HOME/lib/tools.jar

2.热部署不能和arthas服务器同时启动,否则热部署链接目标进程会失败

3.目前功能不支持目标主机为本地服务器地址,如果选择是本地目标主机地址,则选择目标进程为空(同官方人员确认!!!别踩坑,不是你本地配置问题!!!),如下图所示

步骤三:建立连接后,在想要热部署的源码文件上右击(或者直接在类中右击选择热部署),选择“热部署”。(可以先进行热部署,测试是否成功后再改动代码,再次点击热部署改动代码才能生效)

 

步骤四:部署成功的文件会显示在热部署工具窗口下方,点击名称可以跳转到对应源码文件,点击右侧按钮还原对应文件的全部修改。

 

步骤五:测试完成后,需要还原热部署源文件,再断开链接,否则热部署文件不会失效(重启之后才会失效热部署代码)!!!

不适用热部署的情况

  • 类的继承关系、接口不能改变,包括添加、删除、修改或改变先后顺序等;
  • 不能添加、删除、修改类字段、以及字段的访问控制符;
  • 不能修改类字段的排列顺序;
  • 不能增加、修改或删除方法签名、访问控制符,可以添加或删除 private static 或 private (static) final 方法;
  • Open JDK(jdk8u74-b02)之前的版本不能热部署包含 lambda 表达式的源码文件;
  • Open JDK(jdk8u74-b02)之后的版本热部署时,不能改变 lambda 表达式在源码文件中出现的顺序;
  • 可以添加、删除或修改内部类,但要注意不要改变内部类首次被调用的顺序;
  • 不能热部署增加、删除或修改闭包的源码文件。

6.踩到的坑

arthas启动报错

 

原因:在百度网盘里面下载的jdk安装包,安装包中工具不全导致,需要在官网中下载安装包:https://www.oracle.com/java/technologies/downloads/#java8

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值