jvm-sandbox-repeater 仅仅提供了录制回放的能力,如果需要完成
业务回归
、实时监控
、压测
等平台,后面须要有一个数据中心
负责采集数据的加工、存储、搜索,repeater-console提供了简单的demo示例;一个模块管理
平台负责管理JVM-Sandbox各模块生命周期;一个配置管理
平台负责维护和推送jvm-sandbox-repeater采集所须要的各种配置变更在阿里集团淘系技术质量内部,已有一套完整的体系在持续运行,从17年开始支持了淘系技术质量部的CI、建站、系统重构等多方面质量保障任务,后续如有需要也会考虑把更多的东西开源回馈社区
注意:目前项目代码默认启动standalone模式,不需要依赖任何服务端和存储,能够简单快速的实现单机的录制回放, 控制单机模式的开关在
~/.sandbox-module/cfg/repeater.properties
配置文件的repeat.standalone.mode=true
,开启或关闭单机工作模式,关闭单机模式后,配置拉取/消息投递等都依赖repeater.properties中配置的具体url;如不想通过http拉取和消息投递的也可以自己实现Broadcaster
和ConfigManager
。稍后我们会公布一份录制回放所需的完整架构图以及jvm-sandbox-repeater在整个体系中的位置供大家工程使用做参考。
代码结构
[root@k8s-worker27-65 jvm-sandbox-repeater]# ls
bin hessian-lite pom.xml repeater-aide repeater-console repeater-plugin-api repeater-plugins travis.sh
docs LICENSE Readme.md repeater-client repeater-module repeater-plugin-core target
[root@k8s-worker27-65 jvm-sandbox-repeater]# ls bin/
bootstrap.sh install-local.sh package.sh repeater-logback.xml sandbox-1.3.3-bin.tar
health.sh install-repeater.sh repeater-config.json repeater.properties
standalone模式,repeat.standalone.mode=true
[root@k8s-worker27-65 jvm-sandbox-repeater]# git cloen https://github.com/alibaba/jvm-sandbox-repeater.git
[root@k8s-worker27-65 jvm-sandbox-repeater]# pwd
/root/work/traffic/jvm-sandbox-repeater
[root@k8s-worker27-65 jvm-sandbox-repeater]# cat bin/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=true
# 是否开启spring advice拦截
repeat.spring.advice.switch=false;
由于https://github.com/alibaba/jvm-sandbox-repeater/releases/download/v1.0.0/sandbox-1.3.3-bin.tar 下载费劲,我先现在了然后改成一下脚本不用每次下载
[root@k8s-worker27-65 jvm-sandbox-repeater]# cat bin/install-local.sh
#!/usr/bin/env bash
# repeater's target dir
REPEATER_TARGET_DIR=../target/repeater
# exit shell with err_code
# $1 : err_code
# $2 : err_msg
exit_on_err()
{
[[ ! -z "${2}" ]] && echo "${2}" 1>&2
exit ${1}
}
# package
sh ./package.sh || exit_on_err 1 "install failed cause package failed"
# extract sandbox to ${HOME}
#curl -s https://github.com/alibaba/jvm-sandbox-repeater/releases/download/v1.0.0/sandbox-1.3.3-bin.tar | tar xz -C ${HOME} || exit_on_err 1 "extract sandbox failed"
cat sandbox-1.3.3-bin.tar | tar xz -C ${HOME} || exit_on_err 1 "extract sandbox failed"
# copy module to ~/.sandbox-module
mkdir -p ${HOME}/.sandbox-module || exit_on_err 1 "permission denied, can not mkdir ~/.sandbox-module"
cp -r ${REPEATER_TARGET_DIR}/* ${HOME}/.sandbox-module || exit_on_err 1 "permission denied, can not copy module to ~/.sandbox-module"
[root@k8s-worker27-65 jvm-sandbox-repeater]# cd bin
[root@k8s-worker27-65 jvm-sandbox-repeater]# ./bootstrap.sh
安装后的结构:
[root@k8s-worker27-65 .sandbox-module]# ls /root/sandbox/
bin cfg example install-local.sh lib module provider sandbox-module
[root@k8s-worker27-65 .sandbox-module]# ls /root/.sandbox-module/
cfg plugins repeater-bootstrap.jar repeater-module.jar
启动命令:也可以自己手动启动
java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -javaagent:/root/sandbox/lib/sandbox-agent.jar=server.port=8820\;server.ip=0.0.0.0 -Dapp.name=jettopro -Dapp.env=sit -jar /root/.sandbox-module/repeater-bootstrap.jar
java
-javaagent:${HOME}/sandbox/lib/sandbox-agent.jar=server.port=${repeater 启动端口}\;server.ip=0.0.0.0 \
-Dapp.name=${录制应用名} \
-Dapp.env=${录制环境} \
-jar application.jar
正常启动的是这个应用程序:
java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -jar /root/.sandbox-module/repeater-bootstrap.jar
录播:
[root@k8s-worker27-65 ~]# curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId=127000000001156034386424510000ed'
JAVA是世界上最好的语言!
回放
curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId-X=127000000001156034386424510000ed'
Python是世界上最好的语言!
此时回放是有问题的,因为没有监听自己的repeater-bootstrap.jar这个应用,监听方式有两种方
1.javaagent方式
java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -javaagent:/root/sandbox/lib/sandbox-agent.jar=server.port=8820\;server.ip=0.0.0.0 -Dapp.name=jettopro -Dapp.env=sit -jar /root/.sandbox-module/repeater-bootstrap.jar
2.attach方式,先获取pid然后监听
[root@k8s-worker27-65 ~]# ps -ef |grep java
root 16713 13435 99 10:55 pts/1 00:00:33 java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -jar /root/.sandbox-module/repeater-bootstrap.jar
监听:
[root@k8s-worker27-65 ~]# cd ~/sandbox/bin/
[root@k8s-worker27-65 bin]# ls
sandbox.sh
[root@k8s-worker27-65 bin]# ./sandbox.sh -p 16713 -P 12580
cat: /root/.sandbox.token: 没有那个文件或目录
NAMESPACE : default
VERSION : 1.3.3
MODE : ATTACH
SERVER_ADDR : 0.0.0.0
SERVER_PORT : 12580
UNSAFE_SUPPORT : ENABLE
SANDBOX_HOME : /root/sandbox/bin/..
SYSTEM_MODULE_LIB : /root/sandbox/bin/../module
USER_MODULE_LIB : /root/sandbox/sandbox-module;~/.sandbox-module;
SYSTEM_PROVIDER_LIB : /root/sandbox/bin/../provider
EVENT_POOL_SUPPORT : DISABLE
然后就是可以开始录制和回放了
step1 开始录制
[root@k8s-worker27-65 ~]# curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId=127000000001156034386424510000ed'
C#是世界上最好的语言!
[root@k8s-worker27-65 ~]# curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId=127000000001156034386424510000ed'
C++是世界上最好的语言!
[root@k8s-worker27-65 ~]#
是不是看到了C++是世界上最好的语言;我们希望让这一刻永远定格;访问链接时,repeater插件通过Repeat-TraceId=127000000001156034386424510000ed,唯一追踪到了这一次请求,后台服务返回了
C++是世界上最好的语言!
,repeater把画面定格在了这一秒并将结果和127000000001156034386424510000ed绑定
[root@k8s-worker27-65 ~]# curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId-X=127000000001156034386424510000ed'
C++是世界上最好的语言!
[root@k8s-worker27-65 ~]# curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId-X=127000000001156034386424510000ed'
C++是世界上最好的语言!
[root@k8s-worker27-65 ~]# curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId-X=127000000001156034386424510000ed'
C++是世界上最好的语言!
[root@k8s-worker27-65 ~]#
无论我们多少次访问这个地址,都将返回Repeat-TraceId=127000000001156034386424510000ed绑定的录制信息
C++是世界上最好的语言!
;如果重新访后又会将最新的返回结果绑定到Repeat-TraceId=127000000001156034386424510000ed(为了快速演示,将链路追踪的标志提到参数中进行透传了)
RegressController中提供了更多的测试用例,包括异步servlet、多线程调用、复杂结构返回对象,可以根据slogan类似的方式进行测试。
简单揭秘:
/regress/slogan
接口调用了RegressServiceImpl#slogan
方法
private AtomicInteger sequence = new AtomicInteger(0);
private String[] slogans = new String[]{"JAVA", "Python", "PHP", "C#", "C++", "Javascript", "GO"};
public String slogan() {
return slogans[sequence.getAndIncrement() % slogans.length] + "是世界上最好的语言!";
}
仔细查看该方法代码会发现,每次请求时都会返回不同的语言,为什么回放时每次都返回同样的结果呢?原因很简单,我们对
RegressServiceImpl#slogan
进行了mock,在回放时开启了mock能力,调用slogan的BEFORE
事件时找到了合适值,直接利用ProcessControlException.throwReturnImmediately
进行了直接返回,RegressServiceImpl的第72行代码在mock回放时永远不会走到。得益于在repeater-config.json中开启了java插件并且默认拦截了RegressServiceImpl#slogan方法,录制slogan时同时录制java子调用
想要知道应用层面发生了什么吗?请看《Slogan Demo究竟发生了什么》
[root@k8s-worker27-65 bin]# ls sandbox-1.3.3-bin.tar repeater-stable-bin.tar
repeater-stable-bin.tar sandbox-1.3.3-bin.tar
1. sandbox-1.3.3-bin.tar:https://github.com/alibaba/jvm-sandbox-repeater/releases/download/v1.0.0/sandbox-1.3.3-bin.tar
1.1)这个是官网下载的解压后:
[root@k8s-worker27-65 ~]# ls sandbox
bin cfg example install-local.sh lib module provider sandbox-module
1.2 )配置文件:
[root@k8s-worker27-65 sandbox]# cat cfg/sandbox.properties |grep -v "#" |grep -v "^$"
user_module=/root/sandbox-module;
server.charset=UTF-8
unsafe.enable=true
user_module=/root/sandbox-module; 配置为sandbox-module所在的路径即可
2. repeater-stable-bin.tar 自己编译或官网下载都可以
https://github.com/alibaba/jvm-sandbox-repeater/releases/download/v1.0.0/repeater-stable-bin.tar
2.1)解压之后:
[root@k8s-worker27-65 ~]# ls sandbox-module/
cfg plugins repeater-bootstrap.jar repeater-data repeater-module.jar
2.2)配置文件:
[root@k8s-worker27-65 cfg]# cat repeater.properties |grep -v "#" |grep -v "^$"
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=true
repeat.spring.advice.switch=false;
repeat.standalone.mode=true
【1】true:就是本地模式不需要数据库存在录播文件,在本地目录中存储[root@k8s-worker27-65 sandbox-module]# ls sandbox-module/repeater-data/record/127000000001156034386424510000ed【2】false:需要数据库mysql进行存储
[root@k8s-worker27-65 aaaa]# cat repeater/cfg/repeater-config.json
{
"useTtl" : true,
"degrade" : false,
"exceptionThreshold" : 1000,
"sampleRate" : 10000,
"pluginsPath" : null,
"httpEntrancePatterns" : [ "^/greeting.*$" ],
"javaEntranceBehaviors" : [],
"javaSubInvokeBehaviors" : [ {
"classPattern" : "hello.GreetingController",
"methodPatterns" : [ "greeting" ],
"includeSubClasses" : false
} ],
"pluginIdentities" : [ "http", "java-entrance", "java-subInvoke", "mybatis", "ibatis" ],
"repeatIdentities" : [ "java", "http" ]
}
自己应用的pid:26362
[root@k8s-worker27-65 target]# ps -ef |grep java
root 26200 13435 11 14:20 pts/1 00:01:00 java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -javaagent:/opt/aaaa/sandbox/lib/sandbox-agent.jar=server.port=8820;server.ip=0.0.0.0 -Dapp.name=jettopro -Dapp.env=sit -jar /opt/aaaa/repeater/repeater-bootstrap.jar
root 26362 13398 5 14:21 pts/0 00:00:22 java -jar gs-rest-service-0.1.0.jar
1)attach自己的pid进行监听
[root@k8s-worker27-65 bin]# pwd
/opt/aaaa/sandbox/bin
[root@k8s-worker27-65 bin]# ./sandbox.sh -p 26362 -P 12501
NAMESPACE : default
VERSION : 1.3.3
MODE : ATTACH
SERVER_ADDR : 0.0.0.0
SERVER_PORT : 12501
UNSAFE_SUPPORT : ENABLE
SANDBOX_HOME : /opt/aaaa/sandbox/bin/..
SYSTEM_MODULE_LIB : /opt/aaaa/sandbox/bin/../module
USER_MODULE_LIB : /opt/aaaa/sandbox/sandbox-module;/opt/aaaa/repeater;
SYSTEM_PROVIDER_LIB : /opt/aaaa/sandbox/bin/../provider
EVENT_POOL_SUPPORT : DISABLE
2)测试自己的服务是否可以录制:因为是录制id一直在增加
[root@k8s-worker27-65 repeater]# pwd
/opt/aaaa/repeater
[root@k8s-worker27-65 repeater]# ls
cfg plugins repeater-bootstrap.jar repeater-module.jar
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId=127000000001156034386424510000ea'
{"id":25,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId=127000000001156034386424510000eb'
{"id":26,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId=127000000001156034386424510000ec'
{"id":27,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId=127000000001156034386424510000ed'
{"id":28,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId=127000000001156034386424510000ee'
{"id":29,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# ls
cfg plugins repeater-bootstrap.jar repeater-data repeater-module.jar
有这个 repeater-data 目录说明录制成功
回放:多次执行一直都是id为25没有增加,说明定在了id为25这个条目上,可以对id=25进行多次回放,也可以选在id进行回放。但是id没有进行录制过的进行回放是回放不了的如id是30的
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId-X=127000000001156034386424510000ea'
{"id":25,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId-X=127000000001156034386424510000eb'
{"id":26,"content":"Hello, jettech01!"}
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId-X=127000000001156034386424510000ec'
{"id":27,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId-X=127000000001156034386424510000ed'
{"id":28,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId-X=127000000001156034386424510000ee'
{"id":29,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId-X=127000000001156034386424510000ef'
{"id":30,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
[root@k8s-worker27-65 repeater]# curl -s 'http://localhost:8080/greeting?name=jettech01&Repeat-TraceId-X=127000000001156034386424510000ea'
{"id":25,"content":"Hello, jettech01!"}[root@k8s-worker27-65 repeater]#
https://github.com/alibaba/jvm-sandbox-repeater/blob/master/docs/user-guide-cn.md#2-%E5%BF%AB%E9%80%9F%E5%BD%95%E5%88%B6%E8%87%AA%E5%B7%B1%E5%BA%94%E7%94%A8