JavaAgent-SandBox

简介: 1.前言 之前初步学习了javaAgent,并做了一份总结《JavaAgent学习笔记》。然后在看到《JVM-Sandbox 基于JVM的非侵入式运行期AOP解决方案》之后,接触到了集团的sandBox。并尝试使用这种有真正应用场景的运行时AOP框架。 2.SandBox简介 sandBox是集团开发的一种非侵入式的运行时AOP解决方案,它能动态地将你要实现的代码模块打包编织到目标代码中,实

1.前言

之前初步学习了javaAgent,并做了一份总结《JavaAgent学习笔记》。然后在看到《JVM-Sandbox 基于JVM的非侵入式运行期AOP解决方案》之后,接触到了集团的sandBox。并尝试使用这种有真正应用场景的运行时AOP框架。

2.SandBox简介

sandBox是集团开发的一种非侵入式的运行时AOP解决方案,它能动态地将你要实现的代码模块打包编织到目标代码中,实现事件的监听、切入与代码增强。我们一般可以使用以下场景:

  • 线上故障定位
  • 线上系统流控
  • 线上故障模拟
  • 方法请求录制和结果回放
  • 动态日志打印
  • 安全信息监测和脱敏
  • 行链路计算和覆盖率统计

详细的介绍可以阅读这篇篇文章《JVM-Sandbox 基于JVM的非侵入式运行期AOP解决方案》,个人简单总结以下几点:

2.1 AOP切入方式

SandBox围绕“EventListener事件监听”、“Filter目标过滤”、“onEvent事件处理”来实现AOP的切入。

首先,SandBox将事件分类为BEFORE、 RETURN和 THROWS三个环节事件,除此之外还有个LINE。然后观察者通过监听这几个环节的事件进行流转和干预

                                        +-------+
                                        |       |
 +========+  <return>             +========+    | <return immediately>
 |        |  <return immediately> |        |    |
 | BEFORE |---------------------->| RETURN |<---+
 |        |                       |        |
 +========+                       +========+
     |                              |    ^
     |         <throws immediately> |    |
     |                              |    | <return immediately>
     |                              v    |
     |                            +========+
     |                            |        |
     +--------------------------->| THROWS |<---+
                    <throws>      |        |    |
        <throws immediately>      +========+    | <throws immediately>
                                        |       |
                                        +-------+

     2.2 沙箱隔离与通讯

1.SandBox与Tomcat同级加载,并且Tomcat是一定程度破坏了双亲委派机制的,实现各个WebApp之前的隔离。这种与Tomcat同级加载的方式,一定程度保证了类的隔离,防止冲突与污染。

2.由Bootstrap加载的Spy类实现了SandBox与被观察的应用的事件通信,然后SandBox将这些事件信息分发给对应的Module进行处理。

2.3 动态代码织入

1.使用过滤器在JVM中找到目标类的数据信息

2.trasform方法形变原生字节码,插入Spy类到字节码中,通过Spy方法中反射调用JVM-Sandbox的方法。

3. 简单的SandBox功能实现

3.1启动SandBox

现在集团的服务器一般都集成了SandBox的插件环境,切换到/home/staragent/plugins/JVM-Sandbox.src/JVM-Sandbox.cur/sandbox/bin目录,找到启动脚本

找到观察的java应用进程,然后进行SandBox的attach。使用指令 ./sandbox.sh -p 进程号(建议使用admin用户执行,否则会遇到一些问题)

挂载成功后,会打印以下内容,其中USER_MODULE_LIB目录是要将自己的Module挂载的目录。将自己打包成jar形式的Module通过scp或oss等方式,上传到该目录后,执行./sandbox.sh -p 进程号 -f 刷新Module,

刷新后,我们看一下Module是否挂载成功

3.2 Module模块开发

SandBox底层提供了一个HTTP-SERVER(Jetty),通过HTTP协议完成sandbox.sh和沙箱的控制交互,同时也给各个模块提供了基于HttpServlet和WebSocket规范的API,各模块可以复用沙箱完成各自模块的控制与交互。

1.首先需要在resource的META-INF.servicesn内配置一个文件,配置一个Module的入口。

2.编写Module类

需要实现Module, ModuleLifecycle这2个接口,添加@Information注释,然后编写具体的增强代码。这里使用了@Http,通过指令,实现退这些方法的调用。这里需要自己写Filter与EventListener,进行目标对象的过滤与监听,还有事件处理。

需要moduleEventWatcher加载这个监听器,然后使用moduleContraller激活这个监听器。

@Information(version = GlobalConfig.VERSION, author = "lixian.wlx@alibaba-inc.com",
    id = GlobalConfig.NAME, isActiveOnLoad = false)
public class DrillModule implements Module, ModuleLifecycle {

    @Resource
    private ModuleController moduleController;

    @Resource
    private ModuleEventWatcher moduleEventWatcher;

    @Override
    public void onLoad() throws Throwable {
        //TODO
    }

    @Override
    public void loadCompleted() {
        //TODO
    }

    @Override
    public void onUnload() throws Throwable {
        //TODO
    }

    @Override
    public void onActive() throws Throwable {
        //TODO
    }

    @Override
    public void onFrozen() throws Throwable {
        //TODO
    }

    @Http("/mps")
    public void mockProvideSentinel(HttpServletRequest request, HttpServletResponse response) throws Throwable {
        //获取入参
        MockConfigModel mockConfigModel = null;

        String mockClassName = null;
        String mockMethodName = null;
        String uniqueCode = null;
        PrintWriter writer = null;
        try {
            mockConfigModel = processMockRequest(request);
            mockClassName = mockConfigModel.getMockClassName();
            mockMethodName = mockConfigModel.getMockMethodName();
            uniqueCode = buildUniqueCode(mockConfigModel);
            writer = new PrintWriter(response.getWriter(), true);
        } catch (Throwable throwable) {
            logger.error("mockProvideSentinel get param error {} of {}", mockMethodName, mockClassName, throwable);
        }
        if (methodMap.get(uniqueCode) != null) {
            writer.write("mockProvideSentinel fail mockModel:{" + uniqueCode +"} has exist!");
            writer.close();
            logger.warn("mockProvideSentinel fail {} of {} has exist!", mockMethodName, mockClassName);
            return;
        }
        //实现aop切入,返回watcherId
        try {
            int watcherId = moduleEventWatcher.watch(new Hsf2InvokeFilter(), new HsfListener(mockClassName, mockMethodName, new HsfInvokeSentinelHandler()), Type.BEFORE);
            //生成mock业务
            watcherIds.add(watcherId);
            methodMap.put(uniqueCode, watcherId);
            watcherMap.put(watcherId, uniqueCode);
            moduleController.active();
            //返回mock结果
            writer.write(watcherId);
            writer.close();
            logger.info("mockProvideSentinel success mock {} of {}. watcherId: {}", mockMethodName, mockClassName, watcherId);
        } catch (ModuleException e) {
            writer.write(e.toString());
            writer.close();
            logger.error("mockProvideSentinel error {} of {}", mockMethodName, mockClassName, e);
        }

    }    

}

3. 以上代码是模拟HSF的客户端对某个API的限流

./sandbox.sh -p 进程号 -d 'tfdrill-module/mps?mockClassName=EmployeeAPI',  针对这个api进行限流

4. 总结

暂时,我们利用SandBox实现了简单的故障模拟,后续还有跟多的功能开发出来

目录
相关文章
|
6月前
|
Oracle jenkins Java
【Jenkins】使用java -jar jenkins.war --httpPort=XXXX启动Jenkins报错【解决方案】
【Jenkins】使用java -jar jenkins.war --httpPort=XXXX启动Jenkins报错【解决方案】
|
Java 编译器 Maven
javaagent实战
javaagent实战
104 2
|
监控 Java 应用服务中间件
APM - Hello Javaagent
APM - Hello Javaagent
120 0
|
消息中间件 JavaScript 小程序
聊聊大厂都在用的 JavaAgent 上
聊聊大厂都在用的 JavaAgent 上
|
监控 Java 程序员
聊聊大厂都在用的 JavaAgent 下
聊聊大厂都在用的 JavaAgent 下
|
应用服务中间件
The JRE_HOME environment variable is not defined correctly This environment【tomcat闪退】
The JRE_HOME environment variable is not defined correctly This environment【tomcat闪退】
108 0
The JRE_HOME environment variable is not defined correctly This environment【tomcat闪退】
|
应用服务中间件
tomcat闪退[【the jre_home environment variable is not defined correctly this environment variabl】
tomcat闪退[【the jre_home environment variable is not defined correctly this environment variabl】
150 0
tomcat闪退[【the jre_home environment variable is not defined correctly this environment variabl】
|
Java jvm-sandbox Windows
【alibaba/jvm-sandbox#01】debug源码的技巧
alibaba/jvm-sandbox是 一种JVM的非侵入式运行期 AOP 解决方案。沙箱容器提供 1. 动态增强类你所指定的类,获取你想要的参数和行信息甚至改变方法执行 2. 动态可插拔容器框架
451 0
|
Java jvm-sandbox 开发者
【alibaba/jvm-sandbox#03】JavaAgent 修改字节码的机制
开发者一般采用建立一个 Agent 的方式来使用 JVMTI,使用 JVMTI 一个基本的方式就是设置回调函数,在回调函数体内,可以 获取各种各样的VM级信息,甚至控制VM行为,如类加载时修改类
401 0
|
应用服务中间件
Tomcat闪退,出现The JAVA_HOME environment variable is not defined correctly的解决方案
Tomcat出现The JAVA_HOME environment variable is not defined correctly问题的解决方案
Tomcat闪退,出现The JAVA_HOME environment variable is not defined correctly的解决方案