流量复制JVM Sandbox

在软件开发和测试过程中,流量回放是一种常用的技术,用于模拟实际用户流量,以验证系统的可靠性和性能。

本文将介绍两个流行的流量回放工具:jvm-sandbox、jvm-sandbox-repeater

一、JVM sandbox介绍

 1. 概念

  jvm-sandbox 是基于 Java 虚拟机的安全增强框架,能在不修改目标 Java 应用程序代码的情况下,对 Java 方法进行无侵入式增强。其核心原理是利用 Java 字节码增强技术,在运行时动态修改字节码,实现对方法的拦截、替换等操作。这种无侵入特性使其在各种 Java 应用场景中易于集成,不会破坏原有代码结构。

  jvm-sandbox是一个轻量级的Java虚拟机(JVM)插件,用于在运行时捕获和回放HTTP流量。它可以帮助开发人员快速创建可重复的测试场景,用于进行性能测试、功能测试和回归测试。使用jvm-sandbox,您可以轻松模拟多种客户端行为,如请求延迟、重试等。

  • JVM 沙箱容器,一种 JVM 的非侵入式运行期 AOP 解决方案
  • 需要代码的编写,可适用于一些比较定制化的场景
  • 阿里巴巴开源

  • 地址:https://github.com/alibaba/jvm-sandbox

 2. 工作原理

  jvm-sandbox 在 Java 虚拟机启动时加载一个代理模块,该模块在类加载过程中扫描和修改目标类字节码。当方法被调用时,jvm-sandbox 可在方法执行前、执行后及方法抛出异常时插入自定义逻辑。比如,可用于统计方法执行时间、记录方法入参和返回值等,为后续流量克隆和重发提供基础支持。

  JVM-Sandbox的工作原理可以概括为以下几个关键步骤:

    1、类加载:在JVM沙箱中,所有的类都由Java虚拟机的类加载器加载。类加载器负责从文件系统、网络或其他来源加载Java类,并将其转换为可执行代码。

    2、字节码验证:加载过程中,JVM会对字节码进行验证,以确保其符合Java语言规范。这一步骤的目的是检测潜在的安全漏洞,如类型转换错误、数组越界访问等。

    3、安全检查:经过字节码验证后,JVM会进一步进行安全检查,限制应用程序的行为,防止对系统造成危害。这包括对应用程序的访问权限和资源使用进行限制,例如文件系统访问、网络访问、系统调用等。

    4、沙箱执行:一旦通过了字节码验证和安全检查,JVM会将应用程序放入一个受控的沙箱环境中执行。这个沙箱环境限制了应用程序对系统资源的访问,确保它只能在限定的范围内执行。

  此外,JVM-Sandbox还利用虚拟化技术创建隔离环境,并通过字节码增强将被mock(模拟)的方法添加到隔离环境中。当这些方法被调用时,JVM-Sandbox通过反射机制查找它们,并使用代理对象将其转发给沙箱中的虚拟机执行。执行完毕后,结果会返回给主程序。

 3. 在微服务测试中的作用

  在微服务测试环境下,jvm-sandbox 可帮助我们在不影响生产环境的前提下,实时监测和分析微服务运行情况。通过拦截微服务接口方法,获取真实请求流量数据,包括请求参数、调用链路等信息,这些是进行流量克隆和重发的关键数据。

 4. 整体架构图

  

 5. 沙箱启动

  沙箱有两种启动方式:

  • 使用jvm的attach机制,线上随时可进行attach
  • java agent启动,需要在命令行增加参数,故需要重启。

  流量复制的场景下基本就是选择 attach。提供的脚本非常简单易用,直接在安装目录下敲入命令即可。

# 假设目标JVM进程号为'2343'
./sandbox.sh -p 2343

  其他的就是编写 AOP相关代码然后编译成 jar 包放入到安装目录。

 6. 使用方法

  a. 在Java项目中引入jvm-sandbox依赖。

  b. 在JVM启动时启用插件。

  c. 运行应用程序并捕获流量。

  d. 使用捕获的流量进行回放测试。

 7. 实践经验

  • jvm-sandbox适用于基于Java的应用程序,但可能不适用于其他语言或框架。
  • 确保在生产环境中禁用jvm-sandbox,以避免影响真实流量。

二、jvm sandbox repeater

 1. 概念

  jvm-sandbox-repeater 是基于 jvm-sandbox 开发的专门用于流量回放的工具。它能捕获应用运行时的流量数据,并在后续测试中按捕获时的顺序和参数重发,实现微服务系统的回归测试、性能测试等多种测试场景。

  jvm-sandbox-repeater是jvm-sandbox的一个扩展,增加了流量重放功能。它允许您将捕获的流量保存到文件中,并在需要时重复播放。这对于回归测试和持续集成/持续部署(CI/CD)流程非常有用。

 2. 工作原理

  jvm-sandbox-repeater 先利用 jvm-sandbox 对目标微服务接口调用进行数据捕获,将请求详细信息,如请求头、请求体、响应结果等,以特定数据结构存储。需要流量重发时,读取存储数据,模拟真实请求发送到目标微服务接口。重发过程中,还可根据需求动态修改部分参数,测试微服务在不同参数组合下的表现。

 3. 在微服务测试中的作用

  流量回放对微服务测试意义重大。使用 jvm-sandbox-repeater,可模拟真实用户请求行为,使微服务测试更贴近实际场景。例如,微服务性能测试时,重发高并发场景下捕获的流量,观察微服务在高负载下的响应时间、吞吐量等性能指标;回归测试时,重发之前捕获的流量,快速验证微服务功能是否因代码变更受影响。

 4. 使用方法

  a. 按照jvm-sandbox的说明进行设置。

  b.运行应用程序并捕获流量。

  c. 将捕获的流量保存到文件。

  d. 使用jvm-sandbox-repeater回放流量。

 5. 实践经验

  • jvm-sandbox-repeater适用于需要重复测试的场景,如持续集成/持续部署(CI/CD)。
  • 可以根据需求调整回放流量参数,如请求延迟、重试次数等。

 6. 功能特性

  jvm-sandbox-repeater 的主要功能特性包括有:

  • 无侵入式录制:jvm-sandbox-repeater 通过 JVM-Sandbox字节码增强技术,在运行时对Java应用进行录制,在运行时自动拦截和记录网络请求,无需对源代码进行任何修改。
  • 支持多种协议:jvm-sandbox-repeater 支持多种网络协议,包括HTTP/HTTPS、gRPC、Dubbo、TCP 等多种协议的拦截和记录。
  • 灵活的配置:jvm-sandbox-repeater 提供了丰富的配置选项,可以根据需要对录制和回放的行为进行定制。
  • 高性能:jvm-sandbox-repeater 基于 JVM-Sandbox 技术,具有较低的性能损耗,对应用程序的影响较小。
  • 高精度录制:该工具能够精确记录请求和响应的详细信息,包括请求头、请求体、响应状态码、响应体等,确保回放的准确性。
  • 灵活的回放策略:支持多种回放策略,如按照时间顺序回放、并发回放等,满足不同的测试需求。
  • 可视化界面:提供易于使用的可视化界面,方便用户进行流量的录制、管理和回放操作,降低使用门槛。
  • 高扩展性:基于JVM Sandbox平台,易于与其他工具进行集成和扩展。

 7. 应用场景

  在工作中使用jvm-sandbox-repeater工具,主要就是借用其中的三类基本能力:

  • 流量录制:jvm-sandbox-repeater 可以实时捕获目标应用程序的网络请求,并将其记录下来。通过录制功能,获取目标应用程序的实际网络请求数据,用于后续的分析和调试。
  • 流量回放:jvm-sandbox-repeater 支持对录制的网络请求进行回放。通过回放功能,模拟目标应用程序的网络请求,以验证其正确性和稳定性。
  • 请求修改:jvm-sandbox-repeater 允许开发人员对录制的网络请求进行修改。通过修改功能,调整网络请求的参数和头部信息,以模拟不同的场景和测试用例。

  借助上述这三类基本能力,在测试开发工作中,常用于如下场景应用:

  • 接口测试:通过录制生产环境的真实接口流量,在测试环境中进行回放,可以模拟各种复杂场景,验证接口的稳定性和性能。
  • 性能测试:利用录制的流量数据进行性能测试,能够更真实地反映系统的性能表现,帮助发现和解决性能瓶颈。
  • 兼容性测试:通过在不同版本的Java应用或不同环境下回放录制的流量,可以验证系统的兼容性。

三、录制回放

 1. jvm-sandbox-repeater服务部署

  linux环境下,安装软件:jdk1.8、maven3.2、mysql5.7

  a. 安装repeater

