1.1 下载BTrace
下载地址:目前需要JDK7+,最新版本为1.3.8.3
download
设置环境变量:BTRACE_HOME
1.2 编写BTrace脚本HelloWorld.java
importcom.sun.btrace.annotations.*;
importstaticcom.sun.btrace.BTraceUtils.*;
@BTrace
publicclassHelloWorld {
@OnMethod(clazz="java.lang.Thread", method="start")
publicstaticvoidonThreadStart() {
println("thread start!");
}
1.3 运行
虽然btrace可以实时编译Java源文件,但如果你的脚本是要给运维同学执行的,线上运行时才发现写错了就尴尬了,可以预编译脚本:btracec HelloWorld.java
,保证代码正确,这样也避免运行时的编译异常。
1.3.1 直接运行
btrace $pid HelloWorld.java
1.3.2 输出到指定文件运行
btrace -o btrace.log $pid HelloWorld.java
当然如果想跟踪SOFALite应用的启动过程的话,可以将下载的压缩包中
btrace-agent.jar
以-javaagent
方式启动起来。例如,
javaagent的设置方式
:
-javaagent:/home/admin/ccbin/lif_btrace/build/btrace-agent.jar=script=/home/admin/ccbin/lif_btrace/build/TrackDTDXSDLoad.class,scriptOutputFile=/home/admin/logs/lif_btrace.log
1.3.3 定义classpath
如果在HelloWorld.java里使用了JDK外的其他类,比如Netty的:
./btrace -cp .:netty-all-4.0.41.Final.jar $pid HelloWorld.java
但上面定义的classpath只在编译脚本时使用,而脚本里需要显式使用非JDK类的机会其实很少,而在运行时,因为已经绑到目标应用的JVM里,用的是目标JVM的classpath。
1.4 拦截方法定义
1.4.1 正则表达式定位
注意:所有样例工程在这里
@com.sun.btrace.annotations.OnMethod用来指定trace的目标类和方法以及具体位置,被注解的方法在匹配的方法执行到指定的位置会被调用。"clazz"属性用来指定目标类名,可以指定全限定类名,比如"java.awt.Component",也可以是正则表达式(表达式必须写在"/ /"中,比如"/java\.awt\..+/")。"method"属性用来指定被trace的方法。表达式可以参考自带的例子(NewComponent.java和Classload.java,关于方法的注解可以参考MultiClass.java)。有时候被trace的类和方法可能也使用了注解。用法参考自带例子WebServiceTracker.java。针对注解也是可以使用正则表达式,比如像这个"@/com\.acme\..+/ ",也可以通过指定超类来匹配多个类,比如"+java.lang.Runnable"可以匹配所有实现了java.lang.Runnable接口的类。具体参考自带例子SubtypeTracer.java。
- 示例:
//下例打印所有用时超过300毫秒的方法调用
@OnMethod(clazz ="/com\\.alipay\\..+/", method ="/.+/", location = @Location(Kind.RETURN))
publicstaticvoidonDoFilter2(@ProbeClassName String pcn,@Durationlongduration) {
longcost = duration/(1000000*100);
if(cost >3) {
print(strcat(strcat(strcat(strcat(name(probeClass()),"."), probeMethod()),":"), str(probeLine())));
print("[");
print(strcat("Time cost (*100ms): ", str(cost)));
println("]");
}
}
1.5 初步结论
* 备注:第一个数字代码代码的行数,第二个代码的耗时,单位100ms
XXX.getIpMap:39[Time cost (*100ms):50]
- 分析堆栈得知,业务测试代码中获取IP和域名等非常耗时(涉及文件IO);经过再一次调整打印规则,再次触发RPC调用,发现首次调用时,非常耗时,通过分析BTrace日志得知,另一个方法热点。
*备注:第一个数字代码代码的行数,第二个代码的耗时,单位100ms
XXX.getPID:192[Time cost (*100ms):50]
1.6 BTrace + JAVA VisualVM**
为了获得更好的展示体验,我们可以利用BTrace + JAVA VisualVM来分析应用中的热点耗时方法,做性能优化,具体如下:
1.6.1打开Java VisualVM并安装BTtrace Workbench
在控制台输入jvisualvm
即可打开,然后安装BTrace
1.6.2指定分析的进程
- 在Java VisualVM中选中想要监控的进程,右击选中
Trace application
1.6.3编写脚本,启动BTrace
1.6.4 运行程序,其中的耗时热点将会打印出来
1.7 展望
有了一次调用的耗时热点分析,可以举一反三,进行压测将所有耗时较高的点打印出来,并通过脚本解析的方式,就可以知道一次压测中所有耗时的热点了,并据此进行应用的性能优化😀。
备注:使用阿里的Greys Java在线问题诊断工具也是非常不错的选择,使用上会更简单些。 github代码