通用流量錄制回放工具 jvm-sandbox-repeater 實踐記錄 (一)

本文作者陳恒捷是TesterHome社區(qū)主編抚太,第十屆MTSC大會上海站-開源專場出品人对湃。先后在PP助手养铸、PPmoney讼积、荔枝等公司從事測試效能提升相關工作扛门,在測試技術及效率提升方面有豐富的經(jīng)驗積累沐祷。

背景

流量錄制回放近幾年已經(jīng)越來越火。如阿里開放的 doom 攒岛、滴滴開源的 RDebug 赖临。而公司隨著業(yè)務的快速發(fā)展,回歸測試的耗時越來越長灾锯,而且可以留給腳本維護的時間也并不多兢榨。因此也期望通過流量錄制回放,提高回歸測試的效率顺饮。

而剛好前幾天看到阿里技術公眾號推送的一篇 jvm-sandbox 的文章吵聪,里面有提到開源了其中做流量錄制回放的 repeater 模塊,所以嘗試一下领突。

jvm-sandbox-repeater 簡介

直接搬運官方文檔里面的介紹吧

[1]

[2]

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

簡單的說暖璧,就是一個可以在不修改程序的情況下案怯,進行一個服務http君旦、java、dubbo入?yún)⒓胺祷刂档匿浿瞥凹睢R仓С挚焖贁U展 api 金砍,實現(xiàn)自己的插件。

standalone 快速開始

step0 安裝sandbox/啟動bootstrap

cd bin
./bootstrap.sh

等待SpringBoot應用啟動完成 -> Started Application in 4.797 seconds (JVM running for 6.586)

step1 開始錄制

curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId=127000000001156034386424510000ed'

執(zhí)行結(jié)果如下:

訪問鏈接時麦锯,repeater插件通過Repeat-TraceId=127000000001156034386424510000ed恕稠,唯一追蹤到了這一次請求,后臺服務返回了JAVA是世界上最好的語言!扶欣,repeater把畫面定格在了這一秒并將結(jié)果和firstId綁定

step2 開始回放

curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId-X=127000000001156034386424510000ed'

無論我們多少次訪問這個地址鹅巍,都將返回 Repeat-TraceId=127000000001156034386424510000ed 綁定的錄制信息JAVA是世界上最好的語言!;如果重新訪問Slogan后又會將最新的返回結(jié)果綁定到Repeat-TraceId=127000000001156034386424510000ed(為了快速演示料祠,將鏈路追蹤的標志提到參數(shù)中進行透傳了)

完整執(zhí)行結(jié)果如下:

?  bin git:(master) curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId=127000000001156034386424510000ed'
<h1 align="center" style="color:red;margin-top:300px">JAVA是世界上最好的語言!</h1>%                                           

?  bin git:(master) curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId-X=127000000001156034386424510000ed'
<h1 align="center" style="color:red;margin-top:300px">JAVA是世界上最好的語言!</h1>%

光是執(zhí)行官方用例骆捧,當然不能滿足我們需要啦。我們來測試下髓绽,如果有多個 Repeat-TraceId 敛苇,是否可以分別錄制?

測試一下:

# 錄制一個 128 開頭的 traceId 顺呕,返回結(jié)果是 java
?  bin git:(master) curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId=128000000001156034386424510000ed'
<h1 align="center" style="color:red;margin-top:300px">JAVA是世界上最好的語言!</h1>%                                                                           
# 錄制一個 129 開頭的 traceId 枫攀,返回結(jié)果是 Python
?  bin git:(master) curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId=129000000001156034386424510000ed'
<h1 align="center" style="color:red;margin-top:300px">Python是世界上最好的語言!</h1>%                                                                         
# 回放前面 128 的流量
?  bin git:(master) curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId-X=128000000001156034386424510000ed'
<h1 align="center" style="color:red;margin-top:300px">JAVA是世界上最好的語言!</h1>%                                                                           
# 回放前面 129 的流量
?  bin git:(master) curl -s 'http://127.0.0.1:8001/regress/slogan?Repeat-TraceId-X=129000000001156034386424510000ed'
<h1 align="center" style="color:red;margin-top:300px">Python是世界上最好的語言!</h1>%  

看來確實是有效的岸啡。

錄制目標服務