cd /usr/local
git clone https://github.com/alibaba/jvm-sandbox-repeater.git
cd jvm-sandbox-repeater/bin
vi install-local.sh 修改tar xz 为tar x .
/install-local.sh

  install-local.sh里面的命令执行出问题可以自己一条一条执行来解决。

  界面展示如下所示,则说明安装成功

   

  b.  修改repeater配置

   vi ~/.sandbox-module/cfg/repeater.properties

# 录制消息投递地址
broadcaster.record.url=http://127.0.0.1:8001/facade/api/record/save

# 回放结果投递地址
broadcaster.repeat.url=http://127.0.0.1:8001/facade/api/repeat/save

# 回放消息取数据地址
repeat.record.url=http://127.0.0.1:8001/facade/api/record/%s/%s

# 配置文件拉取地址
repeat.config.url=http://127.0.0.1:8001/facade/api/config/%s/%s

# 心跳上报配置
repeat.heartbeat.url=http://127.0.0.1:8001/module/report.json

# 是否开启脱机工作模式
repeat.standalone.mode=false

# 是否开启spring advice拦截
repeat.spring.advice.switch=false;

   为什么要修改这2个配置?原因如下:

    repeat.standalone.mode控制 repeater 是否以 standalone 模式启动,我们要与 repeater-console 结合使用,所以配置为false

    其他 url 都是与 repeater-console 交互的 url,所以需要将 host 改为本地启动的 repeater-console 的地址

  c. 修改console配置

   vi /usr/local/jvm-sandbox-repeater/repeater-console/repeater-console-start/src/main/resources/application.properties

spring.application.name=repeater-server
server.port=8001
mybatis.type-aliases-package=com.alibaba.repeater.console.dal.model
# 本地mysql数据源测试,根据需要进行修改
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/repeater?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=none

# 使用本地数据源进行测试
console.use.localCache =false
# 示例回放地址(工程使用需要维护repeater插件的ip:port替换,指定ip发起回放)
repeat.repeat.url=http://%s:%s/sandbox/default/module/http/repeater/repeat
# 示例配置地址(工程使用需要维护repeater插件的ip:port替换,指定ip发起回放)
repeat.config.url=http://%s:%s/sandbox/default/module/http/repeater/pushConfig
# 示例重载地址(工程使用需要维护repeater插件的ip:port替换,指定ip发起回放)
repeat.reload.url=http://%s:%s/sandbox/default/module/http/repeater/reload

   只改了数据库,其他配置不动

  d. 建库建表

   由于我这里是结合console一起使用,所以需要用到Mysql,自然就需要建立所需的数据库和表。建库建表语句在项目中是有的,路径为:/jvm-sandbox-repeater/repeater-console/repeater-console-dal/src/main/resources/database.sql,语句如下所示:

CREATE DATABASE IF NOT EXISTS repeater
    DEFAULT CHARSET utf8
    COLLATE utf8_general_ci;
DROP TABLE IF EXISTS repeater.record;
CREATE TABLE repeater.record
(
    id             BIGINT(20)    NOT NULL AUTO_INCREMENT PRIMARY KEY
        COMMENT '主键',
    gmt_create     DATETIME      NOT NULL
        COMMENT '创建时间',
    gmt_record     DATETIME      NOT NULL
        comment '录制时间',
    app_name       VARCHAR(255)  NOT NULL
        COMMENT '应用名',
    environment    VARCHAR(255)  NOT NULL
        COMMENT '环境信息',
    host           VARCHAR(36)   NOT NULL
        COMMENT '机器IP',
    trace_id       VARCHAR(32)   NOT NULL
        COMMENT '链路追踪ID',
    entrance_desc  VARCHAR(2000) NOT NULL
        COMMENT '链路追踪ID',
    wrapper_record LONGTEXT      NOT NULL
        COMMENT '记录序列化信息',
    request        LONGTEXT      NOT NULL
        COMMENT '请求参数JSON',
    response       LONGTEXT      NOT NULL
        COMMENT '返回值JSON'
)
    ENGINE = InnoDB
    COMMENT = '录制信息'
    DEFAULT CHARSET = utf8
    AUTO_INCREMENT = 1;

