jvm-sandbox学习+实践
⼀、简介
0、  、几点立夏
1、JVM-SANDBOX(沙箱)实现了⼀种在不重启、不侵⼊⽬标JVM应⽤的运⾏期AOP解决⽅案。
2、动态增强类你所指定的类,获取你想要的参数和⾏信息甚⾄改变⽅法执⾏
3、动态可插拔容器框架
注:可插拔两层含义:
a、JVM 沙箱本⾝是可以被插拔的,可被动态地挂载到指定 JVM 进程上和可以被动态地卸载;
b、JVM 沙箱内部的模块是可以被插拔的,在沙箱启动期间,被加载的模块可以被动态地启⽤和卸载
(⼀)应⽤场景
1、线上故障定位
2、线上系统流控
3、线上故障模拟
4、⽅法请求录制和结果回放
5、动态⽇志打印
6、安全信息监测和脱敏
2、agent⽅式启动
a、沙箱⼯作在应⽤代码加载之前,或者⼀次性渲染⼤量的类、加载⼤量的模块,此时如果⽤ATTACH⽅式加载,可能会引起⽬标JVM的卡顿或停顿(GC),这就需要启⽤到AGENT的启动⽅式。
b、JVM启动参数中增加上:-javaagent:/export/opt/app/jvm-sandbox/sandbox/lib/sandbox-agent.jar
例:nohup java -javaagent:/export/opt/app/jvm-sandbox/sandbox/lib/sandbox-agent.jar -jar sunxj-deploy-1.0-SNAPSHOT.jar >/export/opt/app/runningApp/nohup.log 2>&1 &
c、这样沙箱将会伴随着JVM启动⽽主动启动并加载对应的沙箱模块。
(三)卸载沙箱
./sandbox.sh -p vmid -S
三、沙箱配置
为了更好地使⽤JVM-Sandbox和管理模块,配置上做了⼀些约定和规范。
(⼀)沙箱结构介绍
1、./sandbox/bin/sandbox.sh:沙箱的客户端脚本,⽤于启动、管理沙箱
2、./sandbox/cfg/:沙箱配置⽂件存放⽬录
a、./sandbox/cfg/version:存放沙箱容器的版本号
b、./sandbox/cfg/sandbox.properties:存放沙箱容器的配置信息,配置⽂件只会在沙箱容器启动的时候加载⼀次。
c、./sandbox/l:⽇志配置,⽇志⽂件默认写⼊到${HOME}/logs/sandbox/sandbox.log⽂件中
12315投诉
3、./sandbox/lib/:沙箱主程序的库包⽬录
sandbox-agent.jar:沙箱启动代理
sandbox-core.jar:沙箱内核
sandbox-spy.jar:沙箱间谍库,⽤于提供插桩埋点的间谍类
4、运⾏时⽂件:沙箱启动后将会创建⼀个隐藏⽂件${HOME}/.ken,这个⽂件将完成⽬标JVM进程和沙箱客户端进程⼀些信息的交互.
5、沙箱拥有两个加载模块的⽬录,⽤途各⾃不⼀
a、./sandbox/module/:沙箱系统模块⽬录,由配置项system_module进⾏定义。⽤于存放沙箱通⽤的管理模块,⽐如⽤于沙箱模块管理功能的module-mgr模块,未来的模块运⾏质量监控模块、安全校验模块也都将存放在此处,跟随沙箱的发布⽽分发。系统模块不受刷新(-f)、**强制刷新(-F)功能的影响,只有容器重置(-R)**能让沙箱重新加载系统模块⽬录下的所有模块。
b、${HOME}/.sandbox-module/:沙箱⽤户模块⽬录,由sandbox.properties的配置项user_module进⾏定义,默认为
${HOME}/.sandbox-module/。⼀般⽤于存放⽤户⾃研的模块。⾃研的模块经常要⾯临频繁的版本升级⼯作,当需要进⾏模块动态热插拔替换的时候,可以通过**刷新(-f)或强制刷新(-F)**来完成重新加载。
(⼆)沙箱模块
1、所有的沙箱模块都可以被设计成为热插拔
2、⼀个JAR包下可以申明多个模块,模块需要符合Java SPI规范,要求
a、必须拥有publish的⽆参构造函数
b、必须实现com.alibaba.jvm.sandbox.api.Module接⼝
c、必须完成META-INF/services/com.alibaba.jvm.sandbox.api.Module⽂件中的注册(Java SPI规范要求)
d、也可以通过依赖sandbox-module-starter来简化以上操作。
<parent>
<groupId>com.alibaba.jvm.sandbox</groupId>
<artifactId>sandbox-module-starter</artifactId>
<version>1.2.0</version>
</parent>
3、同⼀个JAR包所声明的所有模块共享同⼀个ModuleJarClassLoader
4、模块⼀共有四种状态
a、加载:模块被沙箱正确加载,沙箱将会允许模块进⾏命令相应、代码插桩等动作
b、卸载:沙箱不会再看到该模块,之前给该模块分配的所有资源都将会被回收,包括模块已经侦听事件的类都将会被移除掉监听插桩,⼲净利落不留后遗症
c、激活:模块加载成功后默认是冻结状态,需要代码主动进⾏激活。模块只有在激活状态下才能监听到沙箱事件
d、冻结:模块进⼊到冻结状态之后,之前侦听的所有沙箱事件都将被屏蔽。需要注意的是,冻结的模块不会退回事件侦听的代码插桩,只有delete()、wathcing()或者模块被卸载的时候插桩代码才会被清理。
(三)配置⽂件解释
1、./cfg/sandbox.properties。如图:
配置⽂件只会在沙箱第⼀次启动的时候加载,刷新(-f)、**强制刷新(-F)和重置(-R)都不会让配置⽂件重新⽣效。如果希望配置⽂件重新⽣效,需要关闭(-S)**容器,重新再次加载。
四、命令说明
sandbox.sh是整个沙箱的主要操作客户端,通过HTTP协议来完成通讯,所以要求Linux系统必须安装curl命令。⽬前我使⽤的是BASH来实现。
1、-p:指定⽬标JVM进程号宽怎么组词
2、-l:列出⽬标JVM沙箱中已经加载的模块
3、-F:强制刷新⽤户模块。⾸先卸载掉所有已加载的⽤户模块,然后再重新进⾏加载。当任何⼀个模块加载失败时,忽略该模块,继续加载其他可加载的模块
4、-f:刷新⽤户模块。与强制刷新⽤户模块不同的地⽅是,普通刷新会遍历⽤户模块下所有发⽣改变的模块⽂件,当且仅对发⽣变化的⽂件进⾏重新加载操作。
5、-R:沙箱模块重置。沙箱模块重置的时候将会强制刷新所有的模块,包括⽤户模块和系统模块。但sandbox.properties不会被重新加载
6、-u:卸载指定模块。卸载指定模块,⽀持通配符表达式⼦。卸载模块不会区分系统模块和⽤户模块。例如:./sandbox.sh -p 4321 -u 'debug-module'
7、-a:激活模块。模块激活后才能收到沙箱事件
8、-A:冻结模块。模块冻结后将感知不到任何沙箱事件,但对应的代码插桩还在。
羊肉饺子馅的做法9、-m:查看模块详细信息。模块名需要精确匹配,不⽀持通配符。如图:
10、-d:模块⾃定义命令
挂载到对应进程:./sandbox.sh -p vmid -d 'my-sandbox-module/addLog' 【my-sandbox-module/addLog】长三角城市
@Information(id = "my-sandbox-module")// 模块名,在指定挂载进程后通过-d指定模块,配合@Command注解来唯⼀确定⽅法【标记在类上】
@Command("addLog")// 模块命令名【标记在⽅法上】
庆国庆的诗词通过指令查看是否挂载成功:./sandbox.sh -p vmid -l
五、sand-box实战(记录请求⽇志)
1、相关项⽬位置:192.168.171.17
a、web项⽬:/export/opt/app/runningApp/unxj-deploy-1.0-SNAPSHOT.jar
c、sandbox-log-module:/root/.sandbox-module/sunxj-sandbox-1.0-SNAPSHOT-jar-with-dependencies.jar
d、http请求⽇志:/export/opt/app/sandbox.log