背景
我们在日常运维过程中可能会经常遇到一些问题,而排查这些问题时又需要获取应用runtime的数据信息,比如方法参数、变量信息等。为了排查问题,我们可能会选择打印tracelog,经过一次发布然后获取信息,但这种方式用起来麻烦不说,还有可能破坏运行环境,导致问题无法复现。那么我们借助于BTrace将可以减少这方面的困扰(ps.正常来说,你还是应该做好应用中的trace log,不能全依赖这个手段).
介绍
BTrace是一个可以为java提供安全可靠动态跟踪分析功能的工具,它基于动态字节码修改技术(hotswap)实现java程序runtime的跟踪和替换(运用的aop思想),而且操作不会对原有的java进程产生影响(性能影响可以忽略不计),也不会修改进程中的执行逻辑和runtime数据。我们可以在不重新部署应用的情况下进行问题查找和分析。 BTrace的脚本就是一个普通的Java程序,不过是需要借助于官方提供的一组annotation,这些annotation是用来指定trace程序的探测点位置,使用起来非常简单方便(如果你熟悉SpringAOP那用起来更顺手了,因为就是AOP的思想嘛)。下面介绍下这个工具的使用方式和一些注意的地方,最后再看下它的实现原理。
使用
你可以直接参考官方的使用指南: http://kenai.com/projects/btrace/pages/UserGuide,介绍的非常全面。下面我介绍下使用btrace需要了解的几个概念
- Probe Point
探测点,指要执行trace的地方(比如哪个方法的哪一行)或者触发的事件,btrace脚本中通过注解指定
- Trace Actions or Actions
指我们定义的trace语句,这些语句在探测点被触发时执行
- Action Methods
这是指btrace脚本里面的静态方法,在探测点被触发时被调用,上面定义的trace语句就在这里面。一般这么定义:
public static void xxx
1.2 版本之后也可以是非静态方法
使用步骤:
- 下载btrace工具包,地址:http://kenai.com/projects/btrace/downloads (taobao的各个环境已经安装,具体可以看下web容器的启动脚本)
- 在环境上解压btrace工具包,比如解压到 /opt/tools/btrace/ 目录下
- 编写btrace脚本(工具包的samples文件夹下有很多官方的例子),下面接着会会介绍脚本的写法
- 通过命令行执行脚本
a) 获取java进程pid (可以使用jps获取)
b) 执行命令行 btrace [pid] [btrace脚本] ,更全的命令:btrace -cp[btrace的jar所在的路径,默认在btrace/build] [vm pid] [btrace脚本]
编写脚本
1. 参考官方的例子,多练
2. 熟悉BTraceUtils的使用API http://btrace.kenai.com/javadoc/1.1/com/sun/btrace/BTraceUtils.html
注意
首先,不当的使用btrace可能导致jvm崩溃的事故,因此在生产环境中使用应该慎之再慎。其次,btrace只能对runtime的数据进行读,不能写。因此,我们的btrace脚本会有一些限制约束。下面是官方的限制列表
- 不能创建对象、数组;
- 不能抛出、捕获异常;
- 不能有外部类、内部类、匿名类、本地类;
- 不能有同步块或者同步方法;
- 不能有循环;
- 不能实现接口、不能扩展类(超类必须是Object);
- 不能有断言;
- 不能使用class字面量;
- 不能调用实例方法和静态方法,只能调用com.sun.btrace.BTraceUtils提供的方法和在BTrace脚本中定义的方法;
原理
Btrace的实现是依靠 attach API、btrace脚本解析引擎、asm、JDK6的instrumentation组合完成的。
1. Sun attach API负责动态加载agent
2. Btrace解析引擎负责解析我们编写的btrace脚本
3. asm负责字节码增强修改
4. instrumentation负责字节码的内存替换
instumentation的强大之处可以自行google,介绍也可以参考下面的文章
http://www.ibm.com/developerworks/cn/java/j-lo-jse61/index.html
参考资料:
http://kenai.com/projects/btrace/pages/UserGuide
http://www.ibm.com/developerworks/cn/java/j-lo-jse61/index.html