Java线上问题排查工具Arthas 原理以及用法是什么

66次阅读
没有评论

共计 9143 个字符,预计需要花费 23 分钟才能阅读完成。

这篇文章将为大家详细讲解有关 Java 线上问题排查工具 Arthas 原理以及用法是什么,文章内容质量较高,因此丸趣 TV 小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

前言

当你兴冲冲地开始运行自己的 Java 项目时,你是否遇到过如下问题:

程序在稳定运行了,可是实现的功能点了没反应。

为了修复 Bug 而上线的新版本,上线后发现 Bug 依然在,却想不通哪里有问题?

想到可能出现问题的地方,却发现那里没打日志,没法在运行中看到问题,只能加了日志输出重新打包——部署——上线

程序功能正常了,可是为啥响应时间这么慢,在哪里出现了问题?

程序不但稳定运行,而且功能完美,但跑了几天或者几周过后,发现响应速度变慢了,是不是内存泄漏了?

以前,你碰到这些问题,解决的办法大多是,修改代码,重新上线。但是在大公司里,上线的流程是非常繁琐的,如果为了多加一行日志而重新发布版本,无疑是非常折腾人的。

现在,我们有了更为优雅的线上调试方法 – 来自阿里巴巴开源的 Arthas。

下图是 Arthas 文档中对于为什么要使用它的描述,我进行了精简:

Java 线上问题排查工具 Arthas 原理以及用法是什么

线上 Debug 神器 ArthasArthas 使用实例

命令的详细文档请参考:
alibaba.github.io/arthas/comm…

快速启动

快速启动它,你只需要两行命令:

wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar

Java 线上问题排查工具 Arthas 原理以及用法是什么

随后,在界面出现的进程中,选择你的程序序号,比如 1

Java 线上问题排查工具 Arthas 原理以及用法是什么

这样你就进入了 arthas 的控制台。

基本使用

Arthas 有如下功能:

Java 线上问题排查工具 Arthas 原理以及用法是什么

1. 首先是我认为的“上帝视角”指令:Dashboard

当前系统的实时数据面板,按 ctrl+c 退出;
当运行在 Ali-tomcat 时,会显示当前 tomcat 的实时信息,如 HTTP 请求的 qps, rt, 错误数, 线程池信息等等。

通过这些,你可以对于整个程序进程有个直观的数据监控。

Java 线上问题排查工具 Arthas 原理以及用法是什么
Java 线上问题排查工具 Arthas 原理以及用法是什么

2. 类加载问题相关指令

Java 线上问题排查工具 Arthas 原理以及用法是什么

SC:查看 JVM 已加载的类信息

通过 SC 我们可以看到我们这个类的详细信息,包括是从哪个 jar 包读取的,他是不是接口 / 枚举类等,甚至包括他是从哪个类加载器加载的。

Java 线上问题排查工具 Arthas 原理以及用法是什么

上图中代码:

[arthas@37]$ sc -d *MathGame
 class-info demo.MathGame
 code-source /home/scrapbook/tutorial/arthas-demo.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@70dea4e
 +-sun.misc.Launcher$ExtClassLoader@69260973
 classLoaderHash 70dea4e

SC 也可以查看已加载的类,帮助你看是否有没有纳入进来的类,尤其是在 Spring 中,可以判断的你的依赖有没有正确的进来。

Java 线上问题排查工具 Arthas 原理以及用法是什么

上图中代码:

#  查看 JVM 已加载的类信息
[arthas@37]$ sc javax.servlet.Filter
com.example.demo.arthas.AdminFilterConfig$AdminFilter
javax.servlet.Filter
org.apache.tomcat.websocket.server.WsFilter
org.springframework.boot.web.filter.OrderedCharacterEncodingFilter
org.springframework.boot.web.filter.OrderedHiddenHttpMethodFilter
org.springframework.boot.web.filter.OrderedHttpPutFormContentFilter
org.springframework.boot.web.filter.OrderedRequestContextFilter
org.springframework.web.filter.CharacterEncodingFilter
org.springframework.web.filter.GenericFilterBean
org.springframework.web.filter.HiddenHttpMethodFilter
org.springframework.web.filter.HttpPutFormContentFilter
org.springframework.web.filter.OncePerRequestFilter
org.springframework.web.filter.RequestContextFilter
org.springframework.web.servlet.resource.ResourceUrlEncodingFilter
Affect(row-cnt:14) cost in 11 ms.
#  查看已加载类的方法信息
[arthas@37]$ sm java.math.RoundingMode
java.math.RoundingMode  init (Ljava/lang/String;II)V
java.math.RoundingMode values()[Ljava/math/RoundingMode;
java.math.RoundingMode valueOf(I)Ljava/math/RoundingMode;
java.math.RoundingMode valueOf(Ljava/lang/String;)Ljava/math/RoundingMode;
Affect(row-cnt:4) cost in 6 ms.

jad:反编译某个类,或者反编译某个类的某个方法。

Java 线上问题排查工具 Arthas 原理以及用法是什么

上图中代码:

#  反编译只显示源码
jad --source-only com.Arthas
#  反编译某个类的某个方法
jad --source-only com.Arthas mysql
[arthas@37]$ jad demo.MathGame
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@70dea4e
 +-sun.misc.Launcher$ExtClassLoader@69260973
Location:
/home/scrapbook/tutorial/arthas-demo.jar
 * Decompiled with CFR.
 */
package demo;
import java.io.PrintStream;
import java.util.ArrayList;
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 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;
 }
 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 +  = 
 for (int factor : primeFactors) { sb.append(factor).append( * 
 }
 if (sb.charAt(sb.length() - 1) ==  * ) { sb.deleteCharAt(sb.length() - 1);
 }
 System.out.println(sb);
 }
Affect(row-cnt:1) cost in 760 ms.

3. 方法运行相关指令

Java 线上问题排查工具 Arthas 原理以及用法是什么

watch:方法执行的数据观测

你可以通过 watch 指令,来监控某个类,监控后,运行下你的功能,复现下场景,arthas 会提供给你具体的出参和入参,帮助你排查故障。

Java 线上问题排查工具 Arthas 原理以及用法是什么

trace:输出方法调用路径,并输出耗时

这个指令对于优化代码非常的有用,可以看出具体每个方法执行的时间,如果是 for 循环等重复语句,还能看出 n 次循环中的最大耗时,最小耗时,和平均耗时,完美!

Java 线上问题排查工具 Arthas 原理以及用法是什么

tt:官方名为时空隧道

这是我调试用的最多的指令,在你对某方法开启 tt 后,会记录下每一次的调用(你需要设置最大监控次数),然后你可以在任何时候会看这里面的调用,包括出参,入参,运行耗时,是否异常等。非常强大。

Java 线上问题排查工具 Arthas 原理以及用法是什么

4. 线程调试相关指令

Java 线上问题排查工具 Arthas 原理以及用法是什么

thread 相关命令:

Java 线上问题排查工具 Arthas 原理以及用法是什么

thread -n:排列出 CPU 使用率 Top N 的线程。

Java 线上问题排查工具 Arthas 原理以及用法是什么

thread -b:排查阻塞的线程

我们代码有时候设计的不好,会引发死锁的问题,卡住整个线程执行,使用这个指令可以轻松的找到问题线程,以及问题的执行语句。

Java 线上问题排查工具 Arthas 原理以及用法是什么
Java 线上问题排查工具 Arthas 原理以及用法是什么

5. 强大的 ognl 表达式

众所周知,一般来说,表达式都是调试工具里最强的指令,哈哈。

Java 线上问题排查工具 Arthas 原理以及用法是什么

在 Arthas 中你可以利用 ognl 表达式语言做很多事,比如执行某个方法,获取某个信息,甚至进行修改。

Java 线上问题排查工具 Arthas 原理以及用法是什么

