searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Jvm-Sandbox原理解析

2024-06-24 09:35:38
112
0

1、框架简介

JVM SandBox 是一款 JVM 平台非侵入式运行期 AOP 解决方案,本质上是一种 AOP 落地形式。JVM SandBox可以动态增强指定的类,获取想要的参数和行信息甚至改变方法的执行,常应用于线上问题排查、动态日志打印、监控数据采集以及流量录制和回放等场景。

2、原理分析

JVM SandBox具备无侵入、类隔离、多租户和可拔插等特点。

无侵入:目标应用无需重启也无需感知沙箱的存在。

类隔离:沙箱以及沙箱的模块不会和目标应用的类相互干扰。

多租户:目标应用可以同时挂载不同租户下的沙箱并独立控制。

可拔插:沙箱以及沙箱的模块可以随时加载和卸载,不会在目标应用留下痕迹。

JVM SandBox由多个模块构成,每个模块负责不同的能力,模块的构成如下图所示:

其中模块控制管理主要负责管理 sandbox 自身模块以及使用者自定义模块,例如模块的加载,激活,冻结,卸载。事件监听处理模块负责用户自定义模块实现 Event 接口对增强的事件进行自定义处理,等待事件分发处理器的触发。事件分发处理器理主要负责对目标方法增强后会对目标方法追加三个环节,分别为BEFORE AFTER THROWS。代码编织框架主要负责通过 ASM 框架依托于 JVMTI 对目标方法进行字节码修改,从而完成代码增强的能力。检索过滤器主要负责当用户对目标方法创建增强事件时,沙箱会对目标 jvm 中的目标类和方法进行匹配以及过滤,匹配到用户设定目标类和方法进行增强,过滤掉 sandbox 内部的类以及 jvm 认为不可修改的类。加载类检索主要负责获取到需要增强的类集合依赖检索过滤器模块

从功能上划分,JVM SandBox主要提供字节码增强和类加载隔离两个主要的功能。下面详细介绍字节码增强和类加载隔离的原理。

字节码增强

要了解字节码增强机制,首先要了解Instrumentation的发展历程,在jdk早期版本,为了官方提供了JVMPI/JVMDI机制,JVMPI监控就JVM发生的各种事件,比如,JVM创建、关闭、Java类被加载、创建对象或GC回收等37种事件。JVMDI提供了一批JVM调试接口。JDK 1.5及之后的版本将JVMPI和JVMDI合二为一,形成了一套JVM语义——JVMTI。JVMTI旨在为需要访问VM状态的所有工具提供VM接口,包括但不限于:评测、调试、监视、线程分析和覆盖率分析工具。

JVMTI 本质上是在JVM内部的许多事件进行了埋点。通过这些埋点可以给外部提供当前上下文的一些信息。甚至可以接受外部的命令来改变下一步的动作。外部程序一般利用C/C++实现一个JVMTIAgent,在Agent里面注册一些JVM事件的回调。当事件发生时JVMTI调用这些回调方法。Agent可以在回调方法里面实现自己的逻辑。

基于JVMTI 机制,Java官方提供了Instrumentation机制,Instrumentation接口底层依赖JVMTI语义的Native API,用户可通过实现Instrumentation接口完成对JVM操作。

使用 Instrumentation,可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。这样的特性实际上提供了一种虚拟机级别支持的 AOP 实现方式,使得开发者无需对 JDK 做任何升级和改动,就可以实现某些 AOP(AOP核心理念是定义切入点(pointcut)以及通知(advice)。程序控制流中所有匹配该切入点的连接点(joinpoint)都将执行这段通知代码)的功能了。

在使用Instrumentation进行字节码修改时,需要自定义一个ClassFileTransformer类,在JVM加载class时,会先调用ClassFileTransformer的transform方法,加载class的流程如下图所示:

在做字节码增强时,除了要在加载class时获取到字节码数组,还需要对字节码数组进程操作,写入需要织入的代码,此时需要用到如ASM的字节码操作工具。

ASM 是一个通用的 Java 字节码操作和分析框架。它能够以二进制形式修改已有的类或是动态生成类。修改class的流程如下:

其中ClassReader主要负责读取字节码文件,然后把读取的数据通知 ClassVisitor。ClassVisitor用于生成和转换编译类的 ASM API 基于 ClassVisitor 抽象类,接收 ClassReader 发出的对 method 的访问请求,并且替换为另一个自定义的 MethodVisitor。ClassWriter继承于 ClassVisitor,主要用来生成类。

加载隔离

要了解类加载隔离,首先要了解JVM的双亲委派机制。双亲委派的加载机制如下:加载一个class,首先会通过启动类加载器加载,其次通过扩展类加载器加载,再通过应用程序类加载器加载,最后通过自定义类加载器加载。

为了实现Jvm-SandBox中沙箱各个模块之间互相隔离,Jvm SandBox破坏了双亲委派机制,在沙箱中自定义了 SandboxClassLoader 以及 ModuleJarClassLoader 来分别加载沙箱内部类和模块中的类,sandbox agent 则是由 AppClassLoader 进行加载的,而 sandbox spy 间谍类是用 BootstrapClassLoader 进行加载,目的就是利用双亲委派加载模型,保证间谍类可以正确的被目标 JVM 加载,从而植入到目标 jvm 中完成与业务代码的交互。

 

3、应用场景

流量回放:如何录制线上应用每次接口请求的入参和出参?改动应用代码固然可以,但成本太大,通过JVM-Sandbox,可以直接在不修改代码的情况下,直接抓取接口的出入参。

 

安全漏洞热修复:假设某个三方包(例如出名的fastjson)又出现了漏洞,集团内那么多应用,一个个发布新版本修复,漏洞已经造成了大量破坏。通过JVM-Sandbox,直接修改替换有漏洞的代码,及时止损。

接口故障模拟:想要模拟某个接口超时5s后返回false的情况,JVM-Sandbox很轻松就能实现。

故障定位:像Arthas类似的功能。

接口限流:动态对指定的接口做限流。

0条评论
0 / 1000
卢****才
2文章数
0粉丝数
卢****才
2 文章 | 0 粉丝
卢****才
2文章数
0粉丝数
卢****才
2 文章 | 0 粉丝
原创

Jvm-Sandbox原理解析

2024-06-24 09:35:38
112
0

1、框架简介

JVM SandBox 是一款 JVM 平台非侵入式运行期 AOP 解决方案,本质上是一种 AOP 落地形式。JVM SandBox可以动态增强指定的类,获取想要的参数和行信息甚至改变方法的执行,常应用于线上问题排查、动态日志打印、监控数据采集以及流量录制和回放等场景。

2、原理分析

JVM SandBox具备无侵入、类隔离、多租户和可拔插等特点。

无侵入:目标应用无需重启也无需感知沙箱的存在。

类隔离:沙箱以及沙箱的模块不会和目标应用的类相互干扰。

多租户:目标应用可以同时挂载不同租户下的沙箱并独立控制。

可拔插:沙箱以及沙箱的模块可以随时加载和卸载,不会在目标应用留下痕迹。

JVM SandBox由多个模块构成,每个模块负责不同的能力,模块的构成如下图所示:

其中模块控制管理主要负责管理 sandbox 自身模块以及使用者自定义模块,例如模块的加载,激活,冻结,卸载。事件监听处理模块负责用户自定义模块实现 Event 接口对增强的事件进行自定义处理,等待事件分发处理器的触发。事件分发处理器理主要负责对目标方法增强后会对目标方法追加三个环节,分别为BEFORE AFTER THROWS。代码编织框架主要负责通过 ASM 框架依托于 JVMTI 对目标方法进行字节码修改,从而完成代码增强的能力。检索过滤器主要负责当用户对目标方法创建增强事件时,沙箱会对目标 jvm 中的目标类和方法进行匹配以及过滤,匹配到用户设定目标类和方法进行增强,过滤掉 sandbox 内部的类以及 jvm 认为不可修改的类。加载类检索主要负责获取到需要增强的类集合依赖检索过滤器模块

从功能上划分,JVM SandBox主要提供字节码增强和类加载隔离两个主要的功能。下面详细介绍字节码增强和类加载隔离的原理。

