一分钟精华速览
流量录制与回放技术在故障排除、性能优化和升级迁移等方面具有重要的应用价值。流量录制是指记录网络通信过程中的数据包,包括请求和响应数据,以便后续分析和调试。流量回放则是将录制的数据包重新发送到网络中,以模拟真实的网络通信环境,验证网络应用程序的性能和稳定性。
本文以去哪儿网为例,介绍流量录制与回放实践,探讨其在接口自动化测试和全链路压测中的应用成效。
作者介绍
去哪儿高级Java研发工程师——沙丹丹
TakinTalks社区专家团成员。2017年加入去哪儿,致力于提升研发和测试人员的效率。在CICD、测试工具领域有丰富的经验,负责去哪儿网写接口自动化测试从0-1的落地、写场景全链路压测从0-1落地。
温馨提醒:本文约4500字,预计花费8分钟阅读。
后台回复 “交流” 进入读者交流群;回复“5131”获取课件资料;
背景
去哪儿网是一种漏斗形业务结构,从搜索、生单到支付,其QPS是逐渐降低的,所以前几年我们更关注漏斗顶端的读场景测试,即搜索环节的测试。而生单和支付这类写场景的测试,因为测试数据构造困难、维护成本等各类原因,此前去哪儿网写场景的测试能力不够完善,很多系统的写接口只能依靠人工测试。
而人工测试的弊端是非常明显的,比如系统改动大、改动频繁,容易发生漏测等。这就会导致故障频发,甚至影响用户的出行和体验。
(去哪儿网某小部门近一年的故障列表)
从故障发生列表可以看出,在接入写接口自动化测试之前,平均每个月都会发生2~3个故障。深入分析这些故障,基本上都是由于数据和环境不足,导致某些特殊Case场景没被测试到,或是某些回归Case漏测导致的。
基于以上的痛点,去哪儿将两种主要的写场景测试方案进行了对比。综合对比构造Case成本、下游数据Mock成本、维护成本等各方面,最终我们选择应用录制回放技术。
我接下来将分享录制回放技术在去哪儿的具体落地,主要包含该技术在接口自动化测试、全链路压测中的应用和落地效果。
二、技术方案如何选择和演进?
阶段一:Areas(二开JVM-Sandbox)
阿里在2017年开源JVM-Sandbox,去哪儿网基于它开发了自动化测试工具Areas。但在使用过程中,此工具有一定的局限性。比如,工具使用方需要引入jar包接入成本高,工具维护方需要开发对应的插件,开发成本高。
阶段二:Q-Thanos-Agent(二开JVM-Sandbox-Repeter)
后来在2019 年阿里又开源了一个专门做录制回放的JVM-Sandbox-Repeater。其优势是有阿里开源社区的支持,可靠性比较高。它可以开发自定义插件,扩展性很强,整体开发成本较低,可以快速落地实现。
而由于它有两层封装——底层是 JVM Sandbox,上一层是Repeater。为了实现跨线程录制,牺牲了一部分性能,所以对QPS较高的服务会有一定性能影响。目前去哪儿网仍在使用该Agent,后面我也将介绍其具体性能影响。
阶段三:Cinema-Agent(自研)
由于要将录制回放技术应用到全链路压测的场景中,所以对于 Agent 的性能有了更高要求,因此去哪儿网自研了Cinema-Agent。其优势是它是完全自研的,与公司的基础组件结合性更高,开发人员的开发和维护体验会更好,性能也会更好。目前为止,去哪儿在线上的所有应用都安装了此Agent,暂未发现性能瓶颈。
阶段二和阶段三的两个Agent目前都在使用中,只是用途和场景不同——Q-Thanos-Agent主要应用于写接口的自动化测试,Cinema Agent 主要应用于写场景的全链路压测。接下来我将分别介绍这两个 Agent 的应用。
三、录制回放技术在接口自动化测试中的应用
3.1 支持的功能
写接口的特点是对于同样的参数,多次请求的返回数据是不幂等的。目前去哪儿接口自动化测试支持的功能如下:
1)读接口的自动化回归测试。其测试方式是直接发起请求。
2)写接口的自动化回归测试。它使用的技术就是录制回放。
3)应用配置修改自动化验证。
3.2 测试流程
整体的测试流程是用户首先在自动化测试平台里新建应用配置,包括接口配置还有录制回放的配置。
在正式测试阶段,首先是触发测试。然后生成Case,同时会部署它的环境。然后执行Case。最终将执行 Case 的结果进行Diff,然后生成测试报告。
3.3 录制回放实现原理
3.3.1 JVM-Sandbox-Repeater 的原理
在沙箱的世界观中,任何一个 Java 方法的调用都可以拆分出三种事件——Before、Return 和Throw。比如,在执行行为A之前,可以获取其 Before 事件,拿到URI和请求参数。在行为A执行完成后,就把这种事件叫做 Return 事件,探测到 Return 事件时,我们可以获取到该方法的返回值。执行行为A的过程中如果抛异常,此时就是会发生一个Throw事件。由此我们就可以得到一个 Java 方法的 URI、Request 和 Response 来实现对行为 A的录制。
比如一个线上服务 Service A,它上面装了一个Repeater Agent。当一个 HTTP 的外部请求进来时,我们就可以得到这个请求的 URI、 Request。如果外部请求又调了Service B或Service C,或者是进行了 Redis/ MySQL 数据库的查询修改,也同样可以得到这些子调用信息,并把请求参数和返回值录制下来。
最终就可以得到一份完整的录制信息,包括入口的 URI 、Request和Response,各个子调用的 URI 、Request和Response。
3.3.2 Agent二次开发
基于以上Agent,我们二次开发了Q-Thanos-Agent。去哪儿有很多的自定义组件,如HTTP、Dubbo、Redis等等,我们对这些组件都进行了自定义的二次开发。具体开发情况如图。
3.4 写接口自动化测试过程
3.4.1 录制回放流程
我们会在选择一台线上机器,安装Repeater Agent来实现线上流量的录制。并在两个 Beta 环境安装Repeater Agent。其中一个Beta环境部署的是 Master代码,可以把它作为基准环境。另一个Beta环境部署的是分支代码,可以把它当做真实的测试环境。
通过Wed端自动化测试平台,从线上的录制数据中筛选和捞取一批Case,再将这些 Case 分别对两个测试环境发起请求。当这两个环境机器上的 Agent 识别到回放请求时,就会从数据中心拉取录制数据。然后对这些入口和子调用进行回放,最后将回放的数据也上报到数据中心。
自动化测试平台从数据中心把这两个环境的回放数据拉取回来,然后将它们的接口返回值和每个子调用的入参进行Diff,最终生成一个测试报告。
3.4.2 自动化测试平台架构图
基于以上测试流程,我们把系统划分成三个部分。
第一部分是控制测试流程的 Web 端服务,包括配置管理和整个测试流程的控制。
第二部分是数据中心,用来保存录制数据和回放数据的。
第三部分是录制回放的Agent,它是挂载在业务应用进程上的。
(自动化测试平台架构图)
3.4.3 录制数据样例
该录制数据的样例,包括入口URL、请求参数、返回值,还有这个入口下面的所有子调用。
3.4.4 回放数据样例
该回放数据的样例,包括两个环境的回放数据,一个是基准环境的回放数据,一个是测试环境的回放数据。而且可以提供这两个环境回放数据入参的Diff。点击环境参数就可以看到这个 URI 对应的参数。如果某一个子调用在某一个环境没有回放也可以提示。
3.5 落地效果
3.5.1 正面业务效果——
a. 已接入应用(核心应用200个,包括读写应用):35个
b. 已接入写接口:296个
c. 新接入一个接口的50个Case时间成本:从1pd降低到1h
d. 故障率:0.28%降低到0.18%
3.5.2 负面性能影响——
a. 单机QPS超过200的应用刚启动会有JIT问题,如果应用没有预热逻辑,会导致业务接口超时;
b. CPU使用率上涨 :1%~3%;
c. 内存上涨:3%~5%;
四、录制回放技术在全链路压测中的应用
4.1 应用背景
近几年去哪儿网所在的出行业务有明显的波动,所以我们做了很多降本提效的工作,比如集群缩容、系统重构、系统精简、代码瘦身等等,业务系统的变化是非常大的。在流量上涨(比如节假日)或者秒杀活动时(比如机票盲盒),这些写场景的业务系统如果不进行一轮压测,当流量上涨时能不能承受住冲击,其实大家心里是没有十足把握的。所以亟需实现一套写场景的压测方案。
写场景会存在返回结果不幂等的问题,比如,用相同的参数生单,第一次生单成功,但第二次生单可能就会失败,会校验出来是个重复的订单。所以写场景中我们又用到了录制回放技术,来解决接口和数据Mock的问题。
4.2 全链路压测Web系统结构
整个系统包括写场景创建、影子库管理、挡板配置、挡板调试、入口 Case生成、子调用预热、触发压测、生成压测报告等等这些小模块。
除了Web 端的录制回放中控以外,我们还在业务系统上挂载了一个 Cinema Agent,这个 Agent 和业务进程在同一个 JVM 里。数据中心用来保存录制数据,录制的原始数据保存在ES中,入口Case的数据会导入MySQL 中。
在压测时,我们要尽量减少回放的延迟,所以会首先把子调用预热到 Redis中,来降低由于回放造成的延迟。
4.3 全链路压测录制回放流程
去哪儿是在线上环境进行的真实流量录制,也是在线上环境进行流量压测。比如,一个用户在线上真实下单时,我们可以识别到这是一个需要录制的入口请求,此时根据当前采样率看这条请求是否需要被采样。如果是,则会给它生成一个唯一标识。这个唯一标识会被带到这个入口请求的下游去,下游的每一个系统都可以识别到这是需要被录制的流量,把需设置挡板的地方录制下来。
比如,B调D这个子调用在压测时不能让它真实调用下去,我们可以提前把它设置成挡板,在录制时,走到这个子调用时就会自动录制下来,录制信息包括唯一标识、应用名、调用类型、URI、Request、Response、是否是入口等。
在真实的压测阶段,压测平台会从数据中心导入一部分入口Case,然后将这些 Case 以一定的 QPS 压测下去。在压测系统模拟下单时,会识别到这是一次压测的流量。如果某个子调用设置了挡板(比如:B调D),Agent会识别到这是一个需要被回放的调用,就会从数据中心的录制数据中获取该调用的返回值,直接返回回去,实现Mock的效果,就不会真实调用到D了。
对于数据库的操作,我们线上有影子 Redis 和影子的MySQL。写操作是直接写到影子 Redis 里。读操作现在是会录制 Redis 的Get、Exist等,通过设置挡板的方式实现录制。对于MySQL,写操作会写到影子库,读操作会优先读影子库,如果影子库里面没有这份数据,就会 Call Back 到线上库。
以上就是整个压测的流量录制和回放的流程。
4.4 痛点/踩坑分享
4.4.1 痛点1:挡板配置梳理
问题:写场景一般是指下单、支付、发短信等对用户有实质上影响的操作,在全链路压测时,有些行为需要Mock。比如:调代理商占座、下单、真实支付、重复单校验、订单状态校验、订单状态修改等,这些操作不能真实去调用。那我们如何能够把这些挡板设置上去?
方案一❌:业务同学梳理挡板,缺点是链路长,涉及100多个应用,完全由人工梳理不全。如果某个挡板没有设置,则会导致压测流程不通。
方案二✅:半自动化设置挡板
首先设一个全局公共挡板,用来拦截所有外网调用,保证不会请求到外网。接着按照以下流程进行调试。
回放1个case,针对业务不通的地方设置挡板的这个操作流程不断重复,最终就可以把一个链路调通。即采用的是快速调试,每次用一个 Case 来探索哪个地方应该设置挡板,不断地重复,直到多个Case都能够顺利地走完业务流程,才算调试结束,以此来保证挡板不遗漏。
4.4.2 痛点2:子调用回放 Response选择
问题:设置档板时,同一个接口或redis.get()可能会调用多次,每次的参数和返回值可能有差异,如何保证正确选择返回值?
方案一✅:按录制顺序回放(默认策略)
方案二✅:取第一次或最后一次结果回放
适用回放时的调用次数比录制时的调用次数多。
很多并发场景下,同一个URI的子调用会录制多次,且录制的顺序和回放时的调用顺序是不一样的。比如,同时生成3个子单,但是其顺序是并行的,没有前后之分,此时则可按参数相似度来模糊匹配。
这里提供两种计算相似度的算法。第一种是简单算法——汉明距离,两个字符串截取最短的字符串的长度,将这两个截取后的字符串进行对比。其缺点是误差较大。第二种是复杂算法,用JSON里相同 Value 的字段占比来计算相似度。比如,一共有 20 个参数,其中10 个都是相同的,则其相似度占比就是50%。此时选取一个相似度最高的返回值即可。
4.5 落地效果
4.5.1 正面业务效果
a. 解决了写压测不能创造流量的痛点
b. 已接入机票业务线写场景:8个(生单、支付前校验、支付、机票盲盒活动等)
c. 最长生单链路应用个数:100+
d. 一个链路首次接入平均调试时间:5pd
e. 压测目标流量:2倍+
f. 压测数据录制+准备时间:40min内
g. 压测Case成功率:95%+
h. 压测过程中,有发现业务系统异常量上涨,真正发现了问题
4.5.2 负面性能影响
a. Cinema Agent对业务系统基本无性能影响
五、总结与展望
目前Q-Thanos-Agent和Cinema Agent去哪儿都在使用中。
Q-Thanos-Agent主要应用于写接口的自动化测试。其使用方式是在线上环境的机器进行录制,在 Beta 环境进行回放,适用于单机 QPS 不高的写场景。也正在探索其他的使用场景,比如用在精准测试中。
Cinema Agent 主要应用于写场景的全链路压测。这个Agent是所有应用都安装的,适合对性能要求高的场景。正在探索应用在接口 Mock 平台。
未来去哪儿可能会将 Q-Thanos-Agent 的功能合并到 Cinema Agent 里。一方面是为了精简安装到业务服务上的 Agent 个数,另一方面是为了在相同功能的改动时,保证逻辑统一,更易于维护。(全文完)
Q&A
**1、压测的时候是否支持回放历史数据?
2、对于流程式的场景如何获取上一步的业务数据?在录制的数据中要进行脱敏处理吗?这个数据会和真实的服务器会交互吗?
3、订单号在不同的环境中,如何保障生成的是一致的?**
更多详细内容,欢迎“点击跳转”,观看完整版解答!
添加助理小姐姐,凭截图免费领取资料
并免费加入「TakinTalks读者交流群」
声明:本文由公众号「TakinTalks稳定性社区」联合社区专家共同原创撰写,如需转载,请后台回复“转载”获得授权。
本文由博客一文多发平台 OpenWrite 发布!