[arthas@19856]$ ognl  @com.Arthas@hashSet 
@HashSet[ @String[count1],
 @String[count2],
 @String[count29],
 @String[count28],
 @String[count0],
 @String[count27],
 @String[count5],
 @String[count26],
 @String[count6],
 @String[count25],
 @String[count3],
 @String[count24],
[arthas@19856]$ ognl  @com.Arthas@hashSet.add(test) 
@Boolean[true]
[arthas@19856]$
#  查看添加的字符
[arthas@19856]$ ognl  @com.Arthas@hashSet  | grep test
 @String[test],
[arthas@19856]$

甚至你可以动态更换日志输出级别。

Java 线上问题排查工具 Arthas 原理以及用法是什么

$ ognl  @com.lz.test@LOGGER.logger.privateConfig 
@PrivateConfig[ loggerConfig=@LoggerConfig[root],
 loggerConfigLevel=@Level[INFO],
 intLevel=@Integer[400],
$ ognl  @com.lz.test@LOGGER.logger.setLevel(@org.apache.logging.log4j.Level@ERROR) 
$ ognl  @com.lz.test@LOGGER.logger.privateConfig 
@PrivateConfig[ loggerConfig=@LoggerConfig[root],
 loggerConfigLevel=@Level[ERROR],
 intLevel=@Integer[200],
]

使用 Arthas 解决具体问题 1. 响应时间异常问题

工作中遇到一个优化问题,系统中一个导出表格的功能,响应时间长达 2 分钟,虽然给内部使用,但也不能这么夸张,用 trace 跟踪下方法,发现是其中的手机号加解密函数占用了非常大的时间,几千个手机号,进行了解密后加密的精彩操作,最终导致了两分钟的返回时间。

Java 线上问题排查工具 Arthas 原理以及用法是什么

2. 某功能 Bug 导致服务器返回 500

首先通过 trace 看异常报错的方法,之后通过 tt 排查方法,发现入参进来后,居然走错了方法(因为多态),走到了返回 null 的方法中,所以导致了 NPE 空指针错误。

Java 线上问题排查工具 Arthas 原理以及用法是什么
Java 线上问题排查工具 Arthas 原理以及用法是什么

补充

Arthas 还支持 Web Console,详见:
alibaba.github.io/arthas/web-…

Java 线上问题排查工具 Arthas 原理以及用法是什么

相似工具

BTrace 一是个历史比较久的工具,观察下来 Arthas 其实和它的理念蛮相似的,相信 Arthas 也参考过 Btrace,作为一个学习样例来开发 Arthas。详细的优劣势看图:

Java 线上问题排查工具 Arthas 原理以及用法是什么

其他的相似工具,还有 jvm-sandbox,有兴趣的朋友可以去看看。

原理浅谈

分为三个部分:

启动

arthas 服务端代码分析

arthas 客户端代码分析

Java 线上问题排查工具 Arthas 原理以及用法是什么

启动

使用了阿里开源的组件 cli, 对参数进行了解析:com.taobao.arthas.boot.Bootstrap

Java 线上问题排查工具 Arthas 原理以及用法是什么

在传入参数中没有 pid, 则会调用本地 jps 命令, 列出 java 进程。

Java 线上问题排查工具 Arthas 原理以及用法是什么

进入主逻辑, 会在用户目录下建立 .arthas 目录, 同时下载 arthas-core 和 arthas-agent 等 lib 文件, 最后启动客户端和服务端。

通过反射的方式来启动字符客户端。

Java 线上问题排查工具 Arthas 原理以及用法是什么

服务端——前置准备

看服务端启动命令可以知道 从 arthas-core.jar 开始启动,arthas-core 的 pom.xml 文件里面指定了 mainClass 为 com.taobao.arthas.core.Arthas,使得程序启动的时候从该类的 main 方法开始运行。

Java 线上问题排查工具 Arthas 原理以及用法是什么

首先解析入参,生成 com.taobao.arthas.core.config.Configure 类,包含了相关配置信息;

使用 jdk-tools 里面的 VirtualMachine.loadAgent,其中第一个参数为 agent 路径,第二个参数向 jar 包中的 agentmain() 方法传递参数(此处为 agent-core.jar 包路径和 config 序列化之后的字符串),加载 arthas-agent.jar 包;

运行 arthas-agent.jar 包,指定了 Agent-Class 为 com.taobao.arthas.agent.AgentBootstrap。

Java 线上问题排查工具 Arthas 原理以及用法是什么

上图中代码:

public class Arthas { private Arthas(String[] args) throws Exception { attachAgent(parse(args));
 }
 private Configure parse(String[] args) {
 //  省略非关键代码,解析启动参数作为配置,并填充到 configure 对象里面
 return configure;
 }
 private void attachAgent(Configure configure) throws Exception {
 //  省略非关键代码,attach 到目标进程
 virtualMachine = VirtualMachine.attach( + configure.getJavaPid());
 virtualMachine.loadAgent(configure.getArthasAgent(),
 configure.getArthasCore() +   + configure.toString());
 }
 public static void main(String[] args) { new Arthas(args);
 }
}

Java 线上问题排查工具 Arthas 原理以及用法是什么

服务端——监听客户端请求

如果是 exit,logout,quit,jobs,fg,bg,kill 等直接执行;

如果是其他的命令,则创建 Job,并运行;

创建 Job 时,会根据具体客户端传递的命令,找到对应的 Command,并包装成 Process, Process 再被包装成 Job;

运行 Job 时,反向先调用 Process,再找到对应的 Command,最终调用 Command 的 process 处理请求。

服务端——Command 处理流程

不需要使用字节码增强的命令

其中 JVM 相关的使用 java.lang.management 提供的管理接口,来查看具体的运行时数据。比较简单,就不介绍了。

需要使用字节码增强的命令

字节码增加的命令统一继承 EnhancerCommand 类,process 方法里面调用 enhance 方法进行增强。调用 Enhancer 类 enhance 方法,该方法内部调用 inst.addTransformer 方法添加自定义的 ClassFileTransformer,这边是 Enhancer 类。

Enhancer 类使用 AdviceWeaver(继承 ClassVisitor),用来修改类的字节码。重写了 visitMethod 方法,在该方法里面修改类指定的方法。visitMethod 方法里面使用了 AdviceAdapter(继承了 MethodVisitor 类),在 onMethodEnter 方法, onMethodExit 方法中,把 Spy 类对应的方法(ON_BEFORE_METHOD,ON_RETURN_METHOD,ON_THROWS_METHOD 等)编织到目标类的方法对应的位置。

在前面 Spy 初始化的时候可以看到,这几个方法其实指向的是 AdviceWeaver 类的 methodOnBegin,methodOnReturnEnd 等。在这些方法里面都会根据 adviceId 查找对应的 AdviceListener,并调用 AdviceListener 的对应的方法,比如 before,afterReturning, afterThrowing。

客户端

客户端代码在 arthas-client 模块里面,入口类是 com.taobao.arthas.client.TelnetConsole。

主要使用 apache commons-net jar 进行 telnet 连接,关键的代码有下面几步:

构造 TelnetClient 对象,并初始化

构造 ConsoleReader 对象,并初始化

调用 IOUtil.readWrite(telnet.getInputStream(), telnet.getOutputStream(), System.in, consoleReader.getOutput()) 处理各个流,一共有四个流:

telnet.getInputStream()

telnet.getOutputStream()

System.in

consoleReader.getOutput()

请求时:从本地 System.in 读取,发送到 telnet.getOutputStream(),即发送给远程服务端。响应时:从 telnet.getInputStream() 读取远程服务端发送过来的响应,并传递给 consoleReader.getOutput(),即在本地控制台输出。

关于源码,深入下去还有很多东西需要生啃,我也没有消化得很好,大家可以继续阅读详细资料。

总结

Arthas 是一个线上 Debug 神器,小白也可以轻松上手。

一键安装并启动 Arthas

方式一:通过 Cloud Toolkit 实现 Arthas 一键远程诊断

Cloud Toolkit 是阿里云发布的免费本地 IDE 插件,帮助开发者更高效地开发、测试、诊断并部署应用。通过插件,可以将本地应用一键部署到任意服务器,甚至云端(ECS、EDAS、ACK、ACR 和 小程序云等);并且还内置了 Arthas 诊断、Dubbo 工具、Terminal 终端、文件上传、函数计算 和 MySQL 执行器等工具。不仅仅有 IntelliJ IDEA 主流版本,还有 Eclipse、Pycharm、Maven 等其他版本。

推荐使用 IDEA 插件下载 Cloud Toolkit 来使用 Arthas:
http://t.tb.cn/2A5CbHWveOXzI7sFakaCw8

方式二:直接下载

地址:
https://github.com/alibaba/arthas。

关于 Java 线上问题排查工具 Arthas 原理以及用法是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-25发表,共计9143字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)