-
Notifications
You must be signed in to change notification settings - Fork 1.6k
INSTALL and CONFIG
- JDK[6,11]
- Linux/UNIX/MacOS;暂不支持Windows,主要是一些脚本需要改造
待完善在线安装脚本
-
首先需要下载最新稳定版本
-
下载完成并解压之后,在sandbox目录下执行安装脚本./sandbox/install-local.sh,并指定沙箱的安装目录。如若不指定,默认的安装目录是${HOME}/.opt
cd sandbox ./install-local.sh
-
成功安装会有以下输出。安装指定安装目录之后,沙箱脚本的工作目录将为你所指定的安装目录。
VERSION=1.2.0 PATH=/Users/luanjia/.opt/sandbox install sandbox successful.
沙箱被设计为不需要安装也能正常执行。沙箱在启动过程中需要定位到配置文件和几个核心JAR包。如果直接运行,则沙箱的工作目录为./sandbox所在的目录;
沙箱有两种启动方式:ATTACH
和AGENT
即插即用的启动模式,可以在不重启目标JVM的情况下完成沙箱的植入。原理和GREYS、BTrace类似,利用了JVM的Attach机制实现。
# 假设目标JVM进程号为'2343'
./sandbox.sh -p 2343
如果输出
NAMESPACE : default
VERSION : 1.2.0
MODE : ATTACH
SERVER_ADDR : 0.0.0.0
SERVER_PORT : 55756
UNSAFE_SUPPORT : ENABLE
SANDBOX_HOME : /Users/luanjia/.opt/sandbox
SYSTEM_MODULE_LIB : /Users/luanjia/.opt/sandbox/module
USER_MODULE_LIB : ~/.sandbox-module;
SYSTEM_PROVIDER_LIB : /Users/luanjia/.opt/sandbox/provider
EVENT_POOL_SUPPORT : DISABLE
则说明启动成功,沙箱已经顺利植入了目标JVM中,并完打开了HTTP端口55756
,完成模块的加载。
有些时候我们需要沙箱工作在应用代码加载之前,或者一次性渲染大量的类、加载大量的模块,此时如果用ATTACH方式加载,可能会引起目标JVM的卡顿或停顿(GC),这就需要启用到AGENT的启动方式。
假设SANDBOX被安装在了/Users/luanjia/.opt/sandbox,需要在JVM启动参数中增加上
-javaagent:/Users/luanjia/.opt/sandbox/lib/sandbox-agent.jar
这样沙箱将会伴随着JVM启动而主动启动并加载对应的沙箱模块。
./sandbox/
+--bin/
| +--sandbox.sh
|
+--cfg/
| +--sandbox-logback.xml
| +--sandbox.properties
| `--version
|
+--lib/
| +--sandbox-agent.jar
| +--sandbox-core.jar
| `--sandbox-spy.jar
|
+--provider/
|. `--sandbox-mgr-provider.jar
|
`--module/
`--sandbox-mgr-module.jar
-
./sandbox/bin/sandbox.sh
沙箱的客户端脚本,用于启动、管理沙箱 -
./sandbox/cfg/
沙箱配置文件存放目录,里面存放了沙箱的所有配置文件 -
./sandbox/lib/
沙箱主程序的库包目录,这里存放的是沙箱工程的主程序,不能随意的删除、改名和移动!文件名 作用说明 sandbox-agent.jar 沙箱启动代理 sandbox-core.jar 沙箱内核 sandbox-spy.jar 沙箱间谍库,用于提供插桩埋点的间谍类
沙箱采用的是Logback日志组件来完成日志记录,日志文件默认写入到${HOME}/logs/sandbox/sandbox.log文件中,如果你有需要也可以通过调整sandbox-logback.xml文件进行修改日志输出配置。
沙箱启动后将会创建一个隐藏文件${HOME}/.sandbox.token,这个文件将完成目标JVM进程和沙箱客户端进程一些信息的交互
沙箱拥有两个加载模块的目录,用途各自不一
-
./sandbox/module/
沙箱系统模块目录,由配置项system_module进行定义。用于存放沙箱通用的管理模块,比如用于沙箱模块管理功能的module-mgr模块,未来的模块运行质量监控模块、安全校验模块也都将存放在此处,跟随沙箱的发布而分发。
系统模块不受刷新(-f)、**强制刷新(-F)功能的影响,只有容器重置(-S)**能让沙箱重新加载系统模块目录下的所有模块。
-
${HOME}/.sandbox-module/
沙箱用户模块目录,由配置项user_module进行定义。一般用于存放用户自研的模块。自研的模块经常要面临频繁的版本升级工作,当需要进行模块动态热插拔替换的时候,可以通过**刷新(-f)或强制刷新(-F)**来完成重新加载。
- 所有的沙箱模块都可以被设计成为热插拔
- 一个JAR包下可以申明多个模块,模块需要符合Java SPI规范,要求
- 必须拥有publish的无参构造函数
- 必须实现com.alibaba.jvm.sandbox.api.Module接口
- 必须完成META-INF/services/com.alibaba.jvm.sandbox.api.Module文件中的注册(Java SPI规范要求)
- 同一个JAR包所声明的所有模块共享同一个
ModuleJarClassLoader
- 模块一共有四种状态
-
加载
模块被沙箱正确加载,沙箱将会允许模块进行命令相应、代码插桩等动作 -
卸载
沙箱不会再看到该模块,之前给该模块分配的所有资源都将会被回收,包括模块已经侦听事件的类都将会被移除掉侦听插桩,干净利落不留后遗症。 -
激活
模块加载成功后默认是冻结状态,需要代码主动进行激活。模块只有在激活状态下才能监听到沙箱事件 -
冻结
模块进入到冻结状态之后,之前侦听的所有沙箱事件都将被屏蔽。需要注意的是,冻结的模块不会退回事件侦听的代码插桩,只有delete()、wathcing()或者模块被卸载的时候插桩代码才会被清理。
-
配置文件:./cfg/sandbox.properties
配置项 | 说明 | 默认值 |
---|---|---|
system_module | 系统模块本地路径 | ./module |
provider | 强化服务提供包本地路径 | ./provider |
user_module | 用户模块本地路径 | ~/.sandbox-module |
server.ip | 沙箱HTTP服务IP | 0.0.0.0 |
server.port | 沙箱HTTP服务端口 | 0(随机端口) |
unsafe.enable | 是否允许增强JDK自带类 | false |
配置文件只会在沙箱第一次启动的时候加载,刷新(-f)、**强制刷新(-F)和重置(-R)都不会让配置文件重新生效。如果希望配置文件重新生效,需要关闭(-S)**容器,重新再次加载。
-
user_module
用户模块本地路径是一个多值通配符表达式,如果用户模块散落在本地多个不同的路径下,可以通过配置多个路径(
;
分割),亦或者可以配置通配符表达式。例如,我们存在一种部署场景,多个用户模块在不同的路径上。
# LOGGING_MODULE /home/upload/logging/jvm-sandbox-module/logging-module.jar # GREYS_MODULE /home/upload/greys/jvm-sandbox-module/greys-module.jar # MKAGENT_MODULE /home/upload/mkagent/jvm-sandbox-module/mkagent.jar
-
使用多值配置:
;
分割
user_module=/home/upload/logging/jvm-sandbox-module/logging-module.jar;/home/upload/greys/jvm-sandbox-module/greys-module.jar;/home/upload/mkagent/jvm-sandbox-module/mkagent.jar; -
使用通配符配置
user_module=/home/upload/*/jvm-sandbox-module/*.jar
以上两种配置都可以正确匹配到所期望三个模块的路径
-
-
unsafe.enable
控制容器是否能让模块增强JDK自带的类,默认值为
FALSE
,即不允许增强JDK自带的类。但实际配置中,在自带的配置文件里,我主动将值配置为TRUE
,将这个控制权交给USER_MODULE进行控制。配置值 说明 TRUE 允许增强JDK自带类 FALSE 不允许增强JDK自带类
sandbox.sh
是整个沙箱的主要操作客户端,通过HTTP协议来完成通讯,所以要求Linux系统必须安装curl命令。目前我使用的是BASH来实现,当然如果你有兴趣也可以自己用Python写一个脚本来实现玩玩~
-
-h
:输出帮助信息 -
-p
:指定目标JVM进程号操作的时候你只需要指定对应的JVM进程号即可,不用关心底层绑定的沙箱HTTP端口,sandbox.sh脚本会帮你搞定这件事
-
-v
:输出加载到目标JVM中的沙箱版本信息 -
-l
:列出目标JVM沙箱中已经加载的模块 -
-F
:强制刷新用户模块沙箱容器在强制刷新的时候,首先会卸载当前所有已经被加载的用户模块,然后再重新对用户模块进行加载
-
首先卸载掉所有已加载的用户模块,然后再重新进行加载
-
模块卸载时将会释放掉沙箱为模块所有开启的资源
- 模块打开的HTTP链接
- 模块打开的WEBSOCKET链接
- 模块打开所在的ModuleClassLoader
- 模块进行的事件插桩
-
当任何一个模块加载失败时,忽略该模块,继续加载其他可加载的模块
-
-
-f
:刷新用户模块刷新用户模块,与强制刷新用户模块不同的地方是,普通刷新会遍历用户模块下所有发生改变的模块文件,当且仅对发生变化的文件进行重新加载操作。
模块文件变化 刷新动作 删除 卸载模块 新增 加载模块 更新 先卸载,再加载模块 卸载模块的时候会释放沙箱为模块所开启的资源(同强制刷新),sandbox.properties不会被重新加载
同样的是,sandbox.properties不会被重新加载
-
-R
:沙箱模块重置沙箱模块重置的时候将会强制刷新所有的模块,包括用户模块和系统模块。
同样的是,sandbox.properties不会被重新加载
-
-u
:卸载指定模块卸载指定模块,支持通配符表达式子。卸载模块不会区分系统模块和用户模块,所有模块都可以通过这个参数完成卸载,所以切记不要轻易卸载module-mgr,否则你将失去模块管理功能,不然就只能
-R
来恢复了。EXAMPLE
# 目标JVM进程号为4321,需要卸载的模块名为`debug-module` ./sandbox.sh -p 4321 -u 'debug-module' # 也可以使用通配符 ./sandbox.sh -p 4321 -u 'debug-*'
-
-a
:激活模块模块激活后才能受到沙箱事件
-
-A
:冻结模块模块冻结后将感知不到任何沙箱事件,但对应的代码插桩还在。
-
-m
:查看模块详细信息模块名需要精确匹配,不支持通配符。
EXAMPLE
# 目标JVM进程号为4321,需要观察的模块名为`sandbox-module-mgr` ./sandbox.sh -p 4321 -m 'sandbox-module-mgr' ID : sandbox-module-mgr VERSION : 0.0.1 AUTHOR : luanjia@taobao.com JAR_FILE : /Users/luanjia/.opt/sandbox/lib/../module/sandbox-mgr-module.jar STATE : FROZEN MODE : {AGENT,ATTACH} CLASS : class com.albaba.jvm.sandbox.module.mgr.ModuleMgrModule LOADER : ModuleJarClassLoader[crc32=1721245995;file=/Users/luanjia/opt/sandbox/lib/../module/sandbox-mgr-module.jar;] cCnt : 0 mCnt : 0
-
-d
:模块自定义命令在模块中可以通过对方法标记
@Command
注释,让sandbox.sh
可以将自定义命令传递给被标记的方法。@Information(id = "sandbox-info", version = "0.0.4", author = "luanjia@taobao.com") public class InfoModule implements Module { @Command("version") public void version(final PrintWriter writer) throws IOException { // ... } }
此时对应过来的
-d
命令参数为:-d sandbox-info/version
即可指定到这个方法。
JVM沙箱偏向于底层产品,受众面比较窄,问题反馈沟通很可能会因为各种原因造成不及时。所以我们建立了一个钉钉小群,方便大家在这里进行沟通。