DROP TABLE IF EXISTS repeater.replay;
CREATE TABLE repeater.replay
(
    id              BIGINT(20)   NOT NULL AUTO_INCREMENT PRIMARY KEY
        COMMENT '主键',
    gmt_create      DATETIME     NOT NULL
        COMMENT '创建时间',
    gmt_modified    DATETIME     NOT NULL
        comment '修改时间',
    app_name        VARCHAR(255) NOT NULL
        COMMENT '应用名',
    environment     VARCHAR(255) NOT NULL
        COMMENT '环境信息',
    ip              VARCHAR(36)  NOT NULL
        COMMENT '机器IP',
    repeat_id       VARCHAR(32)  NOT NULL
        COMMENT '回放ID',
    status          TINYINT      NOT NULL
        COMMENT '回放状态',
    trace_id        VARCHAR(32)
        COMMENT '链路追踪ID',
    cost            BIGINT(20)
        COMMENT '回放耗时',
    diff_result     LONGTEXT
        COMMENT 'diff结果',
    response        LONGTEXT
        COMMENT '回放结果',
    mock_invocation LONGTEXT
        COMMENT 'mock过程',
    success         BIT
        COMMENT '是否回放成功',
    record_id       BIGINT(20)
        COMMENT '外键'

)
    ENGINE = InnoDB
    COMMENT = '回放信息'
    DEFAULT CHARSET = utf8
    AUTO_INCREMENT = 1;


DROP TABLE IF EXISTS repeater.module_info;
CREATE TABLE repeater.module_info
(
    id           BIGINT(20)   NOT NULL AUTO_INCREMENT PRIMARY KEY
        COMMENT '主键',
    gmt_create   DATETIME     NOT NULL
        COMMENT '创建时间',
    gmt_modified DATETIME     NOT NULL
        comment '修改时间',
    app_name     VARCHAR(255) NOT NULL
        COMMENT '应用名',
    environment  VARCHAR(255) NOT NULL
        COMMENT '环境信息',
    ip           VARCHAR(36)  NOT NULL
        COMMENT '机器IP',
    port         VARCHAR(12)  NOT NULL
        COMMENT '链路追踪ID',
    version      VARCHAR(128) NOT NULL
        COMMENT '模块版本号',
    status       VARCHAR(36)  NOT NULL
        COMMENT '模块状态'
)
    ENGINE = InnoDB
    COMMENT = '在线模块信息'
    DEFAULT CHARSET = utf8
    AUTO_INCREMENT = 1;


DROP TABLE IF EXISTS repeater.module_config;
CREATE TABLE repeater.module_config
(
    id           BIGINT(20)   NOT NULL AUTO_INCREMENT PRIMARY KEY
        COMMENT '主键',
    gmt_create   DATETIME     NOT NULL
        COMMENT '创建时间',
    gmt_modified DATETIME     NOT NULL
        comment '录制时间',
    app_name     VARCHAR(255) NOT NULL
        COMMENT '应用名',
    environment  VARCHAR(255) NOT NULL
        COMMENT '环境信息',
    config       LONGTEXT     NOT NULL
        COMMENT '配置信息'
)
    ENGINE = InnoDB
    COMMENT = '模块配置信息'
    DEFAULT CHARSET = utf8
    AUTO_INCREMENT = 1;
  e. 修改repeater项目代码
  • #parse("/blocks替换为#parse("blocks

   路径为:/jvm-sandbox-repeater/repeater-console/repeater-console-start/src/main/resources/velocity,将velocity路径下的所有文件,存在#parse("/blocks的替换为#parse("blocks这个点,我是看之前的文章有提及,但我拉取源码来看的时候,这个点的问题已经不存在的,源码中就已经是#parse("blocks,所以我这个点没有修改代码

  • 修改 ReplayController.java

   路径为:/jvm-sandbox-repeater/repeater-console/repeater-console-start/src/main/java/com/alibaba/repeater/console/start/controller/page/ReplayController.java,将return "/replay/detail";修改为return "replay/detail";,去掉双引号里面第一个 /

  • 修改 RegressPageController.java

路径为:/jvm-sandbox-repeater/repeater-console/repeater-console-start/src/main/java/com/alibaba/repeater/console/start/controller/test/RegressPageController.java,将return "/regress/index";修改为return "regress/index";,去掉双引号里面第一个 /

  f. 启动repeater项目

