其他测试框架 流量回放框架 jvm-sandbox-repeater 的实践

酷家乐质量效能 for 酷家乐质量效能 · 2020年05月11日 · 最后由 陈恒捷 回复于 2021年07月30日 · 2333 次阅读

一. 前言

你是否和我一样遇到过以下的问题?

1)服务重构,一堆接口需要回归,让人头疼

2)每次迭代,都要花很多精力来进行回归测试

3)线上 bug,线下复现不了

4)接口自动化用例写辛苦,维护更辛苦

… …

或者许你正在被这些问题困扰。你可能和我一样也尝试过一些流量回放工具来解决上述问题,但最终经历了从入门到放弃的无奈。现有大部分流量回放工具中都存在这样那样的限制,比如只支持 GET 接口、不能对子调用进行 mock、对环境和数据依赖高等,所以往往线上录制时心惊胆战,线下回放时坎坷不断。回归的接口少,使用流量回放还不如手动测试快。回归的接口多,使用的坎坷让人绝望。

所以我们需要的是一款简单易用、安全可靠的流量录制回放工具!!!

在此,推荐 jvm-sandbox-repeater。

二. jvm-sandbox-repeater 简介

jvm-sandbox-repeater 是阿里在 19 年 7 月份的时候开源的流量录制回放工具,代码提供了录制回放的能力,以及一个简单的 repeater-console 的 demo 示例。github 地址:https://github.com/alibaba/jvm-sandbox-repeater

jvm-sandbox-repeater 框架基于 JVM-Sandbox,具备了 JVM-Sandbox 的所有特点封装了以下能力:

1.录制/回放基础协议,可快速配置/编码实现一类中间件的录制/回放

2.开放数据上报,对于录制结果可上报到自己的服务端,进行监控、回归、问题排查等上层平台搭建

基于它,我们可以在业务系统无感知的情况下,快速扩展 api ,实现自己的插件,对流量进行录制,入口请求(HTTP/Dubbo/Java)流量回放、子调用(Java/Dubbo)返回值 Mock 能力。详细介绍可以看官方说明。

录制回放主要原理如下:

录制:如图,当 repeater 启动对 service A 的录制后,有请求到 service A,sandbox 感知到请求后通知 repeater。repeater 对事件进行过滤和采样计算,对满足录制条件的请求会记录请求、响应、子调用和响应,序列化成后通知 repeater-console 进行处理和保存。

回放:回放时,用户请求 repeater-console 的回放接口,明确需要回放哪条录制数据。然后 repeater-console 通过调用 repeater 提供的回放任务接收接口下发回放任务。repeater 在执行回放任务的过程中,会反序列化记录的 wrapperRecord,根据信息构造相同的请求,对被挂载的任务进行请求,并跟踪回放请求的处理流程,以便记录回放结果以及执行 mock 动作。如图,当我们启用了 redis 插件,录制时,service A 到 reids 等的子请求方法、参数、响应将被录制下来,回放时,当 service A 再对 reids 发起请求时,repeater 会先判断是否需要 mock,当需要 mock 时会根据回放上下文中的信息拼接出 MockRequest,通过 mock 策略计算获取 MockResponse。目前源码中是获取相似度 100% 的请求的响应来进行 mock。回放结束,repeater 会将回放信息和结果序列化后通知 repeater-console 进行处理和保存。

进一步了解可以阅读源代码或者参考大能文档:

录制流程:https://testerhome.com/topics/20962

回放流程:https://testerhome.com/topics/21046

三. 我们的落地实践

jvm-sandbox-repeater 仅仅提供了录制回放的能力,如果真的需要实现业务回归使用,后面须要有一个数据中心负责采集数据的加工、存储、搜索。repeater-console 提供了简单的 demo 示例,它支持本地或者 mysql 存储和获取录制回访结果,可进行单请求的录制回放,使用可参考官方文档。而真实的使用场景中,我们一般需要的是批量的录制、回放以及结果查看,所以需要写一个自己的 repeater-console,另外也还需要实现更多的 repeater-plugins。官方已经有了一些常用的插件,所以我们根据需要,从没有的入手。主要改动有:

1)根据需要,先实现了 SOA、mongo 和 es 插件,后续还需要慢慢加。框架封装了基础录制回放协议,对于普通插件开发可以快速完成,主要成本在于寻找最合适的插桩埋点

2)将录制、回放都结果存入 es,并增加了一些字段方便数据搜索查询。

3)在 RecordFacadeApi.java 中增加了批量获取录制结果、批量回放、批量获取回放结果接口。

4)console 独立部署,配置获取接口/facade/api/config/%s/%s 从数据库获取配置,大大减少了对目标服务器资源的占用。

5)repeat 接口支持 diff,diff 结果也存入 es。回放结果查询时,支持 diff 过滤。

四.结果展示

完成上述改造,基本上流量回放就可以简单使用起来了。下面记录一次录制回访的过程。

1)在目标服务器上运行./sandbox.sh -p {PID} -P 12580 启动录制,看日志见插件加载成功,服务开始录制


2)批量查看录制结果

3)批量回放。

一般我们录制和回放的服务器不是同一台,且 console 独立部署了,所以这里需要指定期望回放到哪一台服务器。

另外为了满足只回放某个接口的请求,我们对 batchGethe 和 batchRepeat 接口也增加了对指定接口的支持。

4)批量回放结果查看

在回放结果入库时,我们对 originResponse 和 response 进行了 diff,和回放结果一起存入 es。这样就可以指定只看回放成功或者失败的用例。下面这条是回放成功的,可以看到 diff 为 false,diffReseult 为 null。

增加了请求接口信息 requestApi,方便知道是哪个接口的回放。response 是回放求结果,originResponse 是录制的原始响应,可以看出来结果一致。mockInvocationEsLists 是 mock 的插件方法和参数。

当想获得比对失败回放时,参数 diff 传 0,结果如下

5)资源占用情况

在服务器上的录制。启动 repeater 开始录制,约占用 80M 的内存。另外短时间也会有较大的 cpu 开销,因为需要遍历所有加载的类以及类增强。而和 console 交互也会占用部分网速,可能影响响应时长。所以线上录制时,务必预留好资源。


回放时,一般建议在线下回放。批量回放对 cpu 资源占用较高,这个后续优化。

五.坑和注意点

由于 jvm-sandbox-repeater 刚开源不久,使用时一些坑或者注意点需要了解下。没有详细记录,这里摘要几点。

1)服务要求至少 2 个 CPU,ThreadPoolExecutor 中有限制,单核会初始化线程池失败。使用前需要检查下服务器的配置。

2)当 post 请求同时包含 params 和 body 时,代码会只处理 body 忽略 params,导致接口回放响应失败。源代码 invokePost 函数中处理 post 请求时,body 中没有数据,就取 paramsMap 组装成 FormBody 去执行;如果 body 不为空,就调用 invokePostBody(url, headers, body),把 paramsMap 给丢了。这边简单兼容了下两者并存的情况。

3)官方开源代码的 HttpUtil 基于 okhttp3.OkHttpClient 封装的 http 请求工具中,只支持 GET 和 POST 方法,其他的方法回放时会报错。这个估计是开发漏掉了,写起来不难,照着 invokeGet 和 invokePost 的实现方法抄一份,请求方法稍微改下就行。

4)回放时,子调用会去匹配 mock 请求参数的相似度,取相似度 100% 的来 mock。如果子调用参数有当前时间相关的或者随机数等,就会出现匹配不到的情况。这边修改的逻辑是如果没有相似度 100% 的,就取相似度最高且大于某个值的,否则 mock 失败,抛出异常,阻断流程。当然不是 100% 的匹配度,就可能出现返回不是正确响应的 mock 的情况。这个需要自己权衡。

