1.转转流量录制与回放的源码原理及实践
2.JVM-SANDBOX:从阿里精准测试走出的开源贡献奖
3.Jvm-Sandbox原理分析-Sandbox的启动-01
4.通用流量录制回放工具 jvm-sandbox-repeater 尝鲜 (二)——repeater-console 使用
5.Jvm sandbox mock机制实践
转转流量录制与回放的原理及实践
随着转转业务规模和复杂度的提升,服务之间的分析依赖关系变得日益复杂,开发和测试过程中遇到的源码问题也日益增多。如何优雅地解决这些问题成为了一个关键点。分析优雅意味着在不增加业务成本、源码保持业务基本无感的分析benchmark 源码同时,尽可能减小对业务性能的源码影响。阿里开源的分析jvm-sandbox-repeater(简称Repeater)正是为解决这些挑战而设计的。本文将详细介绍Repeater是源码如何实现业务无感的流量录制和回放,以及其在实际应用中的分析实践与改造。
首先,源码让我们聚焦于Repeater如何做到业务无感的分析流量录制。流量录制包括对一次入口调用(例如HTTP、源码Dubbo或Java调用)及其子调用的分析捕获和记录,形成完整的源码过程记录。以获取产品价格方法为例,流量录制包含入口调用的参数和返回值,以及远程子调用(如redis.get、daoRpc.getProductCount、redis.set、logicRpc.process)的入参和返回值。本地子调用则不被录制。通过转转流量回放平台展示的单个流量线上效果图,我们可以直观理解流量录制的概念。
随后,教学评价软件源码流量回放的过程涉及获取录制流量的入口调用参数,再次发起调用,并根据参数匹配子调用,使用录制时记录的入参和返回值。如果回放后返回值与录制时返回值不一致,则标记回放失败。通过转转流量回放平台展示的流量回放线上效果图,我们可以进一步理解流量回放的概念。
接下来,我们将深入探讨Repeater实现原理。Repeater利用JVM-Sandbox的BEFORE、RETURN和THROW事件机制进行录制流程控制,实现代码织入。通过字节码增强技术,JVM-Sandbox在目标方法上实现aop逻辑,实现流量录制和回放的自动化。下图展示了使用JVM-Sandbox增强前后的代码变化,帮助理解其原理。
Repeater的核心逻辑录制基于JVM-Sandbox的事件机制,通过doBefore和doMock方法实现录制和回放的关键逻辑。这些方法在目标方法执行前后被触发,用于记录和模拟调用过程。为了减小录制对线上服务的性能影响,线上环境录制需要特别注意,决战手游源码本文将介绍具体策略。
最后,本文总结了Repeater流量录制和回放的实现原理以及在实际应用中的实践与改造点。通过介绍Repeater的使用方法、注意事项和改造点,旨在帮助读者深入了解并熟练运用这一工具,实现业务无感的流量录制和回放,提升开发和测试效率。
JVM-SANDBOX:从阿里精准测试走出的开源贡献奖
阿里妹导语:在历年双的技术质量保障中,稳定性一直为核心。从年起,淘宝技术质量部研发了一套创新的实时无侵入字节码增强框架——JVM-SANDBOX,并在MTSC大会上荣获开源贡献奖。今天,让我们深入了解这个获奖项目。
在最近的中国移动互联网测试开发大会上,JVM-SANDBOX与淘系同学维护的ATX共同荣获了MTSC 年度开源贡献奖,表彰他们在测试领域的突出贡献。JVM-SANDBOX旨在为服务端稳定性提供实时、非侵入的字节码增强框架,以提升系统的稳定性保障。
自年起,团队面临如何高效、轻量级地实现稳定性专项的消灭病毒类似源码挑战,如功能回归和故障演练等。通过研发JVM-SANDBOX,他们解决了字节码增强技术的高门槛问题,降低了维护成本,并支持了多项功能的动态管理和快速实现。项目的关键在于实现java方法的环绕控制和运行时链路获取,即AOP解决方案,既要实时生效又需灵活。
JVM-SANDBOX以纯Java实现,基于JVMTI技术,提供了实时无侵入的AOP框架和模块管理容器,支撑核心功能如BEFORE、RETURN和THROWS事件处理。项目架构包括HTTP-SERVER组件,通过HTTP协议与模块进行交互,并提供API接口。实践应用中,JVM-SANDBOX显著提升了故障演练效率、自动化依赖检测能力和服务端录制隔离回放的精准度。
目前,JVM-SANDBOX已支持两个开源模块:chaosblade和Repeater,社区活跃度不断提升,期待更多开发者参与。团队呼吁对测试技术感兴趣的连锁门诊源码伙伴加入社区,共同推动测试领域的进步。如果你对加入淘系技术质量团队感兴趣,可通过taobaoqa@list.alibaba-inc.com投递简历。
Jvm-Sandbox原理分析-Sandbox的启动-
Jvm-Sandbox的启动(一):sandbox.sh脚本分析
Sandbox的启动是通过其内置的shell脚本 sandbox.sh 开始执行的,一切的开始皆可从该脚本中探寻出结果。脚本有一定的代码量,大概有+行,这里将该脚本分为如下几个部分进行讲解:
1、变量定义过程这个过程首先预定义了接下来即将使用的一些变量。代码如下:
# 定义sandbox的home目录,并为其赋值 typeset SANDBOX_HOME_DIR [[ -z ${ SANDBOX_HOME_DIR} ]] && SANDBOX_HOME_DIR=${ PWD}/..# 定义 SANDBOX_USER,并为其赋值 typeset SANDBOX_USER=${ USER} [[ -z ${ SANDBOX_USER} ]] && SANDBOX_USER=$(whoami)# 定义 SANDBOX_SERVER_NETWORK typeset SANDBOX_SERVER_NETWORK# 定义lib目录,这个目录下主要存放jar包 typeset SANDBOX_LIB_DIR=${ SANDBOX_HOME_DIR}/lib# 定义 SANDBOX_TOKEN_FILE typeset SANDBOX_TOKEN_FILE="${ HOME}/.sandbox.token"# 定义JVM参数 SANDBOX_JVM_OPS typeset SANDBOX_JVM_OPS="-XmsM -XmxM -Xnoclassgc -ea"# 定义目标JVM的进程号,后面的agent主要attach到该JVM进程上 typeset TARGET_JVM_PID# 定义目标机器IP以及默认机器IP typeset TARGET_SERVER_IP typeset DEFAULT_TARGET_SERVER_IP="0.0.0.0"# 定义目标进程端口 typeset TARGET_SERVER_PORT# 定义名称空间 typeset TARGET_NAMESPACE typeset DEFAULT_NAMESPACE="default"注释和变量命名已经描绘的非常清楚了,在看后面代码遇到忘记了的变量可以到这里来回顾下。
这里为其中一些变量补充说明:
SANDBOX_HOME_DIR:shell脚本中,-z表示检测紧跟的字符串长度是否为0,如果为0返回true。这里使用短路与,如果 ${ SANDBOX_HOME_DIR} 为0,则使用 ${ PWD}/.. 的目录作为sandbox的home目录。这种方式表示优先使用环境变量 SANDBOX_HOME_DIR,如果未定义环境变量SANDBOX_HOME_DIR,则使用当前目录。
SANDBOX_TOKEN_FILE:这个文件主要存放了sandbox attach记录,包括attach进程的host:port。
TARGET_SERVER_IP:一般情况下,我们都是将整个工程打包后上传至目标机器,然后在目标机器上执行该shell脚本,因此默认机器IP一般为localhost即可。
2、执行入口执行入口就比较简单了,就一行代码,其中${ @}会保存我们传递给该shell脚本的所有参数:
main "${ @}"比方说,我们以如下命令启动脚本,则${ @} 就包含了-p 这个参数
./sandbox.sh -p 、main函数main函数是该脚本的重要方法,也是脚本的执行入口,它主要完成了以下几件事:
其代码如下所示:
function main() { # 遍历脚本参数 while getopts "hp:vFfRu:a:A:d:m:I:P:ClSn:X" ARG; do case ${ ARG} in h) # 帮助手册函数,大家可以自行翻阅源码查看 usage exit ;; # 赋值PID p) TARGET_JVM_PID=${ OPTARG} ;; v) OP_VERSION=1 ;; l) OP_MODULE_LIST=1 ;; R) OP_MODULE_RESET=1 ;; F) OP_MODULE_FORCE_FLUSH=1 ;; f) OP_MODULE_FLUSH=1 ;; u) OP_MODULE_UNLOAD=1 ARG_MODULE_UNLOAD=${ OPTARG} ;; a) OP_MODULE_ACTIVE=1 ARG_MODULE_ACTIVE=${ OPTARG} ;; A) OP_MODULE_FROZEN=1 ARG_MODULE_FROZEN=${ OPTARG} ;; d) OP_DEBUG=1 ARG_DEBUG=${ OPTARG} ;; m) OP_MODULE_DETAIL=1 ARG_MODULE_DETAIL=${ OPTARG} ;; # 赋值IP I) TARGET_SERVER_IP=${ OPTARG} ;; # 赋值PORT P) TARGET_SERVER_PORT=${ OPTARG} ;; C) OP_CONNECT_ONLY=1 ;; S) OP_SHUTDOWN=1 ;; n) OP_NAMESPACE=1 ARG_NAMESPACE=${ OPTARG} ;; X) set -x ;; ?) usage exit_on_err 1 ;; esac done # 重置环境 reset_for_env # 校验权限 check_permission# 根据不同的参数,进行相应处理 # 如果没有指定IP,则使用默认值 [ -z "${ TARGET_SERVER_IP}" ] && TARGET_SERVER_IP="${ DEFAULT_TARGET_SERVER_IP}"# 如果没有指定port,使用默认值 [ -z "${ TARGET_SERVER_PORT}" ] && TARGET_SERVER_PORT=0# reset NAMESPACE [[ ${ OP_NAMESPACE} ]] && TARGET_NAMESPACE=${ ARG_NAMESPACE} [[ -z ${ TARGET_NAMESPACE} ]] && TARGET_NAMESPACE=${ DEFAULT_NAMESPACE}if [[ ${ OP_CONNECT_ONLY} ]]; then [[ 0 -eq ${ TARGET_SERVER_PORT} ]] && exit_on_err 1 "server appoint PORT (-P) was missing" SANDBOX_SERVER_NETWORK="${ TARGET_SERVER_IP};${ TARGET_SERVER_PORT}" else # -p was missing [[ -z ${ TARGET_JVM_PID} ]] && exit_on_err 1 "PID (-p) was missing." # attach jvm的核心方法 attach_jvm fi# -v show version [[ -n ${ OP_VERSION} ]] && sandbox_curl_with_exit "sandbox-info/version"# -l list loaded modules [[ -n ${ OP_MODULE_LIST} ]] && sandbox_curl_with_exit "sandbox-module-mgr/list"# -F force flush module [[ -n ${ OP_MODULE_FORCE_FLUSH} ]] && sandbox_curl_with_exit "sandbox-module-mgr/flush" "&force=true"# -f flush module [[ -n ${ OP_MODULE_FLUSH} ]] && sandbox_curl_with_exit "sandbox-module-mgr/flush" "&force=false"# -R reset sandbox [[ -n ${ OP_MODULE_RESET} ]] && sandbox_curl_with_exit "sandbox-module-mgr/reset"# -u unload module [[ -n ${ OP_MODULE_UNLOAD} ]] && sandbox_curl_with_exit "sandbox-module-mgr/unload" "&action=unload&ids=${ ARG_MODULE_UNLOAD}"# -a active module [[ -n ${ OP_MODULE_ACTIVE} ]] && sandbox_curl_with_exit "sandbox-module-mgr/active" "&ids=${ ARG_MODULE_ACTIVE}"# -A frozen module [[ -n ${ OP_MODULE_FROZEN} ]] && sandbox_curl_with_exit "sandbox-module-mgr/frozen" "&ids=${ ARG_MODULE_FROZEN}"# -m module detail [[ -n ${ OP_MODULE_DETAIL} ]] && sandbox_curl_with_exit "sandbox-module-mgr/detail" "&id=${ ARG_MODULE_DETAIL}"# -S shutdown [[ -n ${ OP_SHUTDOWN} ]] && sandbox_curl_with_exit "sandbox-control/shutdown"# -d debug if [[ -n ${ OP_DEBUG} ]]; then sandbox_debug_curl "module//post/通用流量录制回放工具 jvm-sandbox-repeater 尝鲜 (二)——repeater-console 使用
通用流量录制回放工具 jvm-sandbox-repeater 的repeater-console部分使用详解
陈恒捷,TesterHome社区主编和第十届MTSC大会上海站开源专场出品人,以其丰富的测试效能提升经验,带我们深入了解repeater-console的实际应用。repeater-console作为jvm-sandbox-repeater的补充,除了基本的录制和回放功能,还需要配合数据中心、模块管理和配置管理来完成业务回归和监控等任务。
repeater-console主要功能包括数据存储、配置管理和数据对比,但其官方文档较为简单,用户需通过源码解析来理解其使用方法。要实现批量流量录制回放,需自行开发,因为当前demo工程仅包含基础功能。将repeater的standalone模式从true切换为false,并调整相关配置,如端口号和配置文件,才能通过console进行存储和配置获取。
在实际操作中,首先需要关闭现有进程,修改配置文件,然后启动repeater-console,接着启动应用和sandbox,确保配置获取的顺序。通过~/logs/sandbox/repeater/repeater.log的日志,可以确认配置是否正确加载。然而,可能会遇到请求回放接口返回success但实际未触发应用请求的问题,这需要对源码中的RepeaterBridge进行调整。
本文的重点在于演示如何在repeater-console的指导下实现录制回放,虽然没有实现批量回放,但展示了整个流程。在使用过程中,务必注意可能遇到的配置和代码调整,以及一些未明原因的内存地址问题,这需要进一步的调试和研究。
本文首发于TesterHome社区,通过链接可查看原文,对于测试开发技术的爱好者,第十届MTSC大会·上海是一个不容错过的平台,提供丰富的内容和专家分享。
Jvm sandbox mock机制实践
在构建测试平台时, JVM sandbox 沙箱机制提供了一种不重启、无侵入方式调整目标应用返回值的面向切面编程解决方案。对于 RPC 接口、HTTP 接口的测试尤为适用,当需要构建一个全面的模拟平台,而不仅仅是模拟 HTTP 接口时,这种方案变得尤为重要。本文将通过具体案例,展示如何实践 JVM sandbox 并构建模拟平台。
为深入理解,我们以 Linux 服务器为例。首先,创建一个 Springboot 工程,并在其中定义一个 Controller 类作为 URL 入口,调用名为 Clock 的类。Clock 类是官方提供的案例,模拟了一个损坏的钟。运行工程后,会发现一直存在异常。
接下来,我们将构建一个名为 clock-tinker 的 Maven 工程,用于修复损坏的钟。在 pom.xml 中添加依赖“sandbox-module-starter”,并创建“BrokenClockTinkerModule”类,用于修复 Clock 类中的问题。
编译并部署 clock-tinker 工程后,生成 jar 包。然后下载安装 jvm-sandbox,并通过命令行操作将其与修复的 jar 包关联。通过查询服务器进程,找到损坏的钟对应的进程号,并启动 sandbox。之后,执行修复逻辑,使得修复后的 clock#checkState() 方法生效,修复的钟开始正确刷新时间。
为了验证修复效果,需恢复原先的 check() 方法,并停止 sandbox。此时,修复的钟再次开始报错,这是因为随着 sandbox 的卸载,修复逻辑也随之失效。
本文展示了利用 JVM sandbox 实践修复模拟案例的过程,通过不中断应用运行,实现模拟环境的构建。后续文章将深入探讨如何利用此机制搭建一个全面的模拟平台,提供更深入的实践指导。
2024-11-06 13:04
2024-11-06 12:57
2024-11-06 12:18
2024-11-06 12:00
2024-11-06 11:22
2024-11-06 11:09