JAVA常用工具--JMeter压力测试工具
一.JMeter介绍以及应用场景
Apache JMeter是Apache组织开发的基于Java的压力测试工具。用于对软件做压力测试,它最初被设计用于Web应用测试,但后来扩展到其他测试领域。 它可以用于测试静态和动态资源,例如静态文件、Java 小服务程序、CGI 脚本、Java 对象、数据库、FTP 服务器, 等等。JMeter 可以用于对服务器、网络或对象模拟巨大的负载,来自不同压力类别下测试它们的强度和分析整体性能。另外,JMeter能够对应用程序做功能/回归测试,通过创建带有断言的脚本来验证你的程序返回了你期望的结果。为了最大限度的灵活性,JMeter允许使用正则表达式创建断言。
JMeter是一个Java桌面应用程序,具有使用Swing图形API的图形界面。 因此,它可以在任何接受Java虚拟机的环境/工作站上运行,例如Windows,Linux,Mac等。
JMeter支持的协议
1.Web - HTTP,HTTPS站点web 1.0,web 2.0(ajax,flex和flex-ws-amf)
2.Web服务 -SOAP/XML-RPC
3.数据库通过JDBC驱动程序
4.目录 - LDAP
5.通过JMS提供面向消息传递的服务
6.服务 -POP3,IMAP,SMTP
7.FTP服务
JMeter的作用
1.接口测试
2.性能测试:程序的算法
3.压力测试:外在负载
4.Web自动化测试
5.数据库测试
6.java测试
在我们编写代码的过程中,经常会出现单机测试下并无任何问题和bug,但是在并发或者集群场景下就会出现许许多多未知的bug。所以根据面向KPI编程定律,为了避免在测试手中或者线上场景出现未知的问题导致KPI扣除,我们就要本地通过JMeter去模拟高并发和集群场景以提升代码的稳定性和高可用性。
二.JMeter的安装与使用
首先进入Jmeter的官网https://jmeter.apache.org/,如下图所示,在左边Download一栏找到Download Releases节点并点击。
在下载页面分别有两个节点,以.tgz为结尾的是linux版本下的,这里我们选择.zip为结尾的压缩包进行下载安装。
这里我下载的是5.2.1版本,如果执行有问题的朋友建议对比下jdk与JMeter的版本号。
下载完成后对我们的压缩包进行解压,然后再进入/bin目录之下找到jmeter.bat并运行。
这里需要说明一点,如果用记事本打开我们会发现在脚本中已经写好环境变量的相关配置所以我们并不需要做更多的操作。如果仍旧无法打开的朋友可以尝试用管理员身份打开脚本。
至此安装结束,进入JMeter主界面,如有需要可以在下图将语言修改为简体中文。
三.使用JMeter模拟高并发场景
第一步:通过JMeter文件点开新建一个测试计划,快捷键Ctrl + L
第二步:在测试计划上右键选择添加>线程(用户)>线程组
第三步:打开线程组,线程数代表同时并发的用户数(建议不要太高,计算机性能会受到影响),Ramp-up决定多长时间启动所有线程(如果使用150个线程,ramp-up period是10秒,那么JMeter用10秒使所有150个线程启动并运行),循环次数指对并发重复执行的次数。
第四步:设置完线程相关的参数后,在线程组上右键选择添加>取样器>Http请求
第五步:在Http请求上进行相关的参数设置,同时这里可以添加请求参数。
第六步:配置监听器,配置监听器:察看结果树、聚合报告、生成概要结果、图形结果
第七步:启动服务器,并运行JMeter
测试代码如下
@RestController
@RequestMapping(value = "/jmeter")
public class TestJMeter {
private Integer count = 100;
@GetMapping(value = {"/test"})
public String test() throws InterruptedException {
if (count <= 0) {
System.out.println("已经没有count了");
return "end";
}
//模拟网络延时
Thread.sleep(10);
System.out.println("现有count数量:" + --count);
return "ok";
}
}
根据后台打印可知出现了负数情况,模拟高并发成功。
四.使用JMeter模拟网络集群场景
这里先放一张简易的集群架构图,以Nginx做服务的分发、Redis作为数据缓存。
首先是Nginx做服务分发、负载均衡的一个配置,修改Nginx文件夹conf目录下的nginx.conf
http {
upstream 127.0.0.1{ #这个是在浏览器中访问的地址
server 127.0.0.1:8080 weight=1;#Server端1的地址 weight代表权重即分配请求次数的比重
server 127.0.0.1:8081 weight=1;#Server端2的地址
}
server {
listen 80;#nginx监听的端口
server_name localhost;
location / {
proxy_pass http://127.0.0.1;#相对路径
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
}
然后修改JMeter中的访问的端口号为80并修改请求路径,请求次数仍然设定为150次
同时启动配置好Redis的两个项目,分别开启端口8080和8081
测试代码如下
@RestController
@RequestMapping(value = "/jmeter")
public class TestJMeter {
@Autowired
private RedisUtil redisUtil;
@GetMapping(value = {"/testCluster"})
public String testCluster(HttpServletRequest httpServletRequest) {
//redisUtil为封装的Redis操作类,可根据自身需要修改
//这条指令仅key不存在的时候才会设值
//key value expire超时时间
redisUtil.setnx("count", "100", 10);
Integer myCount = Integer.parseInt(redisUtil.get("count"));
if (myCount.compareTo(0) <= 0) {
System.out.println("已经没有count了");
return "end";
}
System.out.println(httpServletRequest.getLocalPort() + "现有count数量" + --myCount);
//key value
redisUtil.set("count", myCount.toString());
return "ok";
}
}
由于本次设定的请求数为150次,理论上每个集群节点会分发到75次的请求,设定的总count数量为100个,可是根据实际运行结果可以看出count并没有被消耗完,这里就出现了集群环境下最常见的数据不一致性的问题。具体解决方案可以使用分布式锁,关于分布式锁的内容本文这里就不再过多阐述了。