压力测试

作为后端/架构人员,在技术选型、服务架构设计的时候,或是造完一个轮子的时候,总是想尝试下极限在哪。此刻压测必不可少,此文介绍各种常见压测工具优缺点,也记录下基本用法。

先说下结论

  • 对于并发测试,首推Jmeter。原因:功能强大、可视化、速度很快。熟悉ab工具的,也可以使用ab,一行命令就搞定。
  • 对于数据库测试,必用sysbench。原因:功能强大,可扩展,还可以造数据。注意:不支持windows
  • 对于复杂一点的测试,很难找到现成工具,那就自己造轮子吧

    有人会说postman也可以测试,还支持前置脚本。其实那不是并发,而且也没有汇总结果。再说下国产新的Apifox,搜索Jmeter居然出来的是它,而且广告做的到处都是。我最近的测试首先就用了它,结果大失所望,功能配置好像是很强大的,集成了很多。可是,太慢了…可能,这也是国产软件的通病。

一、Jmeter

JmeterJmeter是由Apache公司开发的一个纯Java的开源项目,即可以用于做接口测试也可以用于做性能测试。

1.1 安装使用步骤

参考
基本使用步骤:
1. 测试计划 -> 添加 -> 线程(用户)-> 线程组
2. 线程组 -> 添加 -> 取样器 -> HTTP请求
3. HTTP请求 -> 添加 -> 监听器 -> 查看结果树
4. HTTP请求 -> 添加 -> 监听器 -> 汇总报告

1.2 汇总报告

汇总报告结果默认时间单位是ms

Jmeter性能指标分析参考

二、Apache Benchmark

Apache 出品的一个 HTTP 服务器性能测试工具。使用它可以测试每秒请求数、吞吐率等参数。

2.1 基本用法

1
2
3
4
# -c  设定并发数,默认并发数是 1
# -n 设定压测的请求总数
# -t 设定压测的时长,单位是秒
ab -c 10 -n 1000 http://example.com

2.2 汇总结果

主要看两个参数Requests per secondPercentage of the request
使用参考

三、sysbench

3.1 简介

sysbench内置的测试项包括内存/CPU/线程/事务/互斥锁,但是一般用来做数据库的测试。 它是全开源的lua写的,各种测试运行都基于lua脚本,可以很便捷的扩展。
它主要是三个阶段:
prepare(准备数据)/ run(执行测试)/ clean(清理测试数据)

3.2 基本使用

例如你只是想测试下新搭建的mysql集群读写性能,你可以:

1
2
3
4
# 准备数据:创建5个表,每个表100条数据
sysbench /usr/share/sysbench/oltp_read_write.lua --tables=5 --table_size=100 --mysql-user=root --mysql-password=xxx --mysql-host=192.168.0.103 --mysql-port=3306 --mysql-db=sysbench_test prepare
# 使用的线程数量为16个,使用的存储引擎为InnoDB,测试事务运行
sysbench --num-threads=16 --test=oltp --mysql-table-engine=innodb --tables=5 --table_size=100 --mysql-user=root --mysql-password=xxx --mysql-host=192.168.0.103 --mysql-port=3306 --mysql-db=sysbench_test run

3.2 进阶

可以发现,准备阶段给我们生成的测试数据结构是固定的。如果我们想更贴切地模拟想要测试的内容,可以像上一段中使用的LUA脚本地址:/usr/share/sysbench/oltp_read_write.lua。这个是自带的lua脚本,也可以自定义一套。

sysbench使用参考

四、java.jdk.concurrent

jdk并发包下有很多工具也可以实现并发请求,对于一些需要构造数据或有特定步骤的复杂测试,自己编码反而更为便利。这里以CountDownLatch为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CountDownLatch countDownLatch = new CountDownLatch(1);
ExecutorService executorService = Executors.newFixedThreadPool(3);
Function<Integer, Thread> supplier = index -> (new Thread(()-> {
try {
countDownLatch.await();
// do something
log.warn(Thread.currentThread().getName() + " : index " + index + " done" );
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
IntStream.range(1, 11).mapToObj(x -> supplier.apply(x)).forEach(executorService::submit);
countDownLatch.countDown();
while (!executorService.awaitTermination(200L,TimeUnit.MILLISECONDS)) {
executorService.shutdown();
}