如何利用wrk与Jmeter做性能压测

我们在新做项目的时候,需要对我们的服务有有一些性能指标,比如:SLA(需要达到多少个9)、QPSTPS等。因为这些量化的数字让我们更加的了解我们的系统。

我们如何压测?其实个人觉得有2种场景。

第一种:是我们明确的知道目标,看我们通过大量的并发看我们是否有达到。如果没有达到,我们需要通过水平扩容、性能优化等让其达到。

第二种:是我们不知道目标,通过压测可以知道一个固定配置下的单机单服务的最大性能,让我们对它有一个彻底的认识。为后面的目标做更多的铺垫与准备,或者跟行业水平对比,看看差距有多少。

如何用wrk进行压测?

Github地址:https://github.com/wg/wrk,该项目也是开源项目,关注的人还不少,有30.4K。咨询了一下身边的同事,使用它的人还不少。主要的语言的是C语言。

http://static.cyblogs.com/Jietu20211023-153923.jpg

安装
1
2
3
4
5
6
git clone https://github.com/wg/wrk

make

-- 拷贝wrk到bin
cp wrk /usr/sbin/wrk
压测脚本

压测脚本press.sh

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
bf=0i
rm ./report_mock.${1}.txt 2> /dev/null
for k in 10; do
bf=`expr ${k} \* 100`
for len in 512k; do
echo "start length ${len}" >> ./report_mock.${1}.txt
./wrk -c${bf} -t16 -d3m --timeout 2m --latency -s ./post_${len}.lua http://${1}/press/${len} >> ./report_mock.${1}.txt
echo "----------------------------------------------------" >> ./report_mock.${1}.txt
done
sleep 10
done

Lua脚本post_512.lua

1
2
3
4
wrk.method = "POST"
wrk.body = '{"key":"value"}'
wrk.headers["Content-Type"] = "application/json"
wrk.headers["X-Forwarded-For"] = "6.6.6.6"

这里是一个通用脚本,大致的含义是:

  • 删除掉原来生成的文件
  • 循环10次,其实也就是从并发数从100~1000依次进行压测
  • 返回的报文大小控制在512K,这个可以为根据你的Request去匹配你的Response。
  • -t16:启动16个线程
  • -d3m:也测时间是3mins
  • –timeout:2m 超时时间是2mins
  • post_${len}.lua:就是构造512K返回的Request参数对应的lua脚本
  • report_mock.${1}.txt:结果会append到该文件中去
  • ${1}:就是你要向哪个服务器发起请求的host+port

总结一下,这些时间需要根据自己的服务器性能去调整,有可能压测出来的数据就是空的,因为超时了未返回Response。

参数解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
使用方法: wrk <选项> <被测HTTP服务的URL>                            
Options:
-c, --connections <N> 跟服务器建立并保持的TCP连接数量
-d, --duration <T> 压测时间
-t, --threads <N> 使用多少个线程进行压测

-s, --script <S> 指定Lua脚本路径
-H, --header <H> 为每一个HTTP请求添加HTTP头
--latency 在压测结束后,打印延迟统计信息
--timeout <T> 超时时间
-v, --version 打印正在使用的wrk的详细版本信息

<N>代表数字参数,支持国际单位 (1k, 1M, 1G)
<T>代表时间参数,支持时间单位 (2s, 2m, 2h)
执行的结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
start length 512k
Running 3m test @ http://{ip+port}/press/512k # {ip+port}是你自己的
16 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 145.17ms 942.97ms 0.86m 98.34%
Req/Sec 1.39k 114.27 3.58k 70.07%
Latency Distribution
50% 36.58ms
75% 48.78ms
90% 185.51ms
99% 1.78s
3994727 requests in 3.00m, 65.25GB read
Non-2xx or 3xx responses: 3863495
Requests/sec: 22181.33
Transfer/sec: 371.00MB

会给一个分布非常的好:50%、75%、90%、99%。

但是如果说这么看大量的数据不够直观,这里再提供一个一个python脚本来解析里面的值。使其能把这些日志的重要的信息提取出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import math

def ms(fr):
fr = fr.lower()
if fr[-2:] == 'ms':
to = float(fr[:-2])
elif fr[-1:] == 's':
to = float(fr[:-1]) * 1000
elif fr[-1] == 'm':
to = float(fr[:-1]) * 1000 * 60
return to

def mb(fr):
fr = fr.lower()
if fr[-2:] == 'gb':
to = float(fr[:-2]) * 1000
elif fr[-2:] == 'mb':
to = float(fr[:-2])
elif fr[-2:] == 'kb':
to = float(fr[:-2]) / 1000
elif fr[-1] == 'b':
to = float(fr[:-1]) / 1000 / 1000
elif fr[-1] == 'k':
to = float(fr[:-1]) / 1000
elif fr[-1] == 'm':
to = float(fr[:-1])
return to

def parse_one(one):
ret = {}
for l in one.split('\n'):
if l.find('test @ http://') > 0:
ret['host'] = l.split('://')[1].split('/')[0].strip()
elif l.find('start length') == 0:
ret['size'] = l.split(' ')[-1].strip()
elif l.find('threads and') > 0:
ret['threads'] = int(l.split('threads and')[0].strip())
ret['conns'] = int(l.split('threads and')[1].split('connections')[0].strip())
elif l.find(' Latency') == 0:
ret['l_avg'] = ms(l[len(' Latency'):].lstrip().split(' ')[0])
elif l.find(' 50%') == 0:
ret['l_50'] = ms(l[len(' 50%'):].strip())
elif l.find(' 90%') == 0:
ret['l_90'] = ms(l[len(' 90%'):].strip())
elif l.find(' 99%') == 0:
ret['l_99'] = ms(l[len(' 99%'):].strip())
elif l.find('Requests/sec:') == 0:
ret['qps'] = float(l[len('Requests/sec:'):].strip())
elif l.find('Transfer/sec:') == 0:
ret['mbps'] = mb(l[len('Transfer/sec:'):].strip())
return ret

