源起
在设计性能测试的时候,往往我们会通过客户端的并发线程数量来改变被测系统所承受的压力,每个线程在一个隐式的循环里执行我们的测试逻辑,10、50、100、500,我们习惯地增加并发的线程数量,记录每次改变后的性能数据,并把整个过程绘制成性能变化曲线。我们用这种方式测试了大量的项目,也发现了许多性能问题,进行了性能优化。
一个产品提出测试同时在线几万个用户的场景,但是我们发现测试机线程数再也加不上去了,在没有开始测试前发起请求的一方自己成为了瓶颈
另一个产品需要进行一次过载测试,模拟大量请求把系统压垮
用原有的方法我们无法很好地达到测试目标,我们越来越察觉到这种方式的局限或者说不真实。线上运行着的系统没有一个的访问行为是固定不变的,系统同时处理的请求无时不刻不在变化,没有哪个用户会默契地等待另一个用户处理完了才提交请求。这种使用有限的线程去阻塞且同步发起请求的方式正是问题所在,因此我们尝试开发一个能够以非阻塞方式发起请求并异步地处理响应的工具,garrosh就这样应运而生了。
garrosh是一个HTTP异步并发测试框架,下面简单介绍其主要概念及使用方法。
HTTP
框架把HTTP请求封装在com.netease.perf.async.test.AsyncClient类中,提供对HEAD、GET、PUT、POST支持的API
请求上下文
以POST API为例
public void doPost(String url, Header[] headers, byte[] body, String... ctx);
前三个参数都比较直观,最后一个参数ctx,是一个可选字符串数组参数,表示一个请求的上下文,在使用该参数时有一些限制
ctx[0]保存该请求对应的名字,以区别一个测试用例中的多个被测接口;如果在多接口测试中没有设置不同的名字,框架无法区分多个不同接口
ctx[1]保存与本次请求的响应验证相关的内容;框架会将该参数传递到结果验证阶段,供使用者进行验证
TestCase
com.netease.perf.async.test.TestCase是对测试用例的抽象,有两个抽象方法。一次测试执行,测试框架载入使用者指定TestCase的实现类进行具体的测试
public abstract void test();
该方法实现所有的测试逻辑,使用者可以利用AsyncClient的HTTP API设计自己的测试用例
public abstract boolean verify(ResultBean result);
该方法实际对应的是AsyncClient的HTTP API的一次调用,调用的结果以ResultBean对象返回给使用者,ResultBean对象保存了HTTP响应码等信息,根据参数配置选择是否保存HTTP响应体。
使用者除了验证HTTP响应码,还可以根据发起请求时传入的上下文参数ctx[1]和HTTP响应体进行比对验证
配置项
config.xml
testcase.name:TestCase的实现类
workers.thread:工作线程数,由于请求是异步发送的,该值不宜过大,一般不超过5,默认为1
run.time:测试时长,单位秒
run.count:测试总的请求次数,0表示一直请求直到达到run.time所指定的时长
think.frequency:思考频率,若设置为整数值N,表示请求N次后思考一次,思考时间为1毫秒
body.store:布尔值,表示是否保存HTTP响应体。存储型请求如下载文件,建议设置为false
使用步骤
1. 继承AsyncClient,实现test()、verify()方法
2. mvn package打包(框架和AsyncClient实现类可以分开打包),解压到测试客户端
3. 进入框架根目录,配置conf/config.xml
4. 运行run.sh
5. 查看log目录下的结果
data.log,模仿grinder的data日志格式
运行日志,类似grinder的out日志,文件末尾打印简单统计信息
PS: com.netease.perf.async.sample.NosTest是一个简单的示例
最后再给这个工具打个广告,感兴趣的tx可以猛戳这里,下载试用,欢迎提出需求或者意见
评论