JMeter

初探HTTP接口压力测试——JMeter

3090
5
2018-11-09

前言

压力测试(Stress Test),也称为强度测试、负载测试。压力测试是模拟实际应用的软硬件环境及用户使用过程,长时间或超大负荷地运行测试软件,来测试被测系统的性能、可靠性、稳定性等,简称压测
对于压力测试所使用的工具软件,常见的有ab、LoadRunner、http_load、JMeter等等,相信大家都有所耳闻甚至是非常熟悉。综合各方面的考量,我最终选择了图形化开源免费跨平台而且是鼎鼎大名的Apache旗下的JMeter

JMeter主要由三个部分组成,它们分别是:

  • 取样器
    进行脚本逻辑控制。用来控制业务流程,模拟用户进行操作
  • 线程组
    场景设置。比如模拟多少用户来访问、访问多少次
  • 监听器
    监控脚本运行,取得性能指标

本文就以 用户登陆 -> 发消息 -> 获取消息内容 的这么一个简单的例子来展示JMeter的使用方法

下载 & 运行

https://jmeter.apache.org/download_jmeter.cgi
Binaries 下选那个.zip结尾的就行了。直接解压无需安装
JMeter基于Java语言开发,所以需要先装一个JRE或者JDK
进入JMeter的bin目录下,如果是Windows系统就运行 jemter.bat ,如果是带桌面环境的Linux或Mac就运行 jmeter.sh

创建取样器与监听器

首先我们可以看到一个空的测试计划,我们先创建一个线程组

线程组里比较常用到的3个属性它们分别是:

  • Number of Threads
    线程数,也就是模拟的用户数量
  • Ramp-Up Period
    加压策略,也就是多少秒内将线程全部创建出来
  • Loop Count
    循环次数,这个很好理解

接下来我们在这个线程组里面创建一个 HTTP请求 取样器

把名字起好,进行相关的配置。我在本地写了个小的服务,并且生成了一些用户数据来作为演示

具体接口代码逻辑请自行实现

再来创建一个 监听器,用来观察执行结果

我们先故意弄一个错误的登陆请求看看。这个红色的盾牌就表示错误,绿色的就表示正确

测试数据参数化

但是在实际使用中总不可能要模拟几个用户就手动创建几个请求然后去填写它们的用户名密码吧?
我们可以把数据库里的用户列表导出来,让JMeter去读取来用。为了方便演示,这些用户的密码都是123456,我们可以这样做

然后将查询结果导出为csv,记得到自定义里把内容分隔符留空,不然双引号也会被JMeter读到

现在我们有一个记录着用户名密码的csv文件了,那么要如何让JMeter去读取它呢?我们去看看它的文档,就在这里

有个函数叫做CSVRead,怎么用呢?它这里有写到

The function represented by this class allows data to be read from CSV files. Syntax is similar to StringFromFile function. The function allows the test to line-thru the data in the CSV file - one line per each test. E.g. inserting the following in the test scripts :

${__CSVRead(c:/BOF/abcd.csv,0)} // read (first) line of 'c:/BOF/abcd.csv'
// and return the 1st column (represented by the '0')
${__CSVRead(c:/BOF/abcd.csv,1)} // read (first) line of 'c:/BOF/abcd.csv'
// and return the 2nd column (represented by the '1')

第二个参数填0就是第一列、1就是第二列,以此类推。至于读第几行的话,是根据当前的线程序号来自动递增的
我们现在只有一个线程,就读第一行;后续我们添加10个线程,就会自动依次读取第1到10行
来试一下。注意动态的内容要用$和花括号括起来

跑一下

可以看到用户名和密码都被成功获取并附加到请求中,这个登陆请求就算是写完了

提取器

那么接下来我们要把接口返回的token存储起来,用在后续的请求之中
因为这个接口返回的是json格式,我们就给它添加一个 后置处理器 - JSON提取器

我们起一个名叫token的变量来存储token值,然后要填这个json路径表达式。首先用$表示json根,然后就跟JS里面的对象调用差不多

比方说当接口返回{"token": "abcdefgxxxxxx"}时,JSON路径表达式写$.token就行了

HTTP头与随机模拟数据

接下来我们用提取出来的token去发送消息
token要带在头里传过去,我们添加一个 配置元件 - HTTP头管理器

把刚才的token用起来

消息内容我们可以利用JMeter的另一个函数 RandomString 来随机生成
这里顺便介绍一下JMeter的函数助手,它会显示所选函数的参数说明,并且可以让你进行简单的调试

我们把生成的函数表达式粘贴出来
来尝试一下。好,返回了一个自增的messageId,表示添加成功

按照之前的操作,用提取器把这个messageId提取出来保存

我们复制一下取样器,来写查看消息的功能

那么一个正常情况下的流程就走完了

错误处理

但是实际压测中可能会遇到一些问题,比如发消息的接口承受不了500了,拿不到messageId了
这种情况下我们就没必要再去测后续的查看消息了,肯定是报错的,这会影响到最终的错误率
这里介绍两种方法:

一、是在线程组里配置遇到错误后的处理方式,分为继续启动下一次线程循环停止线程停止测试立即停止测试
后面两者的区别是什么呢,停止测试 会等待当前最后一个取样器执行完毕才停止;而 立即停止测试 则会中断正在进行中的采样器

二、是使用 if逻辑控制器 。我们添加一个if判断

这个默认勾选的选项是判断一个变量是否等于true,我们要判断是否取到了messageId,所以需要自己写表达式。我们去掉它,手写判断表达式

为了模拟服务出错,我们改一下代码,50%的概率返回500
我们跑一下。可以看到,如果发消息失败了,就不会继续下一步的查看消息了

那么,一个流程就写完了

总结报告

接下来,我们要模拟10个用户,去跑10次,也就是理论上每个采样器跑100次

好,跑完了。可以看到有部分报错了,但是到底有多少个出错呢?错误率多少呢?不直观

这里就要用到另一个监听器——总结报告

我们再来跑一次。可以看到总结报告内出现了数据,它们分别是什么意思呢:

其他补充

比方说,我想模拟100个用户去压测,但我的csv里只有10个用户,怎么办呢?
不要慌,线程数直接填100就行了,JMeter会自动循环取用户去创建线程的
加压策略直接填0,让它不顾一切尽可能快的创建线程

最终压测前建议把查看结果树监听器(也就是本文中最开始创建的那个监听器)给禁用掉,它比较浪费性能。我们只需要看总结报告就行了

本萌新也是自己折腾着初学的压测,本文如有遗误还请指出

完成成就

你:看完了超能小紫博客有史以来最多配图的一篇博文
超能小紫:写完了超能小紫博客有史以来最多配图的一篇博文

昵称
邮箱
网址
过滤沙缸的头像 2018-12-07 14:54

厉害,解析的很全面

FlyingSky的头像 2018-12-01 09:56

太强了 QAQ

广树的头像 2018-11-18 19:24

膜拜小紫大佬!

波波鱼的头像 2018-11-09 23:39
波波鱼

哈哈!大佬写得太高深了,小伙伴们都不知道该评论啥。下回做一下服务器资源的消耗情况评估,一台1u1g的跑满能承受多少压力,分离数据库,加缓存,换算法的优化效果对比。这样多做几种架构方案的对比,以后就可以大概估算计算资源的配置

mokeyjay的头像 2018-11-12 14:36
mokeyjay 博主

?你说的这些个玩意儿才是真的高深啊