前面只是個簡單的練手阎毅,實際用不用得了,當然的實際項目說話啦梅割。

為了簡單启盛,此處使用了幾個 spring boot 的示例項目當做實際項目使用扫夜。

  • restful-api

項目地址:https://github.com/chenhengjie123/gs-rest-service(官方文檔:https://spring.io/guides/gs/rest-service/ 楞泼,在官方的基礎上增加了請求日志打印的功能,便于查看回放效果)

clone 后笤闯,直接用 complete 里面的完整示例堕阔,當做被測程序。

程序本身功能:當請求 http://localhost:8080/greeting?name=User 時颗味,返回 {"id":2,"content":"Hello, User!"} 超陆。其中 Hello 后面的名稱根據(jù)請求參數(shù)的 name 自動替換,id 會自動遞增浦马。

接下來时呀,按照官方的說明,進行操作:

step0 安裝sandbox和插件到應用服務器

curl -s http://sandbox-ecological.oss-cn-hangzhou.aliyuncs.com/install-repeater.sh | sh

正常日志輸出:

======  begin to install sandbox and repeater module       ======
======  step 0 begin to download sandbox package           ======
======  step 1 begin to download repeater module package   ======
======                 install finished                    ======

step1 修改repeater-config.json晶默,啟用攔截點和插件信息

根據(jù)需要修改repeater-config.json配置文件谨娜,具體配置含義參見:RepeaterConfig.java

repeater-config.json 配置文件,位置是 ~/.sandbox-module/cfg/repeater-config.json

具體的配置含義磺陡,官方提供的鏈接相對路徑有問題趴梢,無法跳轉(zhuǎn)”宜可以直接看這個鏈接:RepeaterConfig.java

此處根據(jù)這個被測項目的需要坞靶,進行了調(diào)整:

20190710更新:之前的配置遺漏了 javaSubInvokeBehaviors 的設定,會導致回放的時候返回沒有被 mock 掉蝴悉,看不出效果彰阴。下面為更正后的配置

{
  "degrade": false, 
  "exceptionThreshold": 1000,
  "httpEntrancePatterns": [
    "^/greeting.*$"
  ],
  "javaEntranceBehaviors": [
  ],
  "javaSubInvokeBehaviors": [
    {
      "classPattern": "hello.GreetingController",
      "includeSubClasses": false,
      "methodPatterns": [
        "greeting"
      ]
    }
  ],
  "pluginIdentities": [
    "http",
    "java-subInvoke"
  ],
  "repeatIdentities": [
    "java",
    "http"
  ],
  "sampleRate": 10000,
  "useTtl": false
}

step2 attach sandbox到目標進程

先到剛才 clone spring boot 示例項目的根目錄,啟動被測應用

