试试流量回放,不用再写烦人的自动化测试case了

接触过接口自动化测试的同学都知道,我们一般要基于某种自动化测试框架,编写自动化case,编写自动化case的依据来源于接口文档,对照接口文档里面的请求参数进行人工添加接口自动化case

其实,对于日常新的服务端需求的迭代,人工一次性补充20个以下接口自动化case,还是可以接受。如果一次性要补充50个以上的接口case,光靠人工去填写就显得非常耗时

还有一种比较常见的场景,一些老的服务模块需要进行迁移或者是重构,这些老模块本身可能也没有接口文档,业务逻辑也没有改变,如何确保原来业务在迁移后的正确运行非常重要,光靠QA进行接口测试也很难保障迁移后的新服务线上没有问题

为了最大程度的覆盖测试,我们可以通过复制线上流量拷贝到线下生成自动化case进行接口的功能测试以及diff测试,这种技术就叫流量回放

什么是流量回放

流量回放从字面意思理解,流量可以理解成互联网上发送和接收数据的量,由于我们网络通信协议一般都是HTTP请求,前后端交互方式一般通过后端API接口,所以流量的形式可以理解成线上的接口请求数量

而回放就是改变接口请求信息的位置,比如存放在到线下的数据库,Redis,或者分布式大数据集群中,也可以不经过存储进行实时回放,使得我们能够对线上流量进行利用

流量回放再通俗理解成两个字,就是引流

流量回放可以将流量进行拷贝后直接使用,也能把流量放大、流量缩小后使用

流量拷贝指的是将线上正式流量通过改写业务逻辑tcpcopy日志回放等方法在线下环境回放,从而达到测试的目的

流量拷贝可以完全模拟线上的流量,从而对复杂的业务场景进行仿真测试,并且不会对线上服务产生影响

一份流量复制多份,每份流量经过修改目的地址后发送到同一台实例上,比如拷贝5份流量到同一台实例,这台实例就能比线上环境同一时间多抗5倍压力,就能实现对线下环境进行压测,这就叫流量放大

那有小伙伴问,能放大,可以缩小吗?当然可以,流量缩小是通过复制部分流量并对其进行处理,以实现流量的缩小。这样做的原因可能是为了减少流量的规模或为了对流量进行进一步的分析和处理

在线下测试中难以覆盖的场景,都可以通过流量拷贝的方式来测试,测试的场景更广泛,覆盖面也更大

业界经验

目前业界也有一些常用的引流解决方案

阿里Doom

Doom是一个将一部分线上真实流量复制并用于自动回归测试的平台。其在应用内部通过aop切面编程方式实现的流量录制和回放功能,由于最底层借助了java的instrument实现aop,因此目前仅支持java应用的接入使用。其原理图如下:

图片

TCPCopy

TCPCopy是一种请求复制 (所有基于tcp的packets) 工具,由tcpcopy和intercept组成,其中tcpcopy在线上服务上运行并利用原始socket复制线上流量到测试服务上 (粉红色的线),intercept部署在辅助服务器上,负责接收响应(绿色的线)并回传给tcpcopy (紫色的线),具体见下图:

图片

GoReplay

Goreplay是用 Golang开发的 HTTP 实时流量复制工具。支持流量的放大、缩小,频率限制,还支持把请求记录到文件,方便回放和分析,也支持和 ElasticSearch 集成,将流量存入 ES 进行实时分析GoReplay不是代理,而是监听网络接口上的流量,不需要更改生产基础架构,只需与服务相同的计算机上运行 。具体原理见下图

图片

GoReplay原理

Nginx的ngx_http_mirror_module模块

Nginx 1.13.4 中引入ngx_http_miror_module模块来支持应用层的流量复制。该模块通过mirror配置指令来实现流量复制。如下图,可以通过下面配置来实现复制proxy.local流量到test.local

图片

  1. upstream backend {

  2. server backend.local:10000;

  3. }

  4. upstream test_backend {

  5. server test.local:20000;

  6. }

  7. server {

  8. server_name proxy.local;

  9. listen 8000;

  10. location / {

  11. mirror /mirror;

  12. proxy_pass http://backend;

  13. }

  14. location = /mirror {

  15. internal;

  16. proxy_pass http://test_backend$request_uri;

  17. }

  18. }

其中每一条mirror配置项对应用户请求的一个副本,可以通过配置多次mirror指令来实现“流量放大”的效果。当然,你也可以将多个副本转发给不同的后端目标系统

流量回放的三种方式

从引流自身来看,主要有3种类型,分别是:主路复制、旁路复制、日志回放

主路复制:

图片

主路复制

