cover_image

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

罗曼 群核科技质量技术
2024年11月29日 08:45

一、前言

酷家乐的流量回放平台kurepeater是在jvm-sandbox-repeater基础上做的二次开发。为何选择它,感兴趣的可以看前文:流量回放框架jvm-sandbox-repeater的实践一

kurepeater由repeater-console和repeater-agent组成。repeater-console用来对配置、录制回放操作、流量等进行管理,repeater-agent基于JVM-Sandbox用于在目标服务器上进行录制回放并将结果上报到repeater-console。虽然平台一直在迭代优化,但基本框架没有太大变化(见文章:流量回放框架jvm-sandbox-repeater的实践二)。这两年为了更好地落地我们做了很多的尝试,在此分享一下,给有需要的人做个参考,也欢迎有更好的建议。文章较长,大家可以根据标题挑着看。

言归正传,要讨论流量回放平台,我们首先要意识到一点:在某种程度上,流量回放对测试来说,虽然有用,但并不是一种绝对必需的手段。所以要想将流量回放在测试甚至研发间推广开来并日常迭代中使用存在不小的难度。这要求平台需要具备如下的特点:

易用:易上手、操作便捷。操作流程越简洁越好,失败排查越方便越好;

稳定:录制和回放的流程不要无故异常,且对服务的影响尽可能降低;
可靠:case稳定,不要频繁无效失败,浪费时间排查。

为此,我们的主要改进一直围绕着提升易用性、提高稳定性、降低误报率来进行。期间的新尝试和小优化有很多很多,下面主要提取一些比较大的改动或者效果比较明显的优化进行介绍。

二、提升易用性:

1、自动录制和回放

为了尽可能减少使用者的使用难度和操作成本,我们做了很多的一键化操作和自动化操作。以往我们需要录制回放一次的操作流程大致如下图,整个流程较长且不连贯,使用体验较差。

图片

现在,我们只需进行一次操作,并静待系统通过企业微信通知录制和回放结果即可。中间所有的操作都由平台来自动操控完成。

图片

另外我们还加了定时录制和测试集(将多次录制的流量筛选后关联在一起)的定时回放功能。这些操作都可以很大程度减少人为流程介入频次。

2、融入CI流程,打通精准测试平台和kaptain平台

虽然加了自动录制和回放,但是kurepeater上录制回放和日常研发迭代还是有点割裂的。使用定时任务,可能会出现需要回放的时候没有触发回放,服务没有迭代更新它却回放的情况。为此kurepeater又和公司内部多个其他平台进行了打通,将流量回放融入CI流程。

具体流程如下图所示,已知每个迭代的需求代码在提测后在测试环境、集成环境、预发环境、线上环境依次流转。我们将流量回放做如下切入:

  • 新代码上线后,自动触发流量录制,并在清洗后存储下来作为下个迭代的回放流量。

  • 当下个迭代当代码流转到集成环境时,自动触发对集成环境进行流量回放。回放结束进行企信通知。

图片

至于是否提测后直接跑流量回放,平台支持配置化添加(因为一些特殊原因,暂时无法统一)。另外,如果希望有更多的流量用于回放,或者对流量有更精细的需求,也支持将多次录制的流量保存成测试集,并配置CI流程中自动回放时使用测试集流量。

对于回放结果,我们使用企信进行通知。同时在发布报告中也加了流量回放信息,引导排查。融入CI后,kurepeater的使用量上升非常明显。

3、降低排查难度

jvm-sandbox-repeater相比于goreplay等流量回放工具来说,成也mock败也mock。mock的能力使得流量回放可以跨环境,摆脱对数据的依赖,摆脱只能回放查询接口的限制。但是mock也使得回放的失败变得复杂,排查难度大大增加。
常见回放的失败原因除了代码bug导致回放结果和录制结果不一致外,还可能有:
1)业务代码中存在特殊逻辑或初始化配置不一致的情况,导致后续mock匹配失败,致使回放会失败;

2)因代码改动新增了插件调用,或者录制回放启用插件不同,导致子调用无法mock上,回放失败;

3)中间子调用的参数是随机生成的,或者时间戳相关的,导致mock匹配不上;

4)正常业务逻辑导致过程值或者响应值变化,比如代码中判断会员时间还剩几天,它是和当前时间对比的,肯定每天都会变化,导致回放结果和录制的不一致。

多样的失败原因使得初步排查变得有难度,特别是对新上手的人来说更是一头雾水。为了方便排查,我们设计开发了如下的一些能力:

1)结合精准测试平台,识别出本次改动到的接口。这些接口优先排查,其他失败的接口可以慢慢解决。

图片

2)增加调试功能,类似postman。点击立即自动填充请求接口、参数、header等信息,可自动选择host发起接口请求。如此方便快速判断出是因为mock引入的失败,还是业务代码的问题。

图片

3)支持查阅mock信息。通过该信息我们可以清晰的看到是在哪里没有mock上,参数是什么,整个代码调用栈是怎么样的。这样结合业务代码可以快速识别出来执行到哪一行出错,为什么没有mock上。

图片

4)关联服务日志和全链路调用链。可进一步结合服务错误日志等信息进行判断失败原因。

图片

此外还有很多其他的小手段用来一起降低排查难度,这里就不赘述了。当然相比降低排查难度,后面会提到的减少误报减少排查次数更重要。

4、接口采样率自动设置

 一般线上各接口流量是严重不均衡的,这会导致流量录制时高频接口录制了一堆,低频接口可能一次都没录到。这样子录制的流量回放价值会大打折扣,也很浪费存储资源。前文流量回放框架jvm-sandbox-repeater的实践二中我们加了接口级别采样率配置功能,希望使用者自行合理配置。但是很多服务有好几百个接口,迭代中又不断有接口新增和下线,另外一天中不同时间段接口流量也不同。如果每次录制时都配置一遍就太麻烦了。即便加了一键自动重新配置落地效果也并不是很理想。为此我们一步到位,直接在每次开启录制流量任务时自动根据监控流量情况重新设置采样率,无需人工干预。使用下来,效果很好。主要计算规则代码如图:

图片

三、提升稳定性:

1、优雅录制和优雅冻结

流量回放的流量最好肯定是来自线上用户的真实行为流量。但是repeater在启动时会对应用的 CPU 使用率、响应耗时产生冲击,极易引起线上服务和其上下游服务出现报警。

为此,我们在线上录制时,先通过修改线上服务在soa中的版本将流量切走,等repeater-agent激活完毕后,再将流量慢慢放进来。流程如下图:

图片

repeater-agent冻结时,对监听方法的释放也会对服务有些影响。为此录制结束时,prod环境也需要先将流量切走,然后再冻结,再将流量切回来。

当然还有一种更好的方案是新起一个pod来安装激活repeater-agent,激活后再导流过来录制流量,录制结束后再将pod回收。这样对线上影响更小。

2、识别接口是否只读

kurepeater支持mock回放和不mock回放。有的测试场景只能不mock回放,但是回放时不mock又会有污染数据的风险。所以不mock回放时,最好只回放只读接口。这需要平台最好能够识别出来哪些接口是只读的,哪些不是只读的。因为开发写代码可能不规范,不能武断的认为get接口就是只读的。但好在流量录制的时候信息很全,不但接口请求参数都记录了,所有子调用的请求参数和响应也录制了。我们可以依据这些信息对流量是否只读进行初步的判断。

我们将流量分成3类,只读(GET)流量,非只读流量(POST),无法判断的流量(OTHER)。大致逻辑是:如果有一条流量,他的接口请求方法是GET或者POST,他的所有子调用中有一条写的子调用,那我们就判定这条流量是非只读流量;部分情况下无法判断的就判定为无法判断的流量;其他情况判定为只读流量。对于DELETE和PUT接口,我们都判定为非只读流量。

另外在录制的流量详情页界面上展示给使用者。支持使用者自行判断修正,当某个接口人工判断为只读,那么后续该接口的流量就都是只读流量。

图片

全局配置界面如下图:

图片

如此,当知道了哪些接口是只读接口,我们就可以放心的进行不mock回放或者直接预发环境回放了。

四、降低误报率

1、java方法的mock

流量回放框架jvm-sandbox-repeater的实践二中,我们基于diffy,使用了降噪回放。回放成功率提升明显。但是当时也发现这种方式存在几个问题:

1)多一个环境,不确定性变高;

2)会损失掉很多的流量,导致很多接口没法回放到;
3)会出现回放失败但是降噪后误判成功的情况。

作为一种测试手段,肯定是期望他尽可能的回归全面。所以还是应该想办法将原本会回放失败的变成回放成功。这里我们开放了开源框架原本就支持的java方法mock能力,并支持配置化。如图,searchLatestRecommend方法里面有2个随机的逻辑,那么每次调用searchLatestRecommend返回的值不一致,也就导致接口响应也会不一致。由于Collections.shuffle()方法无法修改,那么就对searchLatestRecommend方法进行mock。

图片

图片

如此,后续录制回放就可以mock上了。

图片

另外,我们对公司内常用的一些类和方法在配置查询中进行统一增加。

对不稳定的方法进行了mock,可以大大的提升回放成功率。但是java方法mock不是对所有方法都生效,有的方法不支持修改,如private类、native类、private方法、final方法等。我们可以对上层方法或者对这些方法再封装个方法再进行mock。

2、响应结果比对优化

回放是否成功,最终靠的是结果的比对。结果的比对,既要考虑性能,也要考虑效果。

1)很多请求的响应特别大,逐个字段去比对非常吃资源。为此平台加了一些前置的快速比较,比如对于响应体较大的情况下,字符排序后完全一致,我们就认为响应一致;有大于10%的差别,直接判断响应不一致。

2)list比较时,需要忽略顺序。
3)逐个字段比较时,对于一些时间相关的字段直接进行忽略。
4)另外,因为业务代码本身存在逻辑,所以响应中有些字段可能就是没法保证录制回放一致。为此除了对响应进行完全比对校验外,kurepeater也支持自定义校验,提升回放成功率。

图片

3、其他

此外,还有一些其他小功能用于提升回放成功率。例如:

1)黑名单:流量回放毕竟不是万能的。部分服务或者部分接口因为一些原因,确实不好支持,或者支持的话需要业务代码做大改动。为此加了服务级别和接口级别的黑名单功能。

2)对公司内会用到的一些常用插件进行了添加或者优化,当前已支持28个插件。默认全部加载,支持自行配置是否启用。

通过治理,流量回放的整体回放成功率已经处于一个比较高的水平。如图是融入CI流程自动触发的回放。

图片

五、总结

除了上面提到的改动,其他的动作还有很多,有兴趣的可以留言讨论。虽然平台的整体能力建设已基本完成,但是更多的插件支持,更多的编码方式支持,更多的细节的调优,更多衍生能力的探索,以及怎么更好的融入研发迭代都是可见的工作。

最后,像文章开头说的那样,流量回放对测试来说很多时候是一种有用但不是必须的回归手段,所以平台的做的再好,也需要一些流程机制来保证它的落地。这个就需要根据每个公司的实际情况来进行调整。



推荐阅读

继续滑动看下一个
群核科技质量技术
向上滑动看下一个