# 在示例項目 clone 后的根目錄中運行
cd complete 
mvn install && java -jar target/*.jar

# 查看進程 id 
ps aux | grep target/gs-rest-service-0.1.0.jar
hengjiechen       7737   0.0  0.0  4267932    616 s007  R+   10:23AM   0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn rest-service
hengjiechen       7306   0.0  3.2  7935464 269884 s000  S+   10:23AM   0:14.84 /usr/bin/java -jar target/gs-rest-service-0.1.0.jar

可以看到拍冠,進程 id 為 7306 尿这。然后開始 attach

cd ~/sandbox/bin

# 假設目標JVM進程號為'7306' 。-P 是設定 jvm-sandbox 的端口號庆杜,后面回放需要用到
./sandbox.sh -p 7306 -P 12580

小技巧:上述的找進程 id + attach 過程射众,可以用這個命令一鍵達成:

# -P 是設定 jvm-sandbox 的端口號,后面回放需要用到
sh ~/sandbox/bin/sandbox.sh -p `ps -ef | grep "target/gs-rest-service-0.1.0.jar" | grep -v grep | awk '{print $2}'` -P 12580

控制臺輸出:

                    NAMESPACE : default
                      VERSION : 1.2.1
                         MODE : ATTACH
                  SERVER_ADDR : account.jetbrains.com
                  SERVER_PORT : 53866
               UNSAFE_SUPPORT : ENABLE
                 SANDBOX_HOME : /Users/hengjiechen/sandbox/bin/..
            SYSTEM_MODULE_LIB : /Users/hengjiechen/sandbox/bin/../module
              USER_MODULE_LIB : /Users/hengjiechen/sandbox/sandbox-module;~/.sandbox-module;
          SYSTEM_PROVIDER_LIB : /Users/hengjiechen/sandbox/bin/../provider
           EVENT_POOL_SUPPORT : DISABLE

查看repeater日志看模塊和插件加載情況

$ tail -200f ~/logs/sandbox/repeater/repeater.log

...
2019-07-07 10:24:14 INFO  initializing logback success. file=/Users/hengjiechen/.sandbox-module/cfg/repeater-logback.xml;
2019-07-07 10:24:14 INFO  module on loaded,id=repeater,version=1.0.0,mode=ATTACH
2019-07-07 10:24:14 INFO  onActive
2019-07-07 10:24:14 INFO  pull repeater config success,config=com.alibaba.jvm.sandbox.repeater.plugin.domain.RepeaterConfig@4dddeb36
2019-07-07 10:24:15 INFO  enable plugin http success
2019-07-07 10:24:15 INFO  add watcher success,type=http,watcherId=1000
2019-07-07 10:24:16 INFO  register event bus success in repeat-register

step3 開始錄制和回放

錄制幾個請求:

?  complete git:(master) ? curl -s 'http://localhost:8080/greeting?name=User'
{"id":1,"content":"Hello, User!"}%                                                                                                                            
?  complete git:(master) ? curl -s 'http://localhost:8080/greeting?name=User2'
{"id":2,"content":"Hello, User2!"}%                                                                                                                           
?  complete git:(master) ? curl -s 'http://localhost:8080/greeting?name=User3'
{"id":3,"content":"Hello, User3!"}%                                                                                                                           
?  complete git:(master) ? curl -s 'http://localhost:8080/greeting'
{"id":4,"content":"Hello, World!"}%

對應看到 repeater 的日志增加了幾個輸出:

...
2019-07-09 16:31:20 INFO  broadcast success,traceId=192168015059156266108005510001ed,resp=success
2019-07-09 16:31:26 INFO  broadcast success,traceId=192168015059156266108604210002ed,resp=success
2019-07-09 16:31:31 INFO  broadcast success,traceId=192168015059156266109135010003ed,resp=success
2019-07-09 16:31:36 INFO  broadcast success,traceId=192168015059156266109622310004ed,resp=success

好了欣福,試試回放责球。

怎么回放?文檔完全沒提到拓劝,一臉懵逼雏逾。。郑临。等官方文檔更新把栖博。

20190709更新:官方已經(jīng)更新回放文檔啦,接著進行下去厢洞。

方式一:利用模塊暴露的http接口發(fā)起回放

官方的說明:

模塊暴露了回放接口仇让,用于服務端發(fā)起遠程回放典奉,具體如下:

url : http://ip:port/sandbox/default/module/http/repeater/repeat
params : _data

其中 port 是jvm-sandbox啟動時候綁定的port,可以在attach sandbox時增加-P
12580指定丧叽,或者執(zhí)行~/sandbox/bin/sandbox.sh -p {pid} -v 查看SERVER_PORT _data
是由RepeatMeta經(jīng)過hessian序列化之后的值卫玖,具體調(diào)用方式參見AbstractRecordService
和RecordFacadeApi

沒說明是用什么 http 方法(后面通過看 AbstractRecordService.java 看出是 post ),而且 _data 需要用程序做RepeatMeta的 hessian 序列化踊淳。假瞬。∮爻ⅲ看起來就不是給我們這種命令行觸發(fā)用的脱茉。先跳過。

方式二:針對HTTP接口垄开,可以像Slogan Demo一樣進行參數(shù)或者Header透傳方式進行MOCK回放

從前面的 repeater 日志琴许,找到了幾個 traceId 。對應把它填到 Repeat-TraceId-X 參數(shù)中溉躲。(特別留意:回放會根據(jù)錄制時的 url 進行匹配榜田。如果有參數(shù)是通過 url 傳遞的,必須錄制和回放都用一樣的參數(shù)

# 第一種寫法:
$ curl -s 'http://localhost:8080/greeting' -H "Repeat-TraceId-X:192168015059156266109622310004ed"
{"id":4,"content":"Hello, World!"}%  
$ curl -s 'http://localhost:8080/greeting?name=User3' -H "Repeat-TraceId-X:192168015059156266109135010003ed"
{"id":3,"content":"Hello, User3!"}%     

# 第二種寫法:
$ curl -s 'http://localhost:8080/greeting?Repeat-TraceId-X=192168015059156266109622310004ed'
{"id":4,"content":"Hello, World!"}%  

id 還在遞增签财,回放沒生效串慰。但看了下 plugin 的源碼 偏塞,確實是有這樣的邏輯唱蒸。而且上面兩個請求發(fā)出的時候, repeater.log 并沒有輸出錄制到請求的日志灸叼。

20190710更新:問題已解決神汹,原因是前面的 repeater.json 配置不正確,遺漏了 javaSubInvokeBehaviors 相關配置古今,導致返回值沒有被錄制到屁魏。

修正后,已經(jīng)可以輸出正確的返回了捉腥。此時 repeater.log 也會對應輸出日志:

2019-07-10 17:19:25 INFO  initializing logback success. file=/Users/chenhengjie/.sandbox-module/cfg/repeater-logback.xml;
2019-07-10 17:19:25 INFO  module on loaded,id=repeater,version=1.0.0,mode=ATTACH
2019-07-10 17:19:25 INFO  onActive
2019-07-10 17:19:25 INFO  pull repeater config success,config=com.alibaba.jvm.sandbox.repeater.plugin.domain.RepeaterConfig@61e09144
2019-07-10 17:19:25 INFO  enable plugin http success
2019-07-10 17:19:26 INFO  add watcher success,type=http,watcherId=1000
2019-07-10 17:19:26 INFO  enable plugin java-subInvoke success
2019-07-10 17:19:26 INFO  add watcher success,type=java,watcherId=1003
2019-07-10 17:19:27 INFO  register event bus success in repeat-register
2019-07-10 17:19:31 INFO  broadcast success,traceId=192168015059156275037036610001ed,resp=success
2019-07-10 17:19:32 INFO  broadcast success,traceId=192168015059156275037271710002ed,resp=success
2019-07-10 17:19:41 INFO  find target invocation by PARAMETER_MATCH,identity=java://hello.GreetingController/greeting~S,invocation=com.alibaba.jvm.sandbox.repeater.plugin.domain.Invocation@3af687c7
2019-07-10 17:19:52 INFO  find target invocation by PARAMETER_MATCH,identity=java://hello.GreetingController/greeting~S,invocation=com.alibaba.jvm.sandbox.repeater.plugin.domain.Invocation@6b6f0533

最后兩行就是對應返回錄制的 response 了氓拼。

方式三:使用 repeater-console 做回放

官方文檔沒有明確給出這個方式,但通過查看 repeater-console 里面的 readme 抵碟,可以看到它也是有暴露接口供調(diào)用的桃漾。因此也試試。

結(jié)果看了下拟逮,里面提供的 standalone 和 mysql 兩種數(shù)據(jù)存儲方式撬统,都不支持前面回放的存儲方法(存在 ~/.sandbox-module/repeater-data/record 中)。還得調(diào)整錄制方式才能進行回放敦迄。

7.16更新:此回放方式已跑通恋追。詳細的記錄凭迹,將在《通用流量錄制回放工具 jvm-sandbox-repeater 實踐 (二)——repeater-console 使用》中分享。

  • mybatis + redis

待補充

  • mq

待補充

源碼結(jié)構簡析

項目的源碼目錄如下:

$ tree -L 2 | grep -v iml
.
├── LICENSE
├── Readme.md
├── bin
│   ├── bootstrap.sh
│   ├── health.sh
│   ├── install-local.sh
│   ├── install-repeater.sh
│   ├── package.sh
│   ├── repeater-config.json
│   ├── repeater-logback.xml
│   └── repeater.properties
├── docs
│   ├── plugin-development.md
│   ├── slogan-demo.md
│   └── user-guide-cn.md
├── hessian-lite
│   ├── pom.xml
│   └── src
├── pom.xml
├── repeater-client
│   ├── pom.xml
│   └── src
├── repeater-console
│   ├── Readme.md
│   ├── pom.xml
│   ├── repeater-console-common
│   ├── repeater-console-dal
│   ├── repeater-console-service
│   ├── repeater-console-start
├── repeater-module
│   ├── pom.xml
│   └── src
├── repeater-plugin-api
│   ├── pom.xml
│   └── src
├── repeater-plugin-core
│   ├── pom.xml
│   └── src
├── repeater-plugins
│   ├── dubbo-plugin
│   ├── http-plugin
│   ├── ibatis-plugin
│   ├── java-plugin
│   ├── mybatis-plugin
│   ├── pom.xml
│   ├── redis-plugin
└── travis.sh

整體結(jié)構還是比較清晰的苦囱,有 plugin 目錄嗅绸,便于擴展。也有 console 提供最簡要的流量管理撕彤。更詳細的朽砰,后續(xù)再慢慢研究。

吐槽

20190709更新:之前提到的3個吐槽點官方都第一時間修復了喉刘,效率很高瞧柔。

這次補充兩個點:

1、repeater-console 的說明還是太少睦裳,雖然通過閱讀源碼大致了解了它的功能造锅,但不如有文檔方便,對新手不大友好廉邑。建議補充對應的說明哥蔚。

2、回放提供的2個方式都不是太友好蛛蒙,方式二比較簡單糙箍,但不支持批量,不適合項目使用牵祟。方式一基本上只能通過編程方式進行深夯,無法直接通過接口進行。

建議提供一個命令行工具诺苹,可以直接通過命令行參數(shù)自動組裝和序列化輸出 _data 參數(shù)咕晋,便于用最簡單的方式調(diào)用回放功能。

小結(jié)

這個開源項目是 7月4日 出來的收奔,由于是直接在 jvm 層控制掌呜,從原理上是通用性、擴展性最強的坪哄。而且目前也提供了 mybatis质蕉、http、dubbo 翩肌、Java 等插件模暗,redis 預計7月放出,基本上覆蓋了項目中最常用的幾個中間件了摧阅。

雖然目前文檔還不是非常完整汰蓉,但看得出來是有在用心維護的,昨天周六也有更新了一版文檔棒卷,補充了關于原理方面的說明顾孽。相信只要有足夠的時間祝钢,會變得更完善的。

最后若厚,非常感謝阿里能開源一個這么強大的組件拦英,這樣一些質(zhì)量技術方面沒法有太多資源投入的公司,也可以把流量錄制回放搞起來了测秸。

本文首發(fā)于TesterHome社區(qū)疤估,點此鏈接可查看原文并與作者直接交流

今日份的知識已攝入~
想了解更多前沿測試開發(fā)技術:歡迎關注「第十屆MTSC大會·上忽耄」>>>
1個主會場+11大專場铃拇,大咖云集精英齊聚

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市沈撞,隨后出現(xiàn)的幾起案子慷荔,更是在濱河造成了極大的恐慌,老刑警劉巖缠俺,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件显晶,死亡現(xiàn)場離奇詭異,居然都是意外死亡壹士,警方通過查閱死者的電腦和手機磷雇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躏救,“玉大人唯笙,你說我怎么就攤上這事÷浼簦” “怎么了睁本?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵尿庐,是天一觀的道長忠怖。 經(jīng)常有香客問我抄瑟,道長凡泣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任皮假,我火速辦了婚禮鞋拟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惹资。我一直安慰自己贺纲,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布褪测。 她就那樣靜靜地躺著猴誊,像睡著了一般潦刃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上懈叹,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天乖杠,我揣著相機與錄音,去河邊找鬼澄成。 笑死胧洒,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的墨状。 我是一名探鬼主播卫漫,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肾砂!你這毒婦竟也來了汛兜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤通今,失蹤者是張志新(化名)和其女友劉穎粥谬,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辫塌,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡漏策,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了臼氨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掺喻。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖储矩,靈堂內(nèi)的尸體忽然破棺而出感耙,到底是詐尸還是另有隱情,我是刑警寧澤持隧,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布即硼,位于F島的核電站,受9級特大地震影響屡拨,放射性物質(zhì)發(fā)生泄漏只酥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一呀狼、第九天 我趴在偏房一處隱蔽的房頂上張望裂允。 院中可真熱鬧,春花似錦哥艇、人聲如沸绝编。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽十饥。三九已至怎棱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绷跑,已是汗流浹背拳恋。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留砸捏,地道東北人谬运。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像垦藏,于是被迫代替她去往敵國和親梆暖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容