curl命令java_卧槽!!又一款Java调试神器来袭~我爱了

d905b0e0808bbb12f3aea38df1a7c420.gif 关注Java技术迷升职加薪不脱发!

c53ddcfee3db8f832dfc0461657aa70a.png

你有没有遇到这种问题,在线下写得代码自信满满,肯定不会再出什么幺蛾子了~然而,一上线,就GG,要调试起来太麻烦,烦的一比。

其实现在这种情况比较少了,毕竟上线一点点代码,都需要经过几轮测试,提交上线报告,你写得那点代码才会上线,所以,要出现上面这种情况还是比较少。

然而,生产环境一般出现的问题,没有一点硬功夫(经验)还真不那么容易分析出来。刚好阿里推出一款一款Java诊断工具——Arthas,菜鸟也可以在线分析调试代码,找出病因~

9b49c16ab1aaaa6083c68a7b6c75d092.png

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

它主要解决的痛点:

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

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

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

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

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

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

  • 线上代码有错误,不想重新发布?那能不能改class文件替换一下?

看到它能解决这些问题,心里挺激动的,这不正是我们线上调试想要的吗^_^

# 支持环境

JDK 6+,Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能

# 安装

1、下载jar

默认推荐的安装方式,使用jar方式来启动

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

90d1c68a6fd0a88709a24fcf0caf31fb.png

其实,我写本文时,用的是Windows操作系统,我直接下载的

1cb3867805087eb54baa1eaa68966345.png

打印帮助信息

java -jar arthas-boot.jar -h

3b02fe9d73066ae9eddf690e8ec63ff2.png

重点说明:--target-ip 一定要是arthas所在机器对外暴露的ip,默认是127.0.0.1,只能本地访问。

2、在线安装

此方式只适应于 Linux/Unix/Mac 等平台,命令如下:

curl -L https://arthas.aliyun.com/install.sh | sh

启动arthas

./as.sh PID #进程id 指定JAVA进程id./as.sh -h #h来获取更多参数信

3、在docker中安装

#运行arthas-demodocker run --name arthas-demo -it hengyunabc/arthas:latest /bin/sh -c "java -jar /opt/arthas/arthas-demo.jar"#安装arthasdocker exec -it  ${containerId} /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"

也可以很简单把Arthas安装到你的Docker镜像里,如下:

FROM openjdk:8-jdk-alpine# copy arthasCOPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas

4、启动时,attach自身进程

1)Arthas Spring Boot Starter

目前只支持springboot 2,添加maven:

    com.taobao.arthas    arthas-spring-boot-starter    ${arthas.version}

配置属性:

arthas.agent-id=hsehdfsfghhwertyfadarthas.tunnel-server=ws://47.75.156.201:7777/ws

通过访问http://localhost:8080/actuator/arthas,来查看agent-id,如下:

{    "arthasConfigMap": {        "agent-id": "hsehdfsfghhwertyfad",        "tunnel-server": "ws://47.75.156.201:7777/ws",    }}

2)非spring boot应用

添加maven依赖:

<dependency>  <groupId>com.taobao.arthasgroupId>  <artifactId>arthas-agent-attachartifactId>  <version>${arthas.version}version>dependency><dependency>  <groupId>com.taobao.arthasgroupId>  <artifactId>arthas-packagingartifactId>  <version>${arthas.version}version>dependency>

添加启动代码:

import com.taobao.arthas.agent.attach.ArthasAgent;  public class ArthasAttachExample {    public static void main(String[] args) {      ArthasAgent.attach();    }}

# 远程连接

1、WebConsole

通过浏览器http访问8563端口,注意页面红色框内的IP也必须指定服务端的IP,不能用默认的127.0.0.1,如下:

17f0c75cf41786f331f5e5cf4a113dc7.png

2、telnet

说明一下,Windows默认telnet客服端没有开启,需要你手动开启一下。

4102b5b69406679c17e8c6402d5d682a.png

3、tunnel server方式

下载相关jar包

f8e1e6ed35dcb64e0158c4f57f230783.png

启动:

java -jar  arthas-tunnel-server.jar

默认情况下,arthas tunnel server的web端口是8080,arthas agent连接的端口是7777。

启动arthas,注册到tunnel server,并指定一个agent-id:mytest123(默认是随机产生):

java -jar arthas-boot.jar --tunnel-server 'ws://192.168.1.28:7777/ws' --agent-id mytest123

