流量回放arex
arex官方文档 https://doc.arextest.com/zh-Hans/docs/intro/
流量回放是指在A环境/节点上录制请求,在B环境/节点针对录制的请求进行回放操作。并通过比对A、B节点相同接口返回的报文是否一致,从而达到对接口进行回归测试的目的。
一般情况下,大部分针对录制、回放的场景如下:
-
在生产环境录制请求,在生产环境进行回放
-
在生产环境录制请求,在非生产环境(灰度环境、测试环境)进行回放
你可能会想,相同的请求,在不同的环境执行,结果大概率都会不一样吧!比如在生产环境录制了一个根据id删除商品的请求,当在非生产环境回放时,这个id在数据库能否找到都不一定,就算能找到,这两个环境的同一个id对应的商品数据也肯定不是同一个呀,别说不同的环境了,就算是同一个环境,一个id也不不能被删除两次吧!而且这样的回放操作,明显会对回放的环境数据产生影响呀!再比如,在生产录制了一个查询商品实时库存的请求,当换一个时间在生产或者测试进行回放时,数据库中的库存量也肯定不一样了,这个时候能保证回放成功?
实际上,这些担心和疑问确实都是正确的,这也正是所有流量回放平台的核心所在。它们解决以上问题的共性思路就是mock子调用结果,在回放时只关心主接口的业务逻辑部分。
所谓主接口就是指我们录制请求的流量入口,比如创建订单接口、获取店铺详情接口、获取用户详情接口等等;而子调用指的是接口内部的一些操作,比如数据库查询操作、数据库update操作、redis查询操作、redis写入操作、调用三方接口、本地缓存读取、写入操作、MQ发送/消费操作等等。
好了,让我们回到之前的疑问,假设A环境录制请求时,能够把所有的子调用都录制并保存下来,并且在B环境进行回放时不真正的执行这些子调用,而是使用录制的子调用结果,这样问题是不是就迎刃而解了。并且,因为不会真正的执行更新类操作,这样的流量回放平台就天然支持写接口的录制回放(有些流量回放平台目前仅支持读接口,如果要支持写接口,需要二次开发)。
二、流量回放价值
我们先看看平时在项目迭代过程中面临的痛点:
-
自动化脚本编写和维护需要大量的人力成本,而且难以保证覆盖率
-
写服务难于验证,而且测试会产生脏数据,例如我们的核心交易系统,可能会往数据库、消息队列、Redis 等写入数据,这部分数据往往比较难以验证,测试产生的数据也难于清理
-
线上问题难以本地复现,排查困难
所以,有了流量回放平台以后,我们后续可以:
-
仅针对主要的接口编写自动化脚本,解放人力
-
配合代码覆盖率工具,每次上线前进行统计,增强上线信心
-
将线上问题搬到本地进行debug排查,还原事故现场
三、流量回放平台技术选型
本次选择的是AREX流量回放平台,AREX 是一款由携程开源的流量回放平台,在携程落地至今已有 4000+ 应用接入。
选择AREX的原因主要有以下几点:
-
天然支持读、写接口录制和回放,几乎无需二次开发
-
子调用mock比较强大,比如mysql、redis、本地缓存、三方http调用、es、mq等组件
-
在携程内部已经大规模落地使用,风险相对较小
-
接入、使用流程比较简单
四、AREX简单介绍
以下内容摘自AREX官方文档:
-
AREX 组成
-
AREX 工作流程
1. 流量录制:
AREX Java Agent 在生产环境中搭载在 Java 应用上,录制数据流量和请求信息。
将录制到的信息发送到 AREX 数据存取服务(Storage Service)。
数据存取服务将信息导入 MongoDB 数据库中进行存储。
2. 流量回放:
调度服务向目标验证服务发送接口请求,模拟生产环境中的行为。
测试环境中的被测应用同样搭载 AREX Java Agent,当被测应用需要对外部依赖进行调用时,Agent 会将录制的外部依赖(外部请求/DB)的响应返回给被测应用,避免了对实际数据库或其他依赖的交互,减少对特定环境数据的依赖,专注于验证程序本身的逻辑和功能。
目标服务处理请求逻辑,并返回响应报文。
3. 结果验证与报告:
调度服务分别对录制和回放的主接口响应报文与子调用的入参进行对比,验证系统逻辑的正确性。
比对结果分析后生成回放报告。
测试人员检查回放报告,评估应用的功能和性能。
-
AREX 工作原理
-
AREX 核心优势
1.低成本
无代码侵入,基本无接入成本 无需编写测试用例,海量的线上请求也能保证高覆盖率 插桩代码足够简单,性能损耗低
2.多样性支持
支持写验证,支持数据库、消息队列、Redis 数据的验证,甚至支持验证运行时的内存数据,并且测试时不会产生脏数据。
3.测试用例运行稳定
支持各种主流技术框架的自动数据采集和 Mock ,并且支持了本地时间、缓存,在回放时精准还原生产执行时的数据环境。
4.快速线上问题复现
支持一键本地调试,可以快速本地调试线上问题
5.安全稳定
提供流量脱敏机制,保护线上敏感数据。代码隔离,也实现了健康管理,在系统繁忙时会智能降低或关闭数据采集频率
6.良好的功能测试支持
支持测试脚本,也可对采集的数据进行简单的编辑实现固定测试观点的测试,避免大量的测试数据准备
五、AREX接入流程
前面说过,AREX 由 AREX Java Agent、UI(前端服务)、Schedule Service(调度服务)、Storage Service(存储服务)、Report Service(报告分析服务)及 Mongodb、Redis 数据存储等多模块组成,为了方便,我们后续将除 AREX Java Agent以外的部分统一称作“平台端”。
整个AREX的接入流程大致分为以下几步:
1、搭建、部署平台端
AREX官网文档有安装过程的详细介绍,具体参照:http://docs.arextest.com/zh-Hans/docs/chapter1/quick-installation
平台端的搭建,可以使用docker形式一键安装,也可以使用单独部署的方式。docker一键部署的优点在于简单快速,但缺点也很明显,因为所有的组件都在一台服务器上,如果后期接入的应用很多,服务器将无法支撑。因此,建议在测试试用过程中使用一键部署的方式,在切换到生产环境正式使用时采用单独部署的方式。
2、挂载agent
在被测应用的启动参数中增加AREX agent对应的jar即可。特别需要注意的是,录制和回放的环境都需要挂载agent,只是回放的环境一般需要关闭录制功能,如果回放的环境没有挂载agent,那么所有的子调用将会真正的执行。
在应用服务的dockerfile加入如下命令,挂载agent
// 下载agent的jar包
RUN cd /usr/local/ && curl -O http://xxxx/replay/arex/resource/arex-agent.jar
// 挂载agent,
CMD eval exec java -javaagent:/usr/local/arex-agent.jar -Darex.service.name=saas_customer -Darex.tags.env=qa -Darex.coverage.packages=com.server.saas -Darex.retransform.instrumentation.module=dynamic-class -Darex.storage.service.host=1.1.1.1:1111 -jar
启动参数说明:
1、-
指定整个应用在平台端的名称,应用启动如果成功挂载了agent,在平台端的展示效果如下:
由于应用在录制和回放环境都需要挂载agent,但是这两个环境的ip是不一样的,所以AREX在管理这些环境时,需要应用在挂载agent时起一个唯一标识,这个唯一标识就是通过上面这个参数来指定的。
2、-Darex.tags.env=qa
AREX可以允许多个环境对流量都进行录制,为了方便管理,在录制时可以给每个环境录制的流量规定一个tag标签,比如生产环境录制的流量叫prod,qa环境录制的流量叫qa,qa1录制的流量叫qa1。进行tag标签管理之后,后续在平台端回放时可以按指定的tag进行。
3、-Darex.coverage.packages=com.server.saas
AREX支持对本地缓存的录制和回放,比如Spring Cache、Guava Cache 或 Caffeine Cache,但是在启动时需要使用上面的参数进行指定,通常情况下参数的指是整个应用的顶层包,这样整个应用凡是使用了Spring Cache、Guava Cache 或 Caffeine Cache的地方就自动支持录制和回放了。
4、-Darex.retransform.instrumentation.module=dynamic-class
平台端如果配置了动态类(动态类的概念后续介绍),需要重启才会生效,如果想要实时生效,就需要在应用的启动参数中加上这条配置。
5、-Darex.storage.service.host=1.1.1.1:1111
指定录制的请求,上报到哪里进行保存。参数的值就是平台端storage服务的ip:port。
六、AREX使用步骤
如果平台端、应用挂载agent都已完成,接下来就可以正式使用AREX的录制、回放了。
1、访问AREX平台
目前,访问地址为:http://1.1.1.1:1111/
初次访问时,需要使用邮箱登录,这里只需要填写自己某个真实的邮箱,并以验证码的形式登录即可。
2、查看agent挂载是否成功
强烈建议:在生产环境进行录制,在测试环境进行回放
2.1 查看注册是否成功
2.2 查看agent状态是否正确
更多状态参见下图:
3、录制
在开启录制的环境下,针对接口进行正常访问即可。访问后,如果有录制到流量,在平台端的展示效果如下:
点击数字角标,可以查看录制的详细信息:
点击每个recordId后的效果:
除了主接口的详情外,这里也给出了录制到的每一个子调用的详情,比如动态类(DynamicClass)、redis、常规database、三方调用等。
4、回放
点击【Run Test】之后,就可以开始回放
5、查看回放报告
6、查看回放详情
如果回放报告中,存在失败的case,此时就需要我们查看回放的详情去判断失败原因。一般来说,失败的原因要么是AREX平台的问题导致,要么是功能迭代引起的代码差异导致(这种情况出现失败是我们预期的),要么就是版本迭代改出bug了。
七、其他
1、动态类介绍
我们先看一下,AREX录制的动态类大概是什么样子:
上图表示访问com.xxx.AppidConfigCache.getWechatAppConfig方法的数据,在AREX中被当作动态类录制下来了,并且回放的时候会mock此方法返回的数据。那为什么这个方法的数据能够被AREX识别呢?为了搞清楚这个问题,我们先看看这个方法的源码:
可以看到,这个方法被@Cacheable修饰了,而@Cacheable注解是Spring提供的缓存解决机制,它可以指定自己的缓存管理器,也就是cacheManager,缓存管理器可以是redis组件,也可以是本地缓存组件,接下来我们看看上面这个方法的缓存管理器到底使用的是什么:
看到这儿,我们明白了,这里使用的缓存管理器其实是EhCache,也就是本地缓存的一种。AREX平台在最新版本中已经天然支持EhCache缓存的录制,因此,凡是访问了com.xxx.AppidConfigCache.getWechatAppConfig方法的地方,它的请求和响应都会被AREX录制到。
也就是,类似于本地缓存这种内存数据在AREX中,统统被称作为动态类,除了已经天然支持的这些本地缓存外,假如在项目中还有其他的内存数据需要被AREX录制,我们可以在平台端将其配置为动态类,然后这个类或方法的访问就会被录制下来。
如果不是AREX天然支持的动态类就需要对其进行配置,否则这个方法在回放时由于没有录制会出现真实调用,从而导致回放失败。配置方式如下:
入口:
进入后:
2、启用/关闭录制
单个tag
多个tag
3、降噪过滤
哪怕是主接口的对比,一定会存在一些每次请求都不一样的字段,比如traceid、UUID等,这些字段的比对需要过滤掉。配置的方式如下:
4、部分接口排除录制
有些接口,我们不需要录制,比如健康检查接口,此时我们也可以进行配置,具体如下:
5、debug注意事项
在AREX上debug,其实就是对目标服务发起请求,只是这里的目标服务一般是我们的本地而已。但是AREX平台上debug时,header中的cookie字段无法被发送(即使我们看到header中明明有cookie)
6、agent插件开发
在实际项目中,除了通用的组件、动态类组件外,一般还会存在一些公司内部的组件,这些组件是无法被AREX识别并录制的,所以,这部分如果要支持录制,需要自行开发agent插件。官方开发指南:http://docs.arextest.com/zh-Hans/docs/chapter5/Agent-plugin
7、录制结果为null
比如在录制redis时,如果redis中确实不存在数据,此时AREX也会进行录制,只是录制的value为null。但有一种情况,即使redis中存在数据,录制的结果依然为null,就像下面这样:
出现这种问题的原因是,AREX在录制时需要返回方法的返回结果可序列化以及在1M以内,如果超过了1M或者结果不能序列化,那么就直接将结果录制为null。这一点可以从AREX的日志中体现:
如果出现了这种录制情况,一般情况下,我们的回放是失败的。因为在回放时value为null,我们的业务代码就不会走缓存,而是走诸如查库等逻辑,但实际上查库的逻辑在录制时并没有,此时就会出现new call或者查库报错。
8、某方法想配置为动态类,但方法本身没有返回值
9、录制的对象中缺失了部分字段
一般情况下,出现这种问题的原因如下: