阿里arthas分享

arthas是阿里开源的Java诊断工具,可以对运行时的java进程进行分析,动态代理运行时的Java进程。artahs支持JDK6+,同时提供丰富的tab自动补全功能,进一步方便进行问题的定位和诊断。

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

arthas基本介绍

        arthas是一个jar包,官方提供了几种方式安装,通常只需要下载jar包,然后java -jar arthas-boot.jar运行该jar包即可。

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

java -jar arthas-boot.jar

基本命令介绍:

dashboard/thread/jvm/sysprop/sysenv

sc/sm

jad/classloader/mc/redefine

monitor/watch/trace/stack

表达式核心变量:

public class Advice {

 

    private final ClassLoader loader;

    private final Class<?> clazz;

    private final ArthasMethod method;

    private final Object target;

    private final Object[] params;

    private final Object returnObj;

    private final Throwable throwExp;

    private final boolean isBefore;

    private final boolean isThrow;

    private final boolean isReturn;

    // getter/setter 

}  

 

arthas原理

        java instrumentation,该机制的最大作用就是类定义动态改变和操作。在java se 5及后续版本中,可以通过java -javaagent参数指定一个特定的jar文件(包含Instrumentation代理)来启动Instrumentation的代理程序。

        se5:编写一个java类,包含如下两个方法中的一个:

public static void premain(String agentArgs, Instrumentation inst);  [1]

public static void premain(String agentArgs); [2]

在这个 premain 函数中,开发者可以进行对类的各种操作。

agentArgs 是 premain 函数得到的程序参数,随同 “–javaagent”一起传入。与 main 函数不同的是,这个参数是一个字符串而不是一个字符串数组,如果程序参数有多个,程序将自行解析这个字符串。

inst 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入。java.lang.instrument.Instrumentation 是 instrument 包中定义的一个接口,也是这个包的核心部分,集中了其中几乎所有的功能方法,例如类定义的转换和操作等等。在se5中,所做的instrumentation仅限于main函数执行前,这样的方式存在一定的局限性。

      se6:虚拟机启动之后的instrument,比se5中又多了两个方法:

public static void agentmain (String agentArgs, Instrumentation inst);          [1]

public static void agentmain (String agentArgs);            [2]

在se6中,开发者可以再main函数开始执行以后,在启动自己的instrumentation程序。

基于Attach API实现,是sun公司提供的一套扩展的API,用来向目标JVM附着(Attach)代理工具程序的。提供一种jvm进程间通信的能力,能让一个进程传命令给另外一个进程,可以理解为一种虚拟机级别的aop实现。

Attach API 有 2 个主要的类,都在 com.sun.tools.attach 包里面: VirtualMachine 代表一个 Java 虚拟机,也就是程序需要监控的目标虚拟机,提供了 JVM 枚举,Attach 动作和 Detach 动作(Attach 动作的相反行为,从 JVM 上面解除一个代理)等等 ; VirtualMachineDescriptor 则是一个描述虚拟机的容器类,配合 VirtualMachine 类完成各种功能。

import java.lang.instrument.ClassDefinition;

import java.lang.instrument.Instrumentation;

import java.lang.instrument.UnmodifiableClassException;

  

public class AgentMain {

   public static void agentmain(String agentArgs, Instrumentation inst)

           throws ClassNotFoundException, UnmodifiableClassException,

           InterruptedException {

       inst.addTransformer(new Transformer (), true);

       inst.retransformClasses(TransClass.class);

       System.out.println("Agent Main Done");

   }

}

 

Transformer类:

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.lang.instrument.ClassFileTransformer;

import java.lang.instrument.IllegalClassFormatException;

import java.security.ProtectionDomain;

  

class Transformer implements ClassFileTransformer {

  

   public static final String classNumberReturns2 = "TransClass.class.2";

  

   public static byte[] getBytesFromFile(String fileName) {

       try {

           // precondition

           File file = new File(fileName);

           InputStream is = new FileInputStream(file);

           long length = file.length();

           byte[] bytes = new byte[(int) length];

  

           // Read in the bytes

           int offset = 0;

           int numRead = 0;

           while (offset <bytes.length

                   && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {

               offset += numRead;

           }

  

           if (offset < bytes.length) {

               throw new IOException("Could not completely read file "

                       + file.getName());

           }

           is.close();

           return bytes;

       catch (Exception e) {

           System.out.println("error occurs in _ClassTransformer!"

                   + e.getClass().getName());

           return null;

       }

   }

  

   public byte[] transform(ClassLoader l, String className, Class<?> c,

           ProtectionDomain pd, byte[] b) throws IllegalClassFormatException {

       if (!className.equals("TransClass")) {

           return null;

       }

       return getBytesFromFile(classNumberReturns2);

  

   }

}


除此之外,se6还提供了本地方法的Instrumentation和 BootClassPath/SystemClassPath的动态增补。

arthas与现有系统集成

启动arthas进程之后,是开放了http端口的,可以直接访问http://localhost:8563

可以把arthas web server部署到一台有超级权限访问其他服务器的机器上。然后用户选了某台机器的ip之后,通过ssh去对应的机器上启动arthas,并获取http端口,通过nginx或java代码转发,然后就可以有统一的界面操作所有的机器。

虚机

1、虚机上下载arthas-boot包

2、登录到对应服务器,基于应用名查找相应的pid

3、如果该端口没有被监听,直接attach该pid之后返回

QAE-jar包

目前没有想到比较好的方法,可以统一集成到现有的系统当中,目前只能是使用的时候从网络上下载,需要开启外网功能,然后启动jar包。

QAE-镜像

1、直接把arthas-boot.jar包copy到基础镜像中,放到/usr/local目录下

2、在qae添加8563端口,然后启动arthas-boot,jar包,从环境变量中获取PORT_8563真实的映射接口,直接跳转到对应页面就可以了

 

 

 

 

 

参考文档

1、Java.lang.instrument使用 https://www.cnblogs.com/wade-luffy/p/6078301.html

2、记录如何使用arthas进行远程访问 https://github.com/alibaba/arthas/issues/442

3、web console功能支持 https://github.com/alibaba/arthas/issues/15

4、arthas 快速入门 https://alibaba.github.io/arthas/quick-start.html

5、Arthas实践--使用redefine排查应用奇怪的日志来源 https://yq.aliyun.com/articles/657215?utm_content=m_1000019894

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值