5)repeater 不支持对 http 返回 code 的比对,只比对返回的 body。回放时对响应不是 2xx 的会给出异常提示而非原始响应,导致回放比对失败,所以不支持对非 2xx 响应接口调用的回放使用。至于 httpCode 的比对,目前看上去是不支持的。

六.总结

jvm-sandbox-repeater 是一款便捷好用的流量回放工具。它无侵入、热插拔的特点对于有一堆历史服务的我们来说有着致命的吸引力。由于直接作用在 jvm 层,它的通用性和可扩展性都不错。

下一步的计划就是支持更多的插件,比如 kafka、es 等,然后平台化,支持平台操作配置变更、录制、回放、结果查看、历史记录查看等。如此,我们就可以从回归测试的漩涡中解脱出来了。

最后感谢阿里开源了这一个强大的流量回放工具。由于本人水平有限,文中对 repeater 认知有误的欢迎指正。

关注我们

酷家乐质量效能团队热衷于技术的成长和分享,几乎每个月都会举办技术分享活动(海星日),每半年举办一次技术专题竞赛分享(火星日),并将优秀内容写成技术文章。

我们尽可能保障分享到社区的内容,是我们用心编写、精心挑选的优质文章。如果您想更全面地阅读我们的文章,请您关注我们的微信公众号"酷家乐技术质量"。

如果您有兴趣了解我们的职位和团队情况,请参考最新职位招聘,并联系 caibao@qunhemail.com。感谢您的阅读!

共收到 13 条回复 时间 点赞

赞👍 还有后续篇么?Mongo 插件能否开源

请问:流量回访如何解决前后接口写入数据依赖的问题?数据库备份库是如何控制在录制时的准确时间节点的

workhard 回复

后续相关专栏还会继续介绍的~

honghd 回复
  1. 本身 jvm-sandbox-repeater 这款工具已经通过 mock 的方式解决了依赖问题。
  2. 首先,目前我们的流量存储在 ES 中,并没有做备份。其次,对于"数据库备份库是如何控制在录制时的准确时间节点的"是基于何种场景下的需求呢?

是考虑流量回放也需要读写数据库,这有没一种可能场景是:回放时某个【接口参数】是依赖上一个接口写入的数据,而刚好数据库确实这一批数据(我理解是生产数据库和流量回放数据库是隔离的,这时如何确保两边源数据一致性;如果不作隔离通过标识,会否出现随着回放次数大数据量激增的问题)

单元测试,接口测试都没有,直接用流量回放来做回归,不是一个好办法。测试应该是一个确定的,有目的的,可控的操作。流量回放的更应该是一种随机测试,在常规测试完成后来查漏补缺。

请问下,回放时,接口 header 中的 Authorization 权限信息怎么处理?
场景是这样:在生产环境录制的请求中带的 A 用户 Authorization 信息,在测试环境中回放时,A 用户的 Authorization 是验证不过的。这种情况如何处理

honghd 回复

jvm-sandbox-repeater 对这个场景的解决方案是:把录制时查数据库的结果也一并录下来,回放的时候直接返回录制的结果而不是去查库。

这样每次用的都是录制那个瞬间查到的数据,什么前后依赖的都不用管了。

pangxie 回复

可以把验证 Authorization 的方法 mock 掉

12楼 已删除
大胡子 jvm-sandbox-repeater 流量录制回放 中提及了此贴 02月02日 15:04

请问下,你们有没有录制网关服务的流量?
我可以正常录制业务服务的 http 请求,但是网关服务的录制不到。我们网关是用的 Spring-Cloud-Gateway.

请问一下,怎么进行线上流量的筛选,筛选出我们未覆盖的场景

陈恒捷 回复

前提是不是得有中间件相关的插件已经启动录制?

onesbyones 回复

这些插件是 jvm-sandbox-repeater 的插件,不需要另外启动。启动 repeater 并且提前做好配置就可以了。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册