cd /usr/local/jvm-sandbox-repeater
mvn clean install -Dmaven.test.skip=true && java -jar repeater-console/repeater-console-start/target/repeater-console.jar

   出现如下所示内容,说明项目构建成功

    

   出现如下所示内容,说明repeater项目启动成功

    

  g. 访问repeater-console页面

   http://192.168.240.134:8001/regress/index.htm,访问页面,进入到如下测试页面,说明通过url访问也ok,服务没有问题

    

    该页面总共三个菜单:在线流量、配置管理、在线模块

    先简单讲下,在线流量就是录制的请求,配置管理就是针对要录制的应用配置,在线模块就是sandbox的心跳。

 2. 启动被测服务

  a. 克隆应用程序源码并安装

cd /usr/local
git clone https://github.com/chenhengjie123/gs-rest-service.git
cd gs-rest-service/complete
mvn install

   这个项目是在看其他帖子看到的,是个开源的demo,我在这也引用下。

   使用mvn install命令,把项目中打好的包,放到本地仓库。

   出现如下界面,说明命令执行成功

    

   在 complete/target 目录下,可以看到,生成了一个jar包,如下所示

    

  b. 启动项目

   在 complete/target 目录下,使用命令 java -jar gs-rest-service-0.1.0.jar 启动项目,出现如下所示内容,项目启动成功 

    

 3. 启动关系sandbox

  a. attach启动:

   获取项目PID,有2种方式

    方式一:在启动项目的时候,会展示PID,如上图所示

    方式二:使用命令ps -ef|grep gs-rest-service-0.1.0.jar可以获得,我这里获取到的PID是:12836,如下所示

     

   获取到项目PID后,到 sandbox 目录 /root/sandbox/bin下,使用命令./sandbox.sh -p 12836 -P 8002,运行命令后,出现如下内容,说明成功

     

    参数说明

    • p 被录制应用进程号
    • P repeater启动端口,这个每个人定义的都可以不同,一定是一个未占用的端口

   attach 模式下,录制应用名和录制环境这两个参数都会被默认为 unknown

   注意:启动失败报错:java.lang.NoClassDefFoundError: com/sun/tools/attach/VirtualMachine。原因:使用的jre中的java,解决办法:更换的java的路径为jdk的java。若安装jdk为openjdk,则更改/etc/profile,更改完后source /etc/profile生效

export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk
export PATH=$PATH:$JAVA_HOME/bin

   b. attach关闭

   运行命令./sandbox.sh -p 12836 -S,出现如下内容,jvm-sandbox关闭成功

    

  4. 配置说明

   a. 日志

    sandbox日志在 /root/logs/sandbox/sandbox.log

    repeater日志在/root/logs/sandbox/repeater/repeater.log(~/.sandbox-module/cfg/repeater-logback.xml中配置的)

    每次修改repeater-logback.xml配置,都需要重启 repeater 才能生效。

    修改日志级别,默认是info,改为debug

     

   b. 录制回放配置字段

    这个配置,主要依赖com.alibaba.jvm.sandbox.repeater.plugin.domain.RepeaterConfig类,参考之前的博文,引用下字段配置说明,如下所示:

配置名配置含义参数说明备注
pluginIdedentities 录制所使用的插件列表,配置了相应的插件名称,才能启用对应类别插件类别的录制 插件名称有效值有:"http", "java-entrance", "java-subInvoke", "mybatis", "redis","ibatis","dubbo-consumer","dubbo-provider" 1、插件配置生效还需要~/.sandbox-module/plugins/有对应的插件 jar 包。2、该参数有效值字段对应的取值是源码中实现了InvokePlugin的类的identity方法。
repeatIdentities 回放所使用的插件列表,配置了对应的插件,才能进行对应类别的回放 插件名称有效值有:"http", java", "dubbo" 1、插件配置生效还需要~/.sandbox-module/plugins/有对应的插件 jar 包。2、该参数有效值字段对应的取值是源码中实现了Repeater的类的identity方法。
httpEntrancePatterns 需要录制和回放的 http 接口,需要同时在 pluginIdedentities 和 repeatIdentities 中都配置了http这个配置才生效 链接的路径 参数支持正则表达式:"^/alertService/.*$"
javaSubInvokeBehaviors 需要录制和 mock 的 java 方法的配置,需要 pluginIdedentities 配置了java-subInvoke这个配置才生效 类名、方法名、以及是否包含子方法(若为 true,则匹配该类下的所有子类或者实现类,实际是否可用,有待验证),支持正则表达式 如下配置的意思就是 com.test.server.utils 包下所有类和所有方法{"classPattern": "com.test.server.utils.","methodPatterns": [ "" ],"includeSubClasses": false}
javaEntranceBehaviors 需要录制和回放的 java 方法的入口,需要同时在 pluginIdedentities 配置了java-entrance以及 repeatIdentities 配置了java这个配置才生效 类名、方法名、以及是否包含子方法(若为 true,则匹配该类下的所有子类或者实现类,实际是否可用,有待验证),支持正则表达式 如下配置的意思就是 com.test.utils 包下所有类和所有方法{"classPattern": "com.test.utils.","methodPatterns": [ "" ],"includeSubClasses": false}如果该入口方法在某个 http 入口的调用链路下,可能不会被录制到,如 com.test.controller.hello() 方法,本身对应着 “/hello 的访问路径,则录制时无法录制到以这个 hello 方法为入口的 java 录制记录”
pluginsPath 插件路径 String,默认填 null 即可 默认填 null 即可
exceptionThreshold 异常发生阈值;默认 1000 当ExceptionAware感知到异常次数超过阈值后,会降级模块 Integer,默认填 1000 即可 当前只使用过 1000,未出现过降级情况。当出现降级则不再进行任何录制。涉及的关键方法:com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultEventListener#access
degrade 开启之后,不进行录制,只处理回放请求 boolean,默认填 false 即可 当前只使用过 false,按照字面理解就是当这个改为 true 之后,不再进行录制。涉及的关键方法:com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultEventListener#access
useTtl 是否开启 ttl 线程上下文切换,开启之后,才能将并发线程中发生的子调用记录下来,否则无法录制到并发子线程的子调用信息,原理是将住线程的 threadLocal 拷贝到子线程,执行任务完成后恢复 boolean,默认填 true 即可 默认使用 true,开启线程跟踪
sampleRate 采样率;最小粒度万分之一 Integer 默认填 10000 即可 当前只使用过 10000,可以结合这个方法理解com.alibaba.jvm.sandbox.repeater.plugin.core.trace.TraceContext#inTimeSample

 5. repeater-console页面

  通过repeater-console页面,查看对应的配置,url为:http://192.168.240.134:8001/regress/index.htm

  服务启动,配置管理-新增配置:

   

  在线模块 

   以attach模式启动sandbox,自动展示sandbox心跳信息。环境和应用名都是unknown,如下所示:

    

 6. 流量录制

  完成上述配置后,我们来录一个请求试下,访问:http://192.168.240.134:8080/greeting?name=yihuqingjiu,页面返回内容,可以在启动的项目下,查看对应日志,如下所示:     

   

  验证是否有录制成功,有2种方式:

   页面查看:直接通过repeater-console的在线流量页面查看,如果有刚操作的请求,说明录制成功,如下所示:

    

   日志查看:查看repeater日志,有相对应的成功日志,如下所示:

    

    相对应的,可以看下数据库是否正常落值,查看record表,是有对应数据的,如下所示:

      

 7.  流量回放

  流量回放的话,就直接点击已录制的请求,右侧有个回放按钮,直接点击即可。

  我们来尝试一下,操作回放后,查看回放详情

    

  看截图,看到回放的结果是失败的,为何失败呢,看下具体信息

  因为id值不一致,所以判断回放失败,如下所示:

   

  修改代码,使得每次回放都是成功的

  启动服务、修改配置、流量录制这些过程就不重复了,直接看下回放结果

  回放详情如下所示:

   

 8. 问题

  a. 录制不成功

   录制遇到最大的一个问题,就是录制不成功,后面查日志和对比配置,是正则表达式写错的问题

   repeater下的日志,如下所示:

    

   日志中明确提示ignore this request

   后面排查repeater-console页面配置管理中的正则表达式,发现正则写错,没有匹配到url的原因导致。

  b. 修改配置不生效

   这个问题算是上一个问题的续集,为啥这么说呢。我之前把配置修改后,再次请求去录制,发现还是不成功

   后来发现,修改repeater配置,需要重启项目,attach到sandbox,只有在attach的时候,才会重新去读取配置

  c. 服务启动顺序

   先启动repeater-console服务

   再启动被测服务

   最后通过attach模式启动sandbox

   如果中途有修改repeater-console配置项,上述步骤重来即可

 

 

posted on 2025-05-27 00:58  花溪月影  阅读(214)  评论(0)    收藏  举报