Java线上问题排查神器Arthas快速上手与原理浅谈

前言

当你兴冲冲地开始运行本身的Java项目时,你是否遇到过以下问题:java

  • 程序在稳定运行了,但是实现的功能点了没反应。
  • 为了修复Bug而上线的新版本,上线后发现Bug依然在,却想不通哪里有问题?
  • 想到可能出现问题的地方,却发现那里没打日志,无法在运行中看到问题,只能加了日志输出从新打包——部署——上线
  • 程序功能正常了,但是为啥响应时间这么慢,在哪里出现了问题?
  • 程序不但稳定运行,并且功能完美,但跑了几天或者几周事后,发现响应速度变慢了,是否是内存泄漏了?

之前,你碰到这些问题,解决的办法大可能是,修改代码,从新上线。可是在大公司里,上线的流程是很是繁琐的,若是为了多加一行日志而从新发布版本,无疑是很是折腾人的。mysql

如今,咱们有了更为优雅的线上调试方法,来自阿里巴巴开源的Arthasgit

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

Java线上问题排查神器Arthas快速上手与原理浅谈

好了,前言已经超过字数了,哈哈,在本篇文章里,你可以了解:
  • Arthas使用实例:帮助你快速让你上手,拯救你的低效率Debug
  • 使用Arthas解决具体问题:看一下Arthas帮我拯救了多少时间
  • 类似工具:看看线上Debug还有没有别的工具可使用
  • 原理浅谈:莫在浮沙筑高阁!你须要大概了解下Arthas的原理

相信我,Arhas以为是你提高效率的利器,适合各类阶段的开发者,尤为适合我这种刚入门的新人(每天上班写Bug的人)。你不该该有这种东西是高阶程序员才应该去使用的思想,放心大胆的去用吧!程序员

线上Debug神器Arthas

Arthas使用实例github

命令的详细文档请参考:

alibaba.github.io/arthas/comm…web

快速启动面试

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

Java线上问题排查神器Arthas快速上手与原理浅谈

Java线上问题排查神器Arthas快速上手与原理浅谈

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

Java线上问题排查神器Arthas快速上手与原理浅谈

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

基本使用

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快速上手与原理浅谈

上图中代码:

Java线上问题排查神器Arthas快速上手与原理浅谈

SC也能够查看已加载的类,帮助你看是否有没有归入进来的类,尤为是在Spring中,能够判断的你的依赖有没有正确的进来。

Java线上问题排查神器Arthas快速上手与原理浅谈

上图中代码:

Java线上问题排查神器Arthas快速上手与原理浅谈

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快速上手与原理浅谈

  1. 强大的ognl表达式

众所周知,通常来讲,表达式都是调试工具里最强的指令,哈哈。

Java线上问题排查神器Arthas快速上手与原理浅谈

在Arthas中你能够利用ognl表达式语言作不少事,好比执行某个方法,获取某个信息,甚至进行修改。

Java线上问题排查神器Arthas快速上手与原理浅谈

Java线上问题排查神器Arthas快速上手与原理浅谈

甚至你能够动态更换日志输出级别

Java线上问题排查神器Arthas快速上手与原理浅谈

Java线上问题排查神器Arthas快速上手与原理浅谈

使用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快速上手与原理浅谈

上图中代码:

Java线上问题排查神器Arthas快速上手与原理浅谈

Java线上问题排查神器Arthas快速上手与原理浅谈

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

  • 若是是exit,logout,quit,jobs,fg,bg,kill等直接执行。
  • 若是是其余的命令,则建立Job,并运行。
  • 建立Job时,会根据具体客户端传递的命令,找到对应的Command,并包装成Process, Process再被包装成Job。
  • 运行Job时,反向先调用Process,再找到对应的Command,最终调用Command的process处理请求。

服务端——Command处理流程

  1. 不须要使用字节码加强的命令
其中JVM相关的使用 java.lang.management 提供的管理接口,来查看具体的运行时数据。比较简单,就不介绍了。
  1. 须要使用字节码加强的命令
字节码增长的命令统一继承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链接,关键的代码有下面几步:

  1. 构造TelnetClient对象,并初始化
  2. 构造ConsoleReader对象,并初始化
  3. 调用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神器,小白也能够轻松上手。

码字不易,但愿你们捧我的场,谢谢诸位。

关注我,私信回复“资料”或者查看我主页介绍便可获取面试宝典《Java核心知识点整理.pdf》还有Java208道面试题(含答案)的免费领取方式!

相关文章
相关标签/搜索