字节码增强

要了解字节码增强机制,首先要了解Instrumentation的发展历程,在jdk早期版本,为了官方提供了JVMPI/JVMDI机制,JVMPI监控就JVM发生的各种事件,比如,JVM创建、关闭、Java类被加载、创建对象或GC回收等37种事件。JVMDI提供了一批JVM调试接口。JDK 1.5及之后的版本将JVMPI和JVMDI合二为一,形成了一套JVM语义——JVMTI。JVMTI旨在为需要访问VM状态的所有工具提供VM接口,包括但不限于:评测、调试、监视、线程分析和覆盖率分析工具。

JVMTI 本质上是在JVM内部的许多事件进行了埋点。通过这些埋点可以给外部提供当前上下文的一些信息。甚至可以接受外部的命令来改变下一步的动作。外部程序一般利用C/C++实现一个JVMTIAgent,在Agent里面注册一些JVM事件的回调。当事件发生时JVMTI调用这些回调方法。Agent可以在回调方法里面实现自己的逻辑。

基于JVMTI 机制,Java官方提供了Instrumentation机制,Instrumentation接口底层依赖JVMTI语义的Native API,用户可通过实现Instrumentation接口完成对JVM操作。

使用 Instrumentation,可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。这样的特性实际上提供了一种虚拟机级别支持的 AOP 实现方式,使得开发者无需对 JDK 做任何升级和改动,就可以实现某些 AOP(AOP核心理念是定义切入点(pointcut)以及通知(advice)。程序控制流中所有匹配该切入点的连接点(joinpoint)都将执行这段通知代码)的功能了。

在使用Instrumentation进行字节码修改时,需要自定义一个ClassFileTransformer类,在JVM加载class时,会先调用ClassFileTransformer的transform方法,加载class的流程如下图所示:

在做字节码增强时,除了要在加载class时获取到字节码数组,还需要对字节码数组进程操作,写入需要织入的代码,此时需要用到如ASM的字节码操作工具。

ASM 是一个通用的 Java 字节码操作和分析框架。它能够以二进制形式修改已有的类或是动态生成类。修改class的流程如下:

其中ClassReader主要负责读取字节码文件,然后把读取的数据通知 ClassVisitor。ClassVisitor用于生成和转换编译类的 ASM API 基于 ClassVisitor 抽象类,接收 ClassReader 发出的对 method 的访问请求,并且替换为另一个自定义的 MethodVisitor。ClassWriter继承于 ClassVisitor,主要用来生成类。

加载隔离

要了解类加载隔离,首先要了解JVM的双亲委派机制。双亲委派的加载机制如下:加载一个class,首先会通过启动类加载器加载,其次通过扩展类加载器加载,再通过应用程序类加载器加载,最后通过自定义类加载器加载。

为了实现Jvm-SandBox中沙箱各个模块之间互相隔离,Jvm SandBox破坏了双亲委派机制,在沙箱中自定义了 SandboxClassLoader 以及 ModuleJarClassLoader 来分别加载沙箱内部类和模块中的类,sandbox agent 则是由 AppClassLoader 进行加载的,而 sandbox spy 间谍类是用 BootstrapClassLoader 进行加载,目的就是利用双亲委派加载模型,保证间谍类可以正确的被目标 JVM 加载,从而植入到目标 jvm 中完成与业务代码的交互。

 

3、应用场景

流量回放:如何录制线上应用每次接口请求的入参和出参?改动应用代码固然可以,但成本太大,通过JVM-Sandbox,可以直接在不修改代码的情况下,直接抓取接口的出入参。

 

安全漏洞热修复:假设某个三方包(例如出名的fastjson)又出现了漏洞,集团内那么多应用,一个个发布新版本修复,漏洞已经造成了大量破坏。通过JVM-Sandbox,直接修改替换有漏洞的代码,及时止损。

接口故障模拟:想要模拟某个接口超时5s后返回false的情况,JVM-Sandbox很轻松就能实现。

故障定位:像Arthas类似的功能。

接口限流:动态对指定的接口做限流。

文章来自个人专栏
软件应用
2 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0