如下图所示,表面生成成功:

6f01243a9a567dbadebe70cc6f58956b.png

这时,便可以访问 http://localhost:8080/ ,再通过agentId连接到已注册的arthas agent上。

35835b0120ce27c864f9e42b8c583209.png

最后,放一张arthas tunnel server的架构示意图,有助于我们理解tunnel server和arthas agent的关系,见下图

d2da5311d88bd87ec1a4d29ce6b4531b.png

# 常用命令

1、Dashboard 命令

查看当前系统的实时数据面板,例如:服务器thread信息、内存memory、GC回收等情况

7f1dffb86fcf0e3acddf7248d5252e4a.png

2、Thread(线程监控)

99b955146cb02ee6a716063b2ce743db.png

$ thread -n 3"as-command-execute-daemon" Id=57 cpuUsage=72% RUNNABLEat 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:133)at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:79)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:370)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)Number of locked synchronizers = 1 - java.util.concurrent.ThreadPoolExecutor$Worker@a2f70c7

可以看到这个线程是被synchroned关键字锁导致的阻塞 ,目前只支持找出synchronized关键字阻塞住的线程, 如果是java.util.concurrent.Lock, 目前还不支持。

3、trace (当前方法内部调用路径,路径上每个节点的耗时)

$ trace #类名  #方法名
3e66afc7dfcecc5c744960828561f994.png

对于执行耗时相对较长的方法,调用链路耗时属性会高亮显示方便排查

f4f7fa8b554749cd3d201b845df00306.png

4、JVM (jvm实时运行状态,内存使用情况等)

$ jvm RUNTIME                                                                                                                                                                                                                                    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MACHINE-NAME                                                       28679@iz2zehzeir87zi8q99krk1z                                                                                                                                            JVM-START-TIME                                                     2019-03-28 17:32:16MANAGEMENT-SPEC-VERSION                                            1.2 SPEC-NAME                                                          Java Virtual Machine Specification                                                                                                                                       SPEC-VENDOR                                                        Oracle Corporation                                                                                                                                                       SPEC-VERSION                                                       1.8 VM-NAME                                                            Java HotSpot(TM) 64-Bit Server VM                                                                                                                                        VM-VENDOR                                                          Oracle Corporation                                                                                                                                                       VM-VERSION                                                         25.191-b12                                                                                                                                                              INPUT-ARGUMENTS                                                    []                                                                                                                                                                      CLASS-PATH                                                         demo-0.0.1-SNAPSHOT.jar                                                                                                                                                  BOOT-CLASS-PATH                                                    /usr/local/jdk/jre/lib/resources.jar:/usr/local/jdk/jre/lib/rt.jar:/usr/local/jdk/jre/lib/sunrsasign.jar:/usr/local/jdk/jre/lib/jsse.jar:/usr/local/jdk/jre/lib/jce.jar                                                                     :/usr/local/jdk/jre/lib/charsets.jar:/usr/local/jdk/jre/lib/jfr.jar:/usr/local/jdk/jre/classes                                                                          LIBRARY-PATH                                                       /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib

5、watch

当前方法执行数据观测,能观察到的范围为:返回值、抛出异常、入参

$ trace #类名  #方法名 "{params,target,returnObj,throwExp }"OGNL 表达式 {params,target,returnObj,throwExp }throwExp:异常params :入参(数组),单个参数params【0】returnObj:返回值
$ watch com.example.demo.controller index2 "{params,target,returnObj}" -x 5Press Q or Ctrl+C to abort.Affect(class-cnt:1 , method-cnt:1) cost in 81 ms.ts=2019-03-29 14:24:14; [cost=1000.746582ms] result=@ArrayList[    @Object[][        @String[辛志富],    ],    @controller[    ],    @String[index2],]

6、stack

当前方法被调用的路径,显示当前方法被那些方法调用

public static String uuidOne() {    return uuidTwo();}public static String uuidTwo() {    return UUID.randomUUID().toString().replaceAll("-", "");}$ stack  com.example.demo.controller uuidTwoPress Q or Ctrl+C to abort.Affect(class-cnt:1 , method-cnt:1) cost in 58 ms.ts=2019-03-29 14:38:19;thread_name=http-nio-8888-exec-5;id=13;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@525b461a    @com.example.demo.controller.uuidOne()        at com.example.demo.controller.index2(controller.java:31)        at sun.reflect.GeneratedMethodAccessor36.invoke(null:-1)        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

