概论
传统压测工具用于测试系统的稳定性,虽然专业但是也是需要收费的,那么在日常开发中我们如何测试自己api的性能呢?这次为大家分享SuperBenchmarker。
1.SuperBenchmarker
SuperBenchmarker是一款运行在Windows上的性能测试工具。
可以下载已打包好的exe安装包,如果本机打开失败,可以在网络上自行下载可用运行包。
1.1 工具规范
SuperBenchmarker默认会生成测试对应的webUI因此我喜欢一般在参数中添加-B,如果需要查看webUI才到文件夹查看看,下面是官网提供的参数列表:
-c, --concurrency (Default: 1) Number of concurrent requests
-n, --numberOfRequests (Default: 100) Total number of requests
-N, --numberOfSeconds Number of seconds to run the test. If specified, -n will be ignored.
-y, --delayInMillisecond (Default: 0) Delay in millisecond
-u, --url Required. Target URL to call. Can include placeholders.
-m, --method (Default: GET) HTTP Method to use
-t, --template Path to request template to use
-p, --plugin Name of the plugin (DLL) to replace placeholders. Should contain one class which
implements IValueProvider. Must reside in the same folder.
-l, --logfile Path to the log file storing run stats
-f, --file Path to CSV file providing replacement values for the test
-a, --TSV If you provide a tab-separated-file (TSV) with -f option instead of CSV
-d, --dryRun Runs a single dry run request to make sure all is good
-e, --timedField Designates a datetime field in data. If set, requests will be sent according to order
and timing of records.
-g, --TlsVersion Version of TLS used. Accepted values are 0, 1, 2 and 3 for TLS 1.0, TLS 1.1 and TLS 1.2
and SSL3, respectively
-v, --verbose Provides verbose tracing information
-b, --tokeniseBody Tokenise the body
-k, --cookies Outputs cookies
-x, --useProxy Whether to use default browser proxy. Useful for seeing request/response in Fiddler.
-q, --onlyRequest In a dry-run (debug) mode shows only the request.
-h, --headers Displays headers for request and response.
-z, --saveResponses saves responses in -w parameter or if not provided in\response_<timestamp>
-w, --responsesFolder folder to save responses in if and only if -w parameter is set
-?, --help Displays this help.
-C, --dontcap Don't Cap to 50 characters when Logging parameters
-R, --responseregex Regex to extract from response. If it has groups, it retrieves the last group.
-j, --jsonCount Captures number of elements under the path e.g. root/leaf1/leaf2 finds count of leaf2
children - stores in the log as another parameter
-W, --warmUpPeriod (Default: 0) Number of seconds to gradually increase number of concurrent users. Warm-up
calls do not affect stats.
-P, --reportSliceSeconds (Default: 3) Number of seconds as interval for reporting slices. E.g. if chosen as 5,
report charts have 5 second intervals.
-F, --reportFolder Name of the folder where report files get stored. By default it is in
yyyy-MM-dd_HH-mm-ss.ffffff of the start time.
-B, --dontBrowseToReports By default it, sb opens the browser with the report of the running test. If specified,
it wil not browse.
-U, --shuffleData If specified, shuffles the dataset provided by -f option.
--help Display this help screen.
1.2 使用
再看一下生成的结果含义
RPS: 682.6 (requests/second) 每秒响应请求数
Max: 49ms 最大响应速度
Min: 0ms 最小响应速度
Avg: 0ms 平均响应速度
-n 设置请求数量,默认100个
sb -u http://127.0.0.1:2222/hello -n 10000 -B
Starting at 2021/3/30 23:46:34
[Press C to stop the test]
10000 (RPS: 694.4)
---------------Finished!----------------
Finished at 2021/3/30 23:46:48 (took 00:00:14.4840000)
Status 200: 10000
RPS: 647.3 (requests/second)
Max: 112ms
Min: 0ms
Avg: 0.1ms
50% below 0ms
60% below 0ms
70% below 0ms
80% below 0ms
90% below 0ms
95% below 0ms
98% below 1ms
99% below 1ms
99.9% below 2ms
-c 设置并发数,默认1个
sb -u http://127.0.0.1:2222/hello -n 10000 -c 5 -B
Starting at 2021/3/30 23:47:05
[Press C to stop the test]
10000 (RPS: 1309.8)
---------------Finished!----------------
Finished at 2021/3/30 23:47:13 (took 00:00:07.7270000)
Status 200: 10000
RPS: 1154.9 (requests/second)
Max: 62ms
Min: 0ms
Avg: 0.2ms
50% below 0ms
60% below 0ms
70% below 0ms
80% below 0ms
90% below 0ms
95% below 1ms
98% below 1ms
99% below 2ms
99.9% below 11ms
-N 设置测试时长,启用后-n会被禁用
sb -u http://127.0.0.1:2222/hello -N 30 -c 5 -B
Starting at 2021/3/30 23:47:33
[Press C to stop the test]
41490 (RPS: 1179.3)
---------------Finished!----------------
Finished at 2021/3/30 23:48:08 (took 00:00:35.2490000)
Status 200: 41490
RPS: 1335.6 (requests/second)
Max: 72ms
Min: 0ms
Avg: 0.1ms
50% below 0ms
60% below 0ms
70% below 0ms
80% below 0ms
90% below 0ms
95% below 1ms
98% below 1ms
99% below 2ms
99.9% below 4ms
-m 设置提交方式
sb -u http://127.0.0.1:2222/hello -m POST
通过阅读源码目前工具还不支持cookie,所以如果需要鉴权需要使用别的方式进行传参
-t 使用文件设置post方法提交的参数,具体内容如下,json字符串需要和Content-Type:application/json有一行的隔离
Content-Type:application/json
{"username":"123"}
sb -u http://127.0.0.1:2222/hello -t json.txt -m POST -B
Starting at 2021/3/30 23:51:30
[Press C to stop the test]
100 (RPS: 187.3)
---------------Finished!----------------
Finished at 2021/3/30 23:51:31 (took 00:00:00.8060000)
Status 200: 100
RPS: 54.7 (requests/second)
Max: 74ms
Min: 1ms
Avg: 2.1ms
50% below 1ms
60% below 1ms
70% below 1ms
80% below 2ms
90% below 2ms
95% below 3ms
98% below 4ms
99% below 74ms
99.9% below 74ms
2.应用
通过压测我们可以看到一个API的RPS还有它的响应时间,例如我们现在有个需求需要接口的RQS达到3000以上,明显现在的设计是无法满足的,我们看看该接口的代码,它就是一个使用Scoket编写的代码。
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class HttpServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(2222);
while (true) {
try {
Socket socket = serverSocket.accept();
service(socket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void service(Socket socket) {
try {
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
printWriter.println("HTTP/1.1 200 OK");
printWriter.println("Content-Type:text/html;charset=utf-8");
String body = "hello";
printWriter.println("Content-Length:" + body.getBytes().length);
printWriter.println();
printWriter.write(body);
printWriter.close();
socket.close();
} catch (IOException e) { // | InterruptedException e) {
e.printStackTrace();
}
}
}
普通socket下的结果
sb -u http://127.0.0.1:2222/hello -N 30 -c 5 -B
Starting at 2021/3/30 23:35:30
[Press C to stop the test]
58492 (RPS: 1687.6)
---------------Finished!----------------
Finished at 2021/3/30 23:36:05 (took 00:00:34.7150000)
Status 200: 58329
Status 303: 163
RPS: 1885 (requests/second)
Max: 129ms
Min: 0ms
Avg: 0.7ms
50% below 1ms
60% below 1ms
70% below 1ms
80% below 1ms
90% below 1ms
95% below 1ms
98% below 2ms
99% below 3ms
99.9% below 6ms
58495 (RPS: 1687.4)
我们知道Netty是一个异步时间驱动框架,可以增加单位时间内的请求吞吐量,我们尝试使用Netty来进行改造。
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class NettyHttpServer {
public static void main(String[] args) throws InterruptedException {
int port = 2222;
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup).channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpInitializer());
Channel ch = b.bind(port).sync().channel();
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
}
}
}
使用Netty下的结果
sb -u http://127.0.0.1:2222/hello -N 30 -c 5 -B
Starting at 2021/3/30 23:38:50
[Press C to stop the test]
148213 (RPS: 4263.3)
---------------Finished!----------------
Finished at 2021/3/30 23:39:25 (took 00:00:34.8590000)
Status 200: 148213
RPS: 4763.5 (requests/second)
Max: 81ms
Min: 0ms
Avg: 0ms
50% below 0ms
60% below 0ms
70% below 0ms
80% below 0ms
90% below 0ms
95% below 0ms
98% below 1ms
99% below 2ms
99.9% below 5ms
实际工作中,肯定是多方面的因素影响了实际的性能,通过性能测试工具我们可以给自己的工作做预估,改善现有的缺陷,从而提高交付质量。
github:https://github.com/tale2009/Blog-Demonstration/tree/main/Superbenchmarker-test