对于 SkyWalking
、Zipkin
、Arthas
来说都是无侵入式的组件,你是否有思考过其底层是如何实现?今天让我们了解下 动态追踪技术的底层分析
动态追踪技术是一个可以不用重启线上java项目来进行问题排查的技术,比如前面讲的 Arthas
就属于一种动态追踪的工具。Arthas里面提供的monitor还有watch等命令就是动态的追踪技术。
当然我们学技术要知其然还要知其所以然,Arthas工具的基础,就是 Java Agent 技术,可以利用它来构建一个附加的代理程序,用来协助检测性能,还可以替换一些现有功能,甚至 JDK 的一些类我们也能修改,有点像 JVM 级别的 AOP 功能。
既然作为JVM的AOP,就必须要有AOP的功能,所以Java Agent提供了两个类似于AOP的方法:
但在一个JVM 中,只会调用一个
javaagent-demo
打包生成agent包,然后放入英文目录下
运行另外 一个项目,然后在VM参数加入jar的配置。
看到修改后的效果。
具体javaagent-demo
这种模式一般用在一些诊断工具上(arthas之类的)。使用jdk/lib/tools.jar 中的工具类中的Attach API,可以动态的为运行中的程序加入一些功能。它的主要运行步骤如下:
Attach API 不是 Java 的标准 API,而是 Sun 公司提供的一套扩展 API,用来向目标 JVM ”附着”(Attach)代理工具程序的。有了它,开发者可以方便的监控一个 JVM,运行一个外加的代理程序。Attach API只有 2 个主要的类,都在 com.sun.tools.attach 包(在jdk的lib目录下tools.jar里面)里面:
VirtualMachine 代表一个 Java 虚拟机,也就是程序需要监控的目标虚拟机,提供了 JVM 枚举,Attach 动作和 Detach 动作(Attach 动作的相反行为,从 JVM 上面解除一个代理)等等 ;
VirtualMachineDescriptor 则是一个描述虚拟机的容器类,配合 VirtualMachine 类完成各种功能。
Java Attach API是一个API接口,JDK提供的,它可以将应用程序连接到另一个目标虚拟机。然后,您的应用程序可以将代理应用程序装入目标虚拟机,例如,用于执行监视状态之类的任务。
JVM Attach API功能上非常简单,主要功能如下
下面的代码的主要功能是:
BTrace是基于Java语言的一个安全的、可提供动态追踪服务的工具。
BTrace基于ASM、Java Attach API、Instrument开发,为用户提供了很多注解。依靠这些注解,我们可以编写BTrace脚本(简单的Java代码)达到我们想要的效果,而不必深陷于ASM对字节码的操作中不可自拔。
BTrace和Arthas都是用于Java应用程序的动态监控和调试工具,但它们的设计目标和实现方式有所不同:
总之,BTrace和Arthas都是强大的Java工具,开发者可以根据具体需求选择使用其中一个或两个工具来帮助调试和监控Java应用程序。
首先要下载btrace的压缩包,并解压,
配置环境变量
path变量新增
打开CMD命令行,输入btrace出现帮助及配置成功
1、准备一个springboot的工程,写一个controller。
2、写几个动态追踪框架的类(一般是单独的项目,这里简化放一起)
项目中引入需要引入几个jar包的依赖
效果
详细语法见官方:https://github.com/btraceio/btrace/blob/master/docs/BTraceTutorial.md
下面是我总结的一些核心的
BTrace注解可以分为:
类注解 @BTrace
方法注解如 @OnMethod
参数注解如 @ProbeClassName
@ProbeClassName 用于标记处理方法的参数,仅用户@OnMethod, 该参数的值就是被跟踪的类名称
@ProbeMethodName 用于表姐处理方法的参数,仅用户 @OnMethod,该参数值是被跟踪方法名称
@Self 当前截取方法的封闭实例参数
@Return 当前截取方法的的返回值, 只对 location=@Location(Kind.RETURN) 生效
@Duration 当前截取方法的执行时间
@TargetInstance 当前截取方法内部调用的实例
@TargetMethodOrField 当前截取方法内部被调用的方法名
@OnMethod - 用于指定跟踪方法到目标类,目标方法和目标位置
@Kind注解
Kind.ENTRY-被trace方法参数
Kind.RETURN-被trace方法返回值
Kind.THROW -抛异常
Kind.ARRAY_SET, Kind.ARRAY_GET -数组索引
Kind.CATCH -捕获异常
Kind.FIELD_SET -属性值
Kind.LINE -行号
Kind.NEW -类名
Kind.ERROR -抛异常
@OnTimer - 用于指定跟踪操作定时执行。value用于指定时间间隔
@OnError - 当trace代码抛异常或者错误时,该注解的方法会被执行.如果同一个trace脚本中其他方法抛异常,该注解方法也会被执行。
BTrace最终借Instrument实现class的替换。出于安全考虑,Instrument在使用上存在诸多的限制,这就好比给一架正在飞行的飞机换发动机一样一样的,因此BTrace脚本的限制如下:
不允许随意调用其他对象或者类的方法,只允许调用com.sun.btrace.BTraceUtils中提供的静态方法(一些数据处理和信息输出工具)
不允许改变类的属性
不允许有成员变量和方法,只允许存在static public void方法
不允许有内部类、嵌套类
不允许有同步方法和同步块
不允许有循环
不允许随意继承其他类(当然,java.lang.Object除外)
不允许实现接口
不允许使用assert
不允许使用Class对象
如此多的限制,其实可以理解。BTrace要做的是,虽然修改了字节码,但是除了输出需要的信息外,对整个程序的正常运行并没有影响。
其实作为Java的动态追踪技术,站在比较底层的角度上来说,底层无非就是基于ASM、Java Attach API、Instrument开发的创建。Arthas都是针前面这些技术的一个封装而已。
Btrace功能虽然强大,但都是比较难入门,这就是为什么 Btrace 出来这么多年,还是只在小范围内被使用。相对来说,Arthas 显的友好而且安全的多。
但无论工具如何强大,一些基础知识是需要牢固掌握的,否则,工具中出现的那些术语,也会让人一头雾水。
工具常变,但基础更加重要。如果你想要一个适应性更强的技术栈,还是要多花点时间在原始的排查方法上。
本文作者:柳始恭
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!