7、monitor 命令

监控类、方法的调用进行监控,调用次数、成功次数、失败次数、平均响应时长、失败率等。

$ monitor -c 4 com.example.demo.controller uuidTwoPress Q or Ctrl+C to abort.Affect(class-cnt:1 , method-cnt:1) cost in 56 ms. timestamp            class                        method   total  success  fail  avg-rt(ms)  fail-rate                                                                                                                                     --------------------------------------------------------------------------------------------------------                                                                                                                                     2019-03-29 14:55:40  com.example.demo.controller  uuidTwo  7      7        0     0.18        0.00%      

8、classloader 命令

将JVM中所有的类加载器统计出来,树状展示

$ classloader #每种classloader加载类的个树 name                                                    numberOfInstances  loadedCountTotal                                                                                                                                                 org.springframework.boot.loader.LaunchedURLClassLoader  1                  4463                                                                                                                                                             com.taobao.arthas.agent.ArthasClassloader               2                  3631                                                                                                                                                             BootstrapClassLoader                                    1                  2961                                                                                                                                                             java.net.FactoryURLClassLoader                          1                  835                                                                                                                                                              sun.misc.Launcher$AppClassLoader                        1                  46                                                                                                                                                               sun.reflect.DelegatingClassLoader                       41                 41                                                                                                                                                               sun.misc.Launcher$ExtClassLoader                        1                  25                                                                                                                                                              Affect(row-cnt:7) cost in 7 ms.$ classloader -t    # 类加载器间的层级关系+-BootstrapClassLoader                                                                                                                                                                                                                      +-sun.misc.Launcher$ExtClassLoader@1959f618                                                                                                                                                                                                   +-com.taobao.arthas.agent.ArthasClassloader@5fc476c6                                                                                                                                                                                        +-com.taobao.arthas.agent.ArthasClassloader@5017e14b                                                                                                                                                                                        +-sun.misc.Launcher$AppClassLoader@5c647e05                                                                                                                                                                                                   +-java.net.FactoryURLClassLoader@4ad317f0                                                                                                                                                                                                   +-org.springframework.boot.loader.LaunchedURLClassLoader@20ad9418                                                                                                                                                                       Affect(row-cnt:7) cost in 5 ms

# 实战案例

我在网上看到一个动态修改上线项目的案例,我觉得比较有意思,这里整理一下给大家分享一下。

这个案例主要做了一件事情,在不停机不重启不重新发包的情况下,手动在代码中去掉抛异常代码,具体要修改的代码如下:

53547fb1c668e025b2a7ffab4252d53a.png

启动服务也达到我们预期异常

f6b7b1bcb83d49db32bd2b5ce36e6274.png

具体替换代码的流程如下:

1、jad:将需要更改的文件先进行反编译,保存下来 ,编译器修改

$ jad --source--only com.example.demo.DemoApplication > /data/DemoApplication.java

2、SC:查找当前类是哪个classLoader加载的

$ sc -d *DemoApplication | grep classLoader classLoaderHash   20ad9418 #类加载器  编号

3、MC:用指定的classloader重新将类在内存中编译

$ mc -c 20ad9418 /data/DemoApplication.java -d /data Memory compiler output:/data/com/example/demo/DemoApplication.class

4、redefine:将编译后的类加载到JVM,上边编译后的.class文件地址

$ redefine /data/com/example/demo/DemoApplication.class  redefine success, size: 1

文件替换后我们再次访问一下程序,发现异常没有了程序已经是我们修改正确后的,class文件替换成功

2f93cba5006fd9e5cd426fe94714a7d2.png

结合这个案例一看,阿里出品的这款神器简直要超神了,这么多命令,记不住怎么办呢?咱们下一篇继续告诉你该怎么来玩转这些命令~

最后,如果觉得这款神器不错,记得点赞、转发支持一波~

# 参考

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

  • https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn

推荐阅读  点击标题可跳转几个IDEA的Sao技巧,效率提升了10倍,网友:没有灵魂!为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?你还在用 Swagger?试试这个神器,不香吗?看完本文有收获?请转发分享给更多人

关注「Java技术迷」,提升Java技

215fcd556c02ba42fa6061794e7e02fb.pngd002e9020fe682f7943a864aac3b452a.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值