BTrace原理与使用详解(附示例)

BTrace原理与使用详解(附示例)-mikechen

BTrace简介

BTrace 是一个安全动态的Java追踪工具,通过动态字节码,动态替换的原理以追踪正在运行的Java程序,达到追踪的效果。

BTrace 是检查和解决线上的问题的杀器,BTrace将跟踪操作插入到正在运行的Java程序的类中,并对跟踪的程序类进行热交换。

BTrace的最大好处,是可以通过自己编写的脚本,获取应用的一切调用信息,而不需要不断地修改代码,不用重启服务,写好脚本,直接用命令执行即可,不用动原程序的代码。

 

Btrace能干什么

  1. 分析任意接口或者方法的耗时情况
  2. 分析不断的添加数据时,Map的扩容情况
  3. 分析那个方法里面调用了System.gc()方法,并打印出其调用栈
  4. 某些方法抛出异常时,分析其运行参数
  5. 统计一些接口的调用次数
  6. 分析一些方法的代码是否执行到了某一行

注意上面的所有操作,都是监控正在运行中的程序,基本不会产生任何影响。

 

BTrace实现原理

BTrace是基于动态字节码修改技术(Hotswap)向目标程序的字节码注入追踪代码。

大体的原理可以用下面的公式描述:

Client(Java compile api + attach api) + Agent(脚本解析引擎 + ASM + Instumentation) + Socket

其实 BTrace 就是使用了 java attach api 附加 agent.jar ,然后使用脚本解析引擎+asm来重写指定类的字节码,再使用 instrument 实现对原有类的替换。

 

BTrace工具下载

github的地址为:https://github.com/btraceio/btrace/tree/master

下载地址为:https://github.com/btraceio/btrace/releases

使用文档:https://github.com/btraceio/btrace/wiki#btrace

设置BTRACE_HOME,将bin目录加至环境变量PATH中,配置完成后执行  source .bash_profile, 在终端中输入btrace 可以看到如下内容:

$ btrace
Usage: btrace <options> <pid> <btrace source or .class file> <btrace arguments>
where possible options include:
  --version             Show the version
  -v                    Run in verbose mode
  -o <file>             The path to store the probe output (will disable showing the output in console)
-u                    Run in trusted mode
  -d <path>             Dump the instrumented classes to the specified path
  -pd <path>            The search path for the probe XML descriptors
  -classpath <path>     Specify where to find user class files and annotation processors
  -cp <path>            Specify where to find user class files and annotation processors
  -I <path>             Specify where to find include files
  -p <port>             Specify port to which the btrace agent listens for clients
  -statsd <host[:port]> Specify the statsd server, if any

 

BTrace如何使用

第一步:jps命令查出需要监控的jvm pid

第二步:编写BTrace跟踪程序

第三部:执行:btrace <pid> BTrace跟踪程序

 

BTrace使用示例

使用起来比较简单,只需要执行btrace {javaPid} {btrace脚本}就行,如果要把输出调试信息到控制台,要加上-v 参数,-o 参数可以把结果输出到文件中。

package com.metty.rpc.common;
import java.util.Random;
 
public class BtraceCase {
  public static Random random = new Random();
  public int size;
 
  public static void main(String[] args) throws Exception {
    new BtraceCase().run();
  }
   
  public void run() throws Exception {
    while (true) {
      add(random.nextInt(10), random.nextInt(10));
    }
  }
 
  public int add(int a, int b) throws Exception {
    Thread.sleep(random.nextInt(10) * 100);
    return a + b;
  }
}

执行add方法时,对传入参数、返回值以及执行耗时进行分析,btrace脚本:

BTrace原理与使用详解(附示例)-mikechen

通过jps命令获取pid为8454

执行btrace 8454 Debug.java实现对运行代码的监控,输出结果如下:

BTrace原理与使用详解(附示例)-mikechen

可以发现,Btrace可以获取每次执行add方法时的数据,当然Btrace能做的远远不止这些,比如获取当前jvm堆使用情况、当前线程的执行栈等等。

 

BTrace注意事项

Btrace脚本就是一个普通的用@Btrace注解的Java类,其中包含一个或多个public static void修饰的方法,注意拦截方法必须是用public static void 进行修饰的,如果不是静态方法则会抛出 instance methods are not allowed 这样的异常信息 如果不是public 则会提示btrace methods should be public ;如果有返回则提示信息为:btrace probe methods must return void

为了保证对目标程序不造成影响,Btrace脚本对其可以执行的动作做了很多限制,如下:

  • 不能创建对象
  • 不能抛出或者捕获异常
  • 不能用synchronized关键字
  • 不能对目标程序中的instace或者static变量
  • 不能调用目标程序的instance或者static方法
  • 脚本的field、method都必须是static的
  • 脚本不能包括outer,inner,nested class
  • 脚本中不能有循环,不能继承任何类,任何接口与assert语句

作者简介

陈睿|mikechen,10年+大厂架构经验,BAT资深面试官,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

👇阅读更多mikechen架构文章👇

阿里架构 |双11秒杀 |分布式架构 |负载均衡 |单点登录 |微服务 |云原生 |高并发 |架构师

以上

关注作者「mikechen」公众号,获取更多技术干货!

后台回复架构,即可获取《阿里架构师进阶专题全部合集》,后台回复面试即可获取《史上最全阿里Java面试题总结

评论交流
    说说你的看法