主路复制指的是在调用链中进行流量拷贝。一种是在业务逻辑中进行流量复制,比如在调用API的过程中,由业务方编写代码逻辑记录请求/响应信息内容;另一种是在框架(如阿里的Doom)处理逻辑中进行流量复制。

  • 优点: 可以高度结合业务逻辑,实现细粒度定制化流量复制,比如可以只针对某些特征的流量进行复制

  • 缺点: 业务逻辑与引流逻辑耦合度较高,功能上相互影响;每个请求都需要进行额外引流处理,对业务流程存在性能影响

旁路复制

图片

旁路复制一般是由第三方服务在网络协议栈中,监听复制流量,对业务无感。比如TCPCopy,相似的工具还有GoReplay

  • 优点: 与业务解耦,可以独立部署升级引流模块,业务方需关注引流功能实现

  • 缺点: 4层网卡层面的网络包抓取后,仍需要进行数据包重组和解析,需要额外的消耗计算资源,往往需要全量抓包解析再进行筛选,无法结合业务逻辑进行定制化的采样

基于网关的业务特点:1) 流量大,无差别的抓包、解包筛选会消耗大量CPU,2) 承接所有产品线的流量,需要提供特定产品线的流量复制能力

特别注意:流量复制是在线上服务上进行的,因此会消耗线上机器的CPU资源,为了不对线上业务带来影响,需要在流量复制时监控线上机器的资源使用,一旦资源消耗太多时需要立即停止流量复制

日志回放

日志回放有点类似旁路复制,但是不再监听网络协议请求,而是在线上服务实例放一个log agent,通过它来将日志转存到大数据分布式集群当中

使用日志回放的前提是,业务代码逻辑当中需要打印的日志,需要包括接口的请求参数,URL,Body,请求方式等必要的接口信息,如果没有打印接口信息的日志,则无法进行日志回放

所以要采取这种回放方式,第一步就是需要开发去协助规范日志

图片

在HDFS/AFS集群当中存放日志以后,就能部署一个hadoop client 用来拉取集群上的日志,并对日志进行处理,解析出接口请求信息,有必要时需要对流量进行筛选后,再进行回放

下面分享一个使用Python多进程,解析日志获取流量的demo程序,假设现在已经从集群上拉下了日志,日志目录结构如下:

图片

每一条日志文件service.log.wf.2023072615.18里面的内容为:一行接着一行的warning日志,部分warning日志带有接口信息

  1. WARNING 247629242023072613:00:24 Present.php:44 qa_traffic_playback: {"request_method":"POST","service_method":"getUserInfo","path":"\/service\/test?ngscfr=getUserInfo_10.221.110.27_fm_smallapp&method=getUserInfo&format=php&ie=utf-8","query":{"ngscfr":"getUserInfo_10.221.110.27_fm_smallapp","method":"getUserInfo","format":"php","ie":"utf-8"},"post":{"account_id":"59","account_type":"1","user_id":"123456","method":"getUserInfo","format":"php","ie":"utf-8","service_array_key":"a:0:{}","tb_sig":"7f2fcc8b398ca16979"}}

  2. WARNING 247629242023072613:00:24 Present.php:44 qa_traffic_playback: {"request_method":"POST","service_method":"getUserInfo","path":"\/service\/test?ngscfr=getUserInfo_10.221.110.27_fm_smallapp&method=getUserInfo&format=php&ie=utf-8","query":{"ngscfr":"getUserInfo_10.221.110.27_fm_smallapp","method":"getUserInfo","format":"php","ie":"utf-8"},"post":{"account_id":"59","account_type":"1","user_id":"56789","method":"getUserInfo","format":"php","ie":"utf-8","service_array_key":"a:0:{}","tb_sig":"7f2fcc8b398ca16979"}}

 
  1. import os

  2. import re

  3. import json

  4. import multiprocessing

  5. def parse_log_file(log_file):

  6. log_entries = []

  7. with open(log_file, 'r') as file:

  8. for line in file:

  9. if'{"request_method"'in line:

  10. # 使用正则表达式匹配 JSON 字典

  11. pattern = re.compile(r'{.*?}}')

  12. match = pattern.search(line)

  13. if match:

  14. json_dict = match.group()

  15. print("json_dict",json_dict)

  16. # 解析 JSON 字典

  17. data = json.loads(json_dict)

  18. print("data",data)

  19. print("解析 JSON 字典",json_dict)

  20. return log_entries

  21. def process_directory(directory, results_dict):

  22. log_files = []

  23. for root, dirs, files in os.walk(directory):

  24. for file in files:

  25. if file.startswith('service_present.log.wf'):

  26. log_file = os.path.join(root, file)

  27. log_files.append(log_file)

  28. # 在这里处理每个匹配到的日志文件

  29. print("log_files B", log_file)

  30. parsed_entries=[]

  31. for log_file in log_files:

  32. parsed_entries += parse_log_file(log_file)

  33. results_dict[directory] = parsed_entries

  34. if __name__ == '__main__':

  35. root_directory = '/home/work/'# 指定根目录

  36. results = multiprocessing.Manager().dict()

  37. processes = []

  38. for subdir in os.listdir(root_directory):

  39. directory = os.path.join(root_directory, subdir)

  40. if os.path.isdir(directory):

  41. process = multiprocessing.Process(target=process_directory, args=(directory, results))

  42. processes.append(process)

  43. process.start()

  44. for process in processes:

  45. process.join()

  46. for directory, entries in results.items():

  47. print(f'Directory: {directory}')

  48. for entry in entries:

  49. print(entry)

