如何减少创建订单、支付等线上写场景漏测?去哪儿流量录制回放实践
一分钟精华速览
流量录制与回放技术在故障排除、性能优化和升级迁移等方面具有重要的应用价值。流量录制是指记录网络通信过程中的数据包,包括请求和响应数据,以便后续分析和调试。流量回放则是将录制的数据包重新发送到网络中,以模拟真实的网络通信环境,验证网络应用程序的性能和稳定性。
本文以去哪儿网为例,介绍流量录制与回放实践,探讨其在接口自动化测试和全链路压测中的应用成效。
作者介绍
去哪儿高级 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 稳定性社区」联合社区专家共同原创撰写,如需转载,请后台回复“转载”获得授权。
版权声明: 本文为 InfoQ 作者【TakinTalks稳定性社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/c4cbc0baff16f0f713c209773】。文章转载请联系作者。
评论