首页 > 其他分享 >基于jvm-sandbox实现一个简单功能的全链路压测agent

基于jvm-sandbox实现一个简单功能的全链路压测agent

时间:2023-08-31 20:33:35浏览次数:53  
标签:模块 agent alibaba sandbox jvm import com

目前我们已知chaosblade-exec-jvm是基于jvm-sandbox开发的混沌工程注入工具,我们可以基于jvm-sandbox创建一些其他的工具agent:流量回放agent、全链路压测agent等等

接下来我会用完全的代码实现一个可以流量透传、mock挡板、影子表数据落地等功能的压测agent:

MyAgentProject/
|-- agent/                          (Agent 模块)
|   |-- src/
|   |-- pom.xml
|
|-- module/                         (Module 模块)
|   |-- src/
|   |-- pom.xml
|
|-- instrument/                     (Instrument 模块)
|   |-- src/
|   |-- pom.xml
|
|-- pom.xml                         (Parent POM)

 

Agent 模块

这个模块主要用于与控制平台交互,管理 Agent 的生命周期,包括安装、卸载和升级等。

  • API Client: 与控制平台的 API 进行交互。
  • Updater: 负责检查更新,并执行升级操作。
  • Lifecycle Manager: 管理 Agent 的加载和卸载。
  • Command Line Tools: 一些命令行工具用于手动管理 Agent。

Module 模块

这个模块主要包括一系列的子模块,每一个用于具体的任务,比如流量透传、方法 Mock 等。

  • Common Interface: 定义所有模块都要实现的通用接口。
  • Middleware Support: 包括一些预定义的中间件支持模块。
  • User-Defined Modules: 用户可以按照规定的接口添加自己的模块。

Instrument 模块

这个模块是 Agent 的框架,负责程序的生命周期管理以及提供一些内置的命令工具。

  • Instrumentation API: 提供用于字节码操纵的 API。
  • Lifecycle API: 提供用于模块生命周期管理的 API。
  • Built-in Tools: 一些内置的命令行或图形工具。

一:流量透传

在实现这个功能之前,我们需要明确目标服务之间的调用框架以及版本:

目标服务:采用spring boot web:2.1.2-release、feign-hystrix:10.1.0

通常公司在中间件层面流量透传能力基本已经实现。我们通过简单的例子来学习如何用jvm-sandbox来实现我们的功能

1.pom.xml添加相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>pressure-agent</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    <parent>
        <groupId>com.alibaba.jvm.sandbox</groupId>
        <artifactId>sandbox-module-starter</artifactId>
        <version>1.2.0</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.kohsuke.metainf-services</groupId>
            <artifactId>metainf-services</artifactId>
            <version>1.11</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>transmittable-thread-local</artifactId>
            <version>2.14.3</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.1</version>
        </dependency>
    </dependencies>
</project>

2. 通过spi实现module接口

package com.lchen;

import com.alibaba.jvm.sandbox.api.Information;
import com.alibaba.jvm.sandbox.api.Module;
import com.alibaba.jvm.sandbox.api.ProcessController;
import com.alibaba.jvm.sandbox.api.annotation.Command;
import com.alibaba.jvm.sandbox.api.event.BeforeEvent;
import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder;
import com.alibaba.jvm.sandbox.api.listener.ext.EventWatcher;
import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher;
import org.kohsuke.MetaInfServices;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.lang.reflect.Method;

import static com.alibaba.jvm.sandbox.api.event.Event.Type.BEFORE;

@MetaInfServices(Module.class)
@Information(id = "pressure-module")
public class PressurePassModule implements Module {
    private static final Logger LOGGER = LoggerFactory.getLogger(PressurePassModule.class);


    @Resource
    private ModuleEventWatcher moduleEventWatcher;

    @Command("enable-traffic-pass")
    public void enableTrafficPass() {
        final EventWatcher watcher = new EventWatchBuilder(moduleEventWatcher)
                .onClass("javax.servlet.http.HttpServlet")
                .includeSubClasses()
                .includeBootstrap()
                .onBehavior("service")
                .onWatching()
                .onWatch(event -> {
                    final BeforeEvent bEvent = (BeforeEvent) event;
                    Object[] params = bEvent.argumentArray;
                    Class<?> contentRequestWrapper = Class.forName("org.springframework.web.util.ContentCachingRequestWrapper", true, bEvent.javaClassLoader);
                    if (params.length >= 2 && contentRequestWrapper.isInstance(params[0])) {
                        Object contentRequestWrapperObj = params[0];
                        Method headerMethod = contentRequestWrapper.getMethod("getHeader", String.class);
                        Object result = headerMethod.invoke(contentRequestWrapperObj, "X-Pressure-Test");
                        LOGGER.info("testFlag:{}", result);
                        if (result != null) {
                            Cache.set(String.valueOf(result));
                        }
                    }
                    ProcessController.returnImmediately(null);
                }, BEFORE);
    }

    @Command("enable-feign-pass")
    public void enableFeignPass() {
        LOGGER.info("enableFeignPass feign");
        final EventWatcher watcher = new EventWatchBuilder(moduleEventWatcher)
                .onClass("feign.SynchronousMethodHandler")
                .includeSubClasses()
                .includeBootstrap()
                .onBehavior("executeAndDecode")
                .onWatching()
                .onWatch(event -> {
                    final BeforeEvent bEvent = (BeforeEvent) event;
                    Class<?> requestTemplateClass = Class.forName("feign.RequestTemplate", true, bEvent.javaClassLoader);
                    Object[] params = bEvent.argumentArray;
                    if (params.length >= 1 && requestTemplateClass.isInstance(params[0])) {
                        Object requestTemplateObj = params[0];
                        Method headerMethod = requestTemplateClass.getMethod("header", String.class, String[].class);
                        // 检查是否为压测流量(从 ThreadLocal 或其他地方)
                        String testFlag = Cache.get();  // 假设这是你的实现
                        LOGGER.info("testFlag feign:{}", testFlag);
                        if (testFlag != null) {
                            headerMethod.invoke(requestTemplateObj, "X-Pressure-Test", new String[]{testFlag});
                        }
                    }
                }, BEFORE);

    }
}

  