with open('/Users/chenyuan/Desktop/report_mock.127.0.0.1.txt') as f:
all = f.read().strip()
out = []
for one in all.split('----------------------------------------------------\n'):
r = parse_one(one)
out.append((r['host'], r['size'], r['conns'], r['l_avg'], r['l_50'], r['l_90'], r['l_99'], r['qps'], r['mbps']))
out.sort()
for o in out:
print('\t'.join([str(i) for i in o]))

最终你可以再在文本里面利用列操作的方式,将内容归整到Excel中去。你就可以很好的汇报与分享给他人了~

http://static.cyblogs.com/Jietu20211023-160325.jpg

如何利用Jmeter进行压测?

简介

Apache JMeter是Apache组织开发的基于Java的压力测试工具。用于对软件做压力测试,它最初被设计用于Web应用测试,但后来扩展到其他测试领域。 它可以用于测试静态和动态资源,例如静态文件、Java 小服务程序、CGI 脚本、Java 对象、数据库、FTP 服务器, 等等。JMeter 可以用于对服务器、网络或对象模拟巨大的负载,来自不同压力类别下测试它们的强度和分析整体性能。另外,JMeter能够对应用程序做功能/回归测试,通过创建带有断言的脚本来验证你的程序返回了你期望的结果。为了最大限度的灵活性,JMeter允许使用正则表达式创建断言。

Apache jmeter 可以用于对静态的和动态的资源(文件,Servlet,Perl脚本,java 对象,数据库和查询,FTP服务器等等)的性能进行测试。它可以用于对服务器、网络或对象模拟繁重的负载来测试它们的强度或分析不同压力类型下的整体性能。你可以使用它做性能的图形分析或在大并发负载测试你的服务器/脚本/对象。

Jmeter也是在进行压测中使用场景很多的软件,图形界面操作起来非常的友好。简单的写一个Demo流程出来。

下载安装

官网:http://jmeter.apache.org/download_jmeter.cgi

http://static.cyblogs.com/Jietu20211023-160918.jpg

下载解压完毕后大概的一个目录结构,可以把bin配置到path中就可以直接通过jmeter密令激活软件了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
➜  jmeter pwd
/Users/chenyuan/Tools/jmeter
➜ jmeter ll
total 64
-rw-rw-r--@ 1 chenyuan staff 15K 1 2 1970 LICENSE
-rw-rw-r--@ 1 chenyuan staff 167B 1 2 1970 NOTICE
-rw-rw-r--@ 1 chenyuan staff 9.6K 1 2 1970 README.md
drwxrwxr-x@ 43 chenyuan staff 1.3K 1 2 1970 bin
drwxr-xr-x@ 6 chenyuan staff 192B 1 2 1970 docs
drwxrwxr-x@ 22 chenyuan staff 704B 1 2 1970 extras
drwxrwxr-x@ 104 chenyuan staff 3.3K 1 2 1970 lib
drwxrwxr-x@ 104 chenyuan staff 3.3K 1 2 1970 licenses
drwxr-xr-x@ 19 chenyuan staff 608B 1 2 1970 printable_docs

# 我这里直接运行,最好配置PATH,后续更加的方便
➜ jmeter ./bin/jmeter
================================================================================
Don't use GUI mode for load testing !, only for Test creation and Test debugging.
For load testing, use CLI Mode (was NON GUI):
jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
& increase Java Heap to meet your test requirements:
Modify current env variable HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m" in the jmeter batch file
Check : https://jmeter.apache.org/usermanual/best-practices.html
================================================================================
# 就这代表已经启动了,运行期间不要终端命令框。
创建测试

先看一张整体的图吧,对它有一个比较整体的认识:

http://static.cyblogs.com/Jietu20211023-161956.jpg

我们可以按照https://www.cnblogs.com/stulzq/p/8971531.html 的步骤一步的去做。我这里就不做太多重复的介绍。因为相对比wrk来的简单。

最后可以点击运行来跑单测,一般我们会调整线程数的大小、发送的频率来进行压测看结果。

http://static.cyblogs.com/Jietu20211023-162302.jpg

我们在断言的地方是可以做很多的事情的,因为什么样的结果是正确的,什么样的结果是失败的。获取需要从Response中、Header里截取一些关键的key与value来做逻辑。这些可以通过编写脚本来去做到,那就算相对高阶一点的操作了。后续可以继续深入一下~

最后可以在汇总报告里可以看出来我们的一个性能情况,SLA的比例等。

作为一名后端开发,对自己写出来的服务进行一个非常全面的性能压测是很有必要的。对于系统的一个QPS、TPS、SLA这些数字应该随口就能说出来。哪些地方存在性能瓶颈?然后再去找相应的方案去优化掉。很多时候,性能可能就会是一个最大的风险,它会导致我们的服务整体的瘫痪、不可用。这些很有可能就跟我们的KPI、奖金挂钩~

参考地址

如果大家喜欢我的文章,可以关注个人订阅号。欢迎随时留言、交流。如果想加入微信群的话一起讨论的话,请加管理员微信号:chengcheng222e,他会拉你们进群。

简栈文化服务订阅号