解释一下这个程序,process_directory方法用来遍历日志目录,获取日志文件的绝对路径,parse_log_file方法用来解析对应路径下的日志文件,利用正则表达式提取出日志里面含接口信息的Json字符串,并转化为字典存放

后续逻辑则是可以读取字典里面的信息,生成接口自动化case进行接口自动化测试或者diff测试

这段代码片段还有可以优化的地方,因为存在在dict字典里,是直接占用内存,如果接口信息过多,可能会出现内存占用过高,内存被打爆的情况,这时候可以选择将接口信息存入数据库或者Redis

最后再提一嘴,在实际应用过程当中,我们可能还要利用算法进行流量筛选,经过初筛和精筛拿到指定的流量,另外还需要统计回放下来的流量覆盖率,这样才能比较准确的衡量流量的覆盖程度

行动吧,在路上总比一直观望的要好,未来的你肯定会感 谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入扣群: 320231853,里面有各种软件测试+开发资料和技术可以一起交流学习哦。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/549232.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue3(二):报错调试,vue3响应式原理、computed和watch,ref,props,接口

一、准备工作调试 跟着张天禹老师看前几集的时候可能会遇到如下问题: 1.下载插件:Vue Language Features (Volar)或者直接下载vue-offical 2.npm run serve时运行时出现错误:Error: vitejs/plugin-vue requires vue (>3.2.13) …

Python 入门指南(五)

原文:zh.annas-archive.org/md5/97bc15629f1b51a0671040c56db61b92 译者:飞龙 协议:CC BY-NC-SA 4.0 第十六章:Python 中的对象 因此,我们现在手头上有一个设计,并且准备将该设计转化为一个可工作的程序&a…

解决npm run dev跑项目,发现node版本不匹配,怎么跑起来?【已解决】

首先问题点就是我们npm run dev 运行项目的时候发现出错,跑不起来,类型下面这种 这里的出错的原因在于我们的node版本跟项目的版本不匹配 解决办法 我这里的问题是我的版本是node14的,然后项目需要node20的,执行下面的就可以正…

JavaScript事件监听测试代码

效果图 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>信息填写页面</title><link …

Linux 内核学习(2) --- regulator 框架

目录 Regulator 介绍Regulator provider 注册struct regulator_descstruct regualtor_configDTS 配置和解析On BoardConfig 配置regulator_ops总结 Regulator Consumer 使用struct regulator 获取regulator 操作使用Multi Regulator 参考博客 Regulator 介绍 Regulator 指的是…

黄金价格上涨对白银的影响是什么?

在金融市场上&#xff0c;黄金与白银通常被视为避险资产&#xff0c;它们的价格走势往往受到多种因素的影响。近期&#xff0c;随着全球经济的波动加剧&#xff0c;黄金价格出现了上涨趋势。这自然会对与之紧密相关的白银市场产生影响。具体来说&#xff0c;黄金价格上涨通常会…

华硕ROG幻16笔记本电脑模式切换管理工具完美替代华硕奥创中心管理工具

文章目录 华硕ROG幻16笔记本电脑模式切换管理工具完美替代华硕奥创中心管理工具1. 介绍2. 下载3. 静音模式、平衡模式、增强模式配置4. 配置电源方案与模式切换绑定5. 启动Ghelper控制面板6. 目前支持的设备型号 华硕ROG幻16笔记本电脑模式切换管理工具完美替代华硕奥创中心管理…

基于U-Net的图像分割算法介绍

U-Net是一种用于图像分割的深度学习架构,其设计初衷是用于生物医学图像分割,尤其是医学影像中的细胞分割任务。U-Net结构独特,具有编码器-解码器结构,能够有效地捕捉图像中的局部和全局信息,并在像素级别上进行精确的分割。 相关论文: U-Net: Convolutional Networks for…

全局视角观看Python备忘录-英文版

全局视角观看Python备忘录-英文版

中国科学院大学学位论文LaTeX模版

Word排版太麻烦了&#xff0c;公式也不好敲&#xff0c;推荐用LaTeX模版&#xff0c;全自动 官方模版下载位置&#xff1a;国科大sep系统 → \rightarrow → 培养指导 → \rightarrow → 论文 → \rightarrow → 论文格式检测 → \rightarrow → 撰写模板下载百度云&#…

如何使用Git-Secrets防止将敏感信息意外上传至Git库

关于Git-Secrets Git-secrets是一款功能强大的开发安全工具&#xff0c;该工具可以防止开发人员意外将密码和其他敏感信息上传到Git库中。 Git-secrets首先会扫描提交的代码和说明&#xff0c;当与用户预先配置的正则表达式模式匹配时&#xff0c;便会阻止此次提交。该工具的优…

Vue3从入门到实战:深度掌握通信插槽slot

slot_默认插槽的概念&#xff1a; 在Vue中&#xff0c;插槽&#xff08;slot&#xff09;是一种用于在组件中插入内容的特殊技术。默认插槽是其中一种类型的插槽&#xff0c;它允许你在组件的模板中指定一个位置&#xff0c;以便在使用组件时插入自定义的内容。 想象一下你有…

FOR循环指令计算累加和(CODESYS ST+SMART梯形图代码)

1、SMART PLC FOR循环指令应用 SMART PLC FOR循环指令_smart plc可以调用多少次for循环-CSDN博客文章浏览阅读2.4k次&#xff0c;点赞2次&#xff0c;收藏6次。SMART PLC的FOR循环&#xff1a; PLC里写需要加上&#xff1a; NEXT指令_smart plc可以调用多少次for循环https://r…

Tomcat下载配置地址

IntelliJ IDEA是一个强大的集成开发环境&#xff0c;能够大大简化Java应用程序的开发和部署过程。而Tomcat作为一个流行的Java Web服务器&#xff0c;其与IntelliJ IDEA的整合能够提供便捷的开发环境&#xff0c;让开发人员更专注于代码的创作与优化。 在配置IntelliJ IDEA以使…

【题解】AB5 点击消除(C++)

把string当栈用&#xff0c;扫一遍就可以了&#xff0c;时间复杂度O(n) #include <iostream> #include <string> using namespace std;int main() {string s;cin >> s;int n s.size();string st;for (int i 0; i < n; i) {if (st.empty() || st.back()…

2023年看雪安全技术峰会(公开)PPT合集(11份)

2023年看雪安全技术峰会&#xff08;公开&#xff09;PPT合集&#xff0c;共11份&#xff0c;供大家学习参阅。 1、MaginotDNS攻击&#xff1a;绕过DNS 缓存防御的马奇诺防线 2、从形式逻辑计算到神经计算&#xff1a;针对LLM角色扮演攻击的威胁分析以及防御实践 3、TheDog、0…

【Java开发指南 | 第一篇】类、对象基础概念及Java特征

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 类、对象基础概念Java特征 Java 是一种面向对象的编程语言&#xff0c;它主要通过类和对象来组织和管理代码。 类、对象基础概念 类&#xff1a;类是一个模板&#xff0c;它描述一类对象的行为和状态。例如水…

绝地求生更新反作弊系统“ZAKYNTHOS”杀疯了

绝地求生的反作弊系统“ZAKYNTHOS”近期取得了显著的成绩。从2024年1月1日至3月3日&#xff0c;共有117,3588个违规账号被封禁&#xff0c;其中107,3317个账号因使用外挂而被永久封禁。 根据官方每周封禁数据公告&#xff0c;1月至3月每周的永久封禁违规账号平均数高达13万&am…

22 文件系统

了解了被打开的文件&#xff0c;肯定还有没被打开的文件&#xff0c;就是磁盘上的文件。先从磁盘开始认识 磁盘 概念 内存是掉电易失存储介质&#xff0c;磁盘是永久性存储介质 磁盘的种类有SSD&#xff0c;U盘&#xff0c;flash卡&#xff0c;光盘&#xff0c;磁带。磁盘是…

WPF中DataGrid主从数据(父子数据)展示

在wpf中可以使用DataGrid控件,进行主从数据展示,也称父子数据展示。下面展示纯原生控件编码实现功能(样式自己可以根据需求进行修改)。 效果如下: 点击图标,展开和收缩可以自由的切换,也可以自己重新写一个样式,比如+,-或者类似图标的样式,都是可以的。 1.首先创建一…