3. 通过threadlocal实现流量服务内部传递,因为父子线程以及线程池原因,普通的threadlocal不能满足,我们采用TransmittableThreadLocal实现

package com.lchen;

import com.alibaba.ttl.TransmittableThreadLocal;

public class Cache<T> {

    private static TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();

    public static void set(String request) {
        threadLocal.set(request);
    }

    public static void remove() {
        threadLocal.remove();
    }

    public static String get() {
        return threadLocal.get();
    }
}

  

 

这样我们基于sandbox实现的简单流量透传能力框架就开发完毕

标签:模块,agent,alibaba,sandbox,jvm,import,com
From: https://www.cnblogs.com/clovejava/p/17670367.html

相关文章

  • OGG_Linux_x64_BigData启动ggsci时报错:error while loading shared libraries: libjvm
    问题描述:[root@hadoop03ggs]$./ggsci./ggsci:errorwhileloadingsharedlibraries:libjvm.so:cannotopensharedobjectfile:Nosuchfileordirectory 解决办法:1.查看缺少那些.so文件[root@hadoop03/]# lddggsci 2.查libjvm.so库文件的路径[root@hadoop0......
  • 如何利用 Agent 构建AI服务
    近年来,人工智能(AI)技术的飞速发展引起了广泛的关注和讨论。而如今,我们正站在一个全新的时代门槛前,面对着AIAgent带来的的崭新未来。以LLM(大型语言模型)作为其核心控制器构建代理是一个很酷的概念。它模拟人类的工作流程,能够自主进行信息搜索、分析、利用,以完成目标。OpenAI联合创始......
  • 笔记-《深入理解java虚拟机-JVM高级特性与最佳实践》
    想深入了解虚拟机相关知识,所以买此书学习,记录笔记,用于后续复习查看本文内容基本摘抄自《深入理解java虚拟机-JVM高级特性与最佳实践》,以供复习之用,没有多少参考价值。想要更详细了解请参考原书。本书是第二版。基于jdk1.7的,1.7中新增了G1收集器。第一部分走近Java  ......
  • jvm 类加载机制
    类加载机制类加载机制是指我们将类的字节码文件所包含的数据读入内存,同时我们会生成数据的访问入口的一种特殊机制。那么我们可以得知,类加载的最终产品是数据访问入口。虚拟机把Class文件加载到内存,并对数据进行校验,转换解析和初始化,形成可以虚拟机直接使用的Java类型,即java.......
  • 病毒|木马|网址在线分析工具 沙箱 sandboxes
     virustotalVirusTotal是一个广泛使用的在线恶意软件分析平台,它提供了综合的文件和URL扫描服务。通过使用多个反病毒引擎和其他分析工具,VirusTotal能够检测和分析恶意软件、病毒、恶意URL和其他安全威胁。VirusTotal的一些主要特点和功能:文件和URL扫描:VirusTotal允许用户上传文......
  • 从原理聊 JVM(五):JVM 的编译过程和优化手段
    一、前端编译前端编译就是将Java源码文件编译成Class文件的过程,编译过程分为4步:1准备初始化插入式注解处理器(AnnotationProcessingTool)。2解析与填充符号表将源代码的字符流转变为标记(Token)集合,构造出抽象语法树(AST)。抽象语法树每个节点都代表着程序代码中的一个语法结......
  • 从原理聊JVM(五):JVM的编译过程和优化手段 | 京东云技术团队
    一、前端编译前端编译就是将Java源码文件编译成Class文件的过程,编译过程分为4步:1准备初始化插入式注解处理器(AnnotationProcessingTool)。2解析与填充符号表将源代码的字符流转变为标记(Token)集合,构造出抽象语法树(AST)。抽象语法树每个节点都代表着程序代码中的一个语法结构,包含包......
  • JVM调优实战及常量池详解
    阿里巴巴Arthas详解 Arthas 是 Alibaba 在2018年9月开源的 Java诊断工具。支持 JDK6+,采用命令行交互模式,可以方便的定位和诊断线上程序运行问题。Arthas 官方文档十分详细,详见:https://alibaba.github.io/arthas  Arthas使用场景得益于Arthas强大且丰富的功......
  • JVM 内存大对象监控和优化实践
    作者:vivo互联网服务器团队-LiuZhen、YeWenhao服务器内存问题是影响应用程序性能和稳定性的重要因素之一,需要及时排查和优化。本文介绍了某核心服务内存问题排查与解决过程。首先在JVM与大对象优化上进行了有效的实践,其次在故障转移与大对象监控上提出了可靠的落地方案。最后,总......
  • JVM系列四:生产环境参数实例及分析【生产环境实例增加中】
    javaapplication项目(非web项目)改进前:-Xms128m-Xmx128m-XX:NewSize=64m-XX:PermSize=64m-XX:+UseConcMarkSweepGC-XX:CMSInitiatingOccupancyFraction=78-XX:ThreadStackSize=128-Xloggc:logs/gc.log-Dsun.rmi.dgc.server.gcInterval=3600000-Dsun.rmi.dgc.client.gcInt......