以下文章来源于 一个 程序员 的 修炼之路 ,作者 河边 一枝 柳一般在软件发布之前,都会经过
单元测试
, 接口测试
, 集成测试
, 性能测试
等。但是这些测试往往都是基于自己定义的测试数据集合,很可能会有漏网之鱼,那么在软件上线之后,在线上流量冲击下,会出现各种之前测试中并没有发现的问题。这是因为线上的流量数据比测试的数据更加多样性,并且随着用户数量的增加,线上流量的也越来越大,更多的隐藏问题也会暴露,比如并发处理不当导致的Crash。那么我们有什么方法能够在上线之前完成这些测试呢?有的,那就是GoReplay
。GoReplay概述 【http|HTTP 流量拷贝测试神器 GoReplay】当前越来越多的产品SaaS化,而SaaS化之后很多的服务都切分成多个
微服务
,HTTP又是服务之间常用的远程调用方式。GoReplay
是一个用Golang
编写的开源的流量复制工具, 基于libpcap
(windows也叫做Winpcap
,Npcap
也可以支持),其原理和Wireshark
和Tcpdump
类似,是一种非侵入软件方式的流量复制方式。文章图片
上图是一个典型的应用场景:
GoReplay
实现为一个可执行程序,方便运行, 支持Windows
和Linux
。先将其运行在一个具有流量环境的机器上, 监听指定端口的流量。GoReplay
将监听到的流量,以HTTP
发送到指定的一个或者多台测试机器。- 测试人员可以在测试机器上对流量处理结果进行分析。
- 比如根据
HTTP
请求的Method
,请求路径
,请求头
进行过滤 - 可以对请求进行进行改写,比如增加HTTP Header
- 可以基于
Middleware
,可以理解为自己编写插件。在插件中自己可以获取原始请求
,原始响应结果
, 以及测试机器返回测试响应结果
,这样就可以实现当前机器上的原始响应结果
和测试响应结果
做对比测试。
GoReplay
作者提供了编译好的版本,提供下载地址:https://github.com/buger/goreplay/releases
本文将介绍 如下几个方面,来阐述
GoReplay
的常见功能,而关于进阶的GoReplay插件实现
将放在后续的文章中。- 流量复制测试
- 流量保存到文件和重放功能介绍
- HTTP请求过滤
- HTTP请求更改
9797
, 客户端使用HTTP
和服务通信。文章图片
如果你想练练手,可是没有现成服务进程,不要担心,
GoReplay
本身提供了模拟服务的功能。那么你可以在服务机器上模拟运行sudo ./gor file-server :9797
。这个时候你通过浏览器访问这个机器就可以产生流量了。现在要开始进行测试了,先准备一台测试机器,也运行这个服务。然后进行流量拷贝操作。如下图所示在机器上运行
GoReplay
命令如下:sudo ./gor--input-raw :9797 --output-http "http://<测试机器IP>:9797"
这个时候将会在
服务机器
上将端口9797
上的HTTP流量复制到测试机器
。文章图片
这样做了,你就可以在不影响运行的
服务机器
,在测试机器
上任意的开启调试选项或者更改服务进程
的代码等,来辅助进行流量测试分析。是不是没有想到,GoReplay
的使用如此简单。!!!注意!!!: 从实践角度而言,不建议进行在线的流量复制测试,因为只要在线上操作,那就有可能会对线上产生影响。比如服务机器和测试机器在互通的网络之中,如果服务进程可能对第三方比如DB,Redis进行写操作,而测试机器上的服务进程收到同样的流量后,也会进行同样的操作,这样必然容易引起问题。你可以通过修改代码,在测试服务机器上屏蔽对数据库等第三方服务的写操作。但是是人就会犯错误,那有可能屏蔽的不够完全,对线上产生第三方服务的更改产生了影响。所以本人不建议在线上使用这个方法。
那么可以在保证流量落盘符合隐私保护法律和公司操作规范的情况下将流量Dump到本地磁盘文件,然后再在和线上环境隔离的测试环境中进行流量重放的测试和分析。
流量保存到文件和重放功能介绍 若要将流量保存到本地磁盘文件,那就一定要注意自己的行为是不侵犯
隐私保护法律
的,并且符合公司的规范。下面我们来讲一讲方法:将流量保存到文件:
sudo ./gor --input-raw :9797 --output-file Traffic.gor
那么将会产生若干个
Traffic_*.gor
的文件。如果重放则可以采用如下方式 (支持通配符方式)。
sudo ./gor --input-fileTraffic_*.gor --output-http "http://[测试机器A的IP]:9797" --output-http "http://[测试机器B的IP]:9797"
文章图片
注意这里特意将流量发送到两台机器了,假设这里的
测试机器A
采用的是上一个发布版本的软件,而测试机器B
采用的是正准备发布的新版本,通过两者运行的结果,比如Log,机器CPU,Memory等情况对比来做对比分析。当然了如果不需要做对比,你也可以只讲流量导入到一个测试机器。GoReplay
重放的时候还可以用来做性能测试分析, 其可以通过放大速率来提高单位时间请求数量,比如下面按照五倍500%
速率发送。sudo ./gor --input-file"Traffic_*.gor|500%" --output-http "http://[测试机器的IP]:9797"
还可以使用
--input-file-loop
来实现循环不断的发送:sudo ./gor --input-file"Traffic_*.gor|500%" --input-file-loop --output-http "http://[测试机器的IP]:9797"
另外可以使用
--stats --output-http-stats
来查看一些统计信息,不过本人觉得当前的统计信息还不够清晰。HTTP请求过滤 HTTP请求的抓取,可以进行一些过滤,从而只抓取和自己感兴趣的请求。
比如下面的命令,只有符合下述条件的才会抓取
--http-allow-url
采用正则表达式,只抓取请求URL
中含有test
的请求;--http-allow-header
采用正则表达式,只抓取XHeader
是123
的请求;--http-allow-method GET
, 只抓取HTTP请求方法为GET
的请求。
sudo ./gor --input-raw :9797 --output-file test.gor --http-allow-url .*test.* --http-allow-header XHeader:123 --http-allow-method GET
也可以使用
--http-disallow-url
和--http-disallow-header
去除一些不需要抓取的请求,同样支持正则表达式。HTTP请求更改 有时候你也需要更改HTTP请求,比如你想增加某个HTTP Header去让测试服务器识别,这个Request来自于
GoReplay
。我们举出一下例子来进行说明:--http-rewrite-url "/v1/user/([^\\/]+)/ping:/v2/user/$1/ping"
这个采用的是官方文档的案例,表示将/v1/user/([^\\/]+)/ping
替换为/v2/user/$1/ping
。不过经过本人测试1.3.3
的版本替换$1
有问题。--http-set-param "isTest=1"
设置参数isTest
为1
, 如果没有则增加这个参数,如果已经有,则修改这个参数。--http-set-header "User-Agent: tester agent"
修改或者增加一个HTTP Header--http-rewrite-header "Host: (.*):9797,$1:9898"
比如原先的HTTP Header为Host: xxx:9797
修改后变成Host: xxx:9898
sudo ./gor --input-raw :9797 --output-file test.gor --http-rewrite-url "/v1/user/([^\\/]+)/ping:/v2/user/$1/ping" --http-set-param "isTest=1" --http-set-header "XGoReplay: 1" --http-set-header "User-Agent: tester agent" --http-rewrite-header "Host: (.*):9797,$1:9898"
这些都是通过
GoReplay
的命令行参数去进行一些基本的更改HTTP请求的方法。需要更强的重写功能,那必须借助GoReplay
的Middlware
,支持使用者编写插件去处理,除此之外插件功能也可以根据原始流量的响应结果
和测试响应结果
来实现的结果对比。总结
GoReplay
可以协助我们利用已有的流量进行部分的功能测试,稳定性测试,以及性能测试等等。但是在使用的过程中,一定要注意不要对线上的数据造成影响,并且操作不要侵犯隐私保护法律
,遵循公司的操作规范。对于
GoReplay
的进阶部分Middleware
去编写自己的插件,实现Rewrite和直接的测试结果对比功能,将在后续文章进行阐述。参考 GoRepay Wiki:
https://github.com/buger/goreplay/wiki
- EOF -
推荐阅读
- 开源|请不要吸开源的血
- mvnd打包快到飞起
- 基础算法
- Arrays.toString() 的用法
- JavaSE进阶Day01
- Spring|小唐开始学 Spring Boot——(3)利用mybatis访问数据表
- SpringBoot MongoDB批量删除指定日期前的文件
- [架构]|如何全面了解一个JAVA应用
- Java|maven tomcat10 servlet api 不兼容 包名javax变成jakarta 实例化Servlet类 异常