侧边栏壁纸
博主头像
憨憨大头个人博客博主等级

心存希冀,目有繁星

  • 累计撰写 110 篇文章
  • 累计创建 13 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Arthas(阿尔萨斯)的基本使用

Administrator
2024-08-03 / 0 评论 / 0 点赞 / 12 阅读 / 14839 字

目录

1.安装使用

2.attach一个进程

3.常用命令的接触 dashboard thread

4.jvm相关命令:sysprop sysenv vmoption getstatic ognl

5.class 和classloader相关的命令

阿尔萨斯的使用案例

用户文档:Arthas 用户文档 — Arthas 3.5.6 文档

当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

  • 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?

  • 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?

  • 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?

  • 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!

  • 是否有一个全局视角来查看系统的运行状况?

  • 有什么办法可以监控到JVM的实时运行状态?

  • 怎么快速定位应用的热点,生成火焰图?

  • 怎样直接从JVM内查找某个类的实例?

1.安装使用

前提:Arthas是一个java的程序,运行前需保证机器上有正在运行的java进程,不然Arthas无法启动

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

2.启动arthas

在命令行下面执行(使用和目标进程一致的用户启动,否则可能 attach 失败):

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
  • 执行该程序的用户需要和目标进程具有相同的权限。比如以admin用户来执行:sudo su admin && java -jar arthas-boot.jarsudo -u admin -EH java -jar arthas-boot.jar
  • 如果 attach 不上目标进程,可以查看~/logs/arthas/ 目录下的日志。
  • 如果下载速度比较慢,可以使用 aliyun 的镜像:java -jar arthas-boot.jar --repo-mirror aliyun --use-http
  • java -jar arthas-boot.jar -h 打印更多参数信息。

3. 查看 dashboard

输入dashboard,按回车/enter,会展示当前进程的信息,按ctrl+c可以中断执行。

$ dashboard
ID     NAME                   GROUP          PRIORI STATE  %CPU    TIME   INTERRU DAEMON
17     pool-2-thread-1        system         5      WAITIN 67      0:0    false   false
27     Timer-for-arthas-dashb system         10     RUNNAB 32      0:0    false   true
11     AsyncAppender-Worker-a system         9      WAITIN 0       0:0    false   true
9      Attach Listener        system         9      RUNNAB 0       0:0    false   true
3      Finalizer              system         8      WAITIN 0       0:0    false   true
2      Reference Handler      system         10     WAITIN 0       0:0    false   true
4      Signal Dispatcher      system         9      RUNNAB 0       0:0    false   true
26     as-command-execute-dae system         10     TIMED_ 0       0:0    false   true
13     job-timeout            system         9      TIMED_ 0       0:0    false   true
1      main                   main           5      TIMED_ 0       0:0    false   false
14     nioEventLoopGroup-2-1  system         10     RUNNAB 0       0:0    false   false
18     nioEventLoopGroup-2-2  system         10     RUNNAB 0       0:0    false   false
23     nioEventLoopGroup-2-3  system         10     RUNNAB 0       0:0    false   false
15     nioEventLoopGroup-3-1  system         10     RUNNAB 0       0:0    false   false
Memory             used   total max    usage GC
heap               32M    155M  1820M  1.77% gc.ps_scavenge.count  4
ps_eden_space      14M    65M   672M   2.21% gc.ps_scavenge.time(m 166
ps_survivor_space  4M     5M    5M           s)
ps_old_gen         12M    85M   1365M  0.91% gc.ps_marksweep.count 0
nonheap            20M    23M   -1           gc.ps_marksweep.time( 0
code_cache         3M     5M    240M   1.32% ms)
Runtime
os.name                Mac OS X
os.version             10.13.4
java.version           1.8.0_162
java.home              /Library/Java/JavaVir
                       tualMachines/jdk1.8.0
                       _162.jdk/Contents/Hom
                       e/jre

arthas常用命令文档:arthas常用命令文档

常见的调优方法

trace 方法

所在文件全路径 方法名
比如说我想查看ImpDocServiceImpl 的add方法
例:trace com.bxkc.service.impl.backend.win.database.WinDatabaseServiceImpl winProjectDbList
调用接口后,出现如下,可以清晰的看到每行代码的耗时

image-20220926144647196

thread

thread命令列出线程的信息

image-20220926145738603

thread -b查看死锁

image-20220926145927528

dashboard

这个我们可以用dashboard命令来动态查看内存情况

image-20220926150137222

如果内容使用率在不断上升,而且gc后也不下降,后面还发现gc越来越频繁,很可能就是内存泄漏了。

这个时候我们可以直接用heapdump命令把内存快照dump出来,作用和jmap工具一样

watch——方法执行数据观测

代码演示:

[root@172-21-21-98 ~]$ # 初次启动arthas 
[root@172-21-21-98 ~]$ docker exec -it  x-service-xxxx /bin/sh -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar --repo-mirror aliyun --use-http"
[INFO] arthas-boot version: 3.4.8
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 6 x-service-xxxx-1.0.0-SNAPSHOT.jar
# 输入服务的编号:1,按enter,
1

[INFO] arthas home: /app/arthas
[INFO] Try to attach process 6
[INFO] Attach process 6 success.
# 成功attch到x-service-xxxx服务
# 开始播放arthas的开机动画😋...
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.                           
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'                          
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.                          
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |                         
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'                          
                                                                               
wiki      https://arthas.aliyun.com/doc                                         
tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html                   
version   3.4.8                                                                 
pid       6                                                                     
time      2021-03-25 15:57:08                                                   

[arthas@6]$
[arthas@6]$ # 输入命令,watch 类名(q全限定名,即类的完整路径) 方法名 OGNL表达式(查看入参)-x 2 (查看对象的层级)
[arthas@6]$ watch com.x.service.xxxx.service.impl.DemandTemplateServiceImpl saveMiddleTempList "{params}" -x 2

Press Q or Ctrl+C to abort.
Affect(class count: 2 , method count: 1) cost in 513 ms, listenerId: 5
# 程序等待...  
# 去页面点击一下,触发函数
method=com.x.service.xxxx.service.impl.DemandTemplateServiceImpl.saveMiddleTempList location=AtExceptionExit
ts=2021-03-27 12:31:12; [cost=73.741218ms] result=@ArrayList[
    @Object[][
        @ArrayList[isEmpty=false;size=9],
        @String[1008],
        @String[group1/M00/02/08/rBUVDGBYZxOAV2ZHAAi3CxHKUZo90.docx],
        @String[测试拆分场景.docx],
        @String[XQ20210322-0062],
    ],
]
# 好,看到了 按Ctrl+C中断监听

不用发版,热更新代码✨

retransform——加载外部的.class文件,retransform到JVM里

jad——查看已加载类的源码/ 查看类中某个方法的源码。

image-20210327145943341

代码演示:

[root@172-21-21-98 ~]$ # 1. 将class文件上传到服务器,放在/tmp目录下 即:/tmp/DemandTemplateServiceImpl.class
[root@172-21-21-98 ~]$ # 此过程略
[root@172-21-21-98 ~]$ 
[root@172-21-21-98 ~]$ # 2. 将class文件拷贝到docker容器中
[root@172-21-21-98 ~]$ docker cp /tmp/DemandTemplateServiceImpl.class x-service-xxxx:/tmp/
[root@172-21-21-98 ~]$ 
[root@172-21-21-98 ~]$ # 3. 再次启动arthas
[root@172-21-21-98 ~]$ docker exec -it  x-service-xxxx /bin/sh -c "java -jar arthas-boot.jar"
[INFO] arthas-boot version: 3.4.8
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 6 x-service-xxxx-1.0.0-SNAPSHOT.jar
# 4. 输入1 ,attch到x-service-xxxx服务
1
[INFO] arthas home: /app/arthas
[INFO] Try to attach process 6
[INFO] Attach process 6 success.
# 开机动画
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.                           
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'                          
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.                          
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |                         
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'                          
                                                                               
wiki      https://arthas.aliyun.com/doc                                         
tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html                   
version   3.4.8                                                                 
pid       6                                                                     
time      2021-03-25 15:57:08                                                   

[arthas@6]$ # 5. retransform热更新代码
[arthas@6]$ retransform /tmp/DemandTemplateServiceImpl.class
retransform success, size: 1, classes:
com.x.service.xxxx.service.impl.DemandTemplateServiceImpl
[arthas@6]$ 
[arthas@6]$ # 6. 查看方法的代码,确定是否修改成功 (可选参数 --source-only (只查看源代码) --lineNumber false (不显示行号) )
[arthas@6]$ jad --source-only --lineNumber false com.x.service.xxxx.service.impl.DemandTemplateServiceImpl saveMiddleTempList

private void saveMiddleTempList(List<WordDirectoryInfo> allSceneList, String tenantsNo, String filePath, String fileName, String bizReqrmntNo) {
    ArrayList<MiddleTempEntity> insertList = new ArrayList<MiddleTempEntity>(allSceneList.size());
    for (WordDirectoryInfo dir : allSceneList) {
        String inno = this.generateNo.getNo(tenantsNo, GenerateNoPrefixEnum.DEMAND_SCENARIO_MIDDLE.getValue(), 18);
        MiddleTempEntity entity = new MiddleTempEntity(tenantsNo, inno, dir.getText(), null, fileName, filePath, bizReqrmntNo);
        entity.setCrtTm(LocalDateTime.now().toString());
        entity.setModfyTm(LocalDateTime.now().toString());
        insertList.add(entity);
    }
    log.debug("insertList:{}", (Object)((Object)insertList).toString());
    try {
        this.middleTempMapper.insertList(insertList);
    }
    catch (Exception e) {
        log.error(">>>saveMiddleTempList-数据库写入失败!", (Throwable)e);
        throw new CommonException("文件检查失败:数据库异常!");
    }
}

[arthas@6]$ 
[arthas@6]$ # 7. 热更新成功!
0

评论区