27

流量回放框架jvm-sandbox-repeater的实践

 4 years ago
source link: https://tech.kujiale.com/liu-liang-hui-fang-kuang-jia-jvm-sandbox-repeaterde-shi-jian/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一. 前言

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

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进行处理和保存。

image2019-12-23_10-49-41.png?version=1&modificationDate=1577090849000&api=v2

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

录制流程: 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启动录制,看日志见插件加载成功,服务开始录制

image2019-12-23_15-22-55.png?version=1&modificationDate=1577090849000&api=v2image2019-12-23_15-19-33.png?version=1&modificationDate=1577090849000&api=v2

2)批量查看录制结果

image2019-12-23_15-42-42.png?version=1&modificationDate=1577090849000&api=v2

3)批量回放。

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

image2019-12-23_15-40-26.png?version=1&modificationDate=1577090849000&api=v2

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

image2019-12-23_17-34-44.png?version=1&modificationDate=1577093682000&api=v2

4)批量回放结果查看

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

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

image2019-12-23_15-47-32.png?version=1&modificationDate=1577090849000&api=v2

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

image2019-12-23_15-54-38.png?version=1&modificationDate=1577090849000&api=v2

5)资源占用情况

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

image2019-12-23_15-14-0.png?version=1&modificationDate=1577090849000&api=v2

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

image2019-12-23_16-1-42.png?version=1&modificationDate=1577090849000&api=v2

五.坑和注意点

由于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的情况。这个需要自己权衡。

image2019-12-23_16-15-56.png?version=1&modificationDate=1577090849000&api=v2

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

六.总结

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

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK