locust分布式压测的Step Load及no web模式下的报表自动生成

Running Locust in Step Load Mode
If you want to monitor your service performance with different user load and probe the max tps that can be achieved, you can run Locust with Step Load enabled with --step-load:

如果你想分阶段递增并发用户数压测,找到系统最大的QPS,你可以用--step-load --step-users XX --step-time XX命令,不用再手动去增加用户数和压测时间。

譬如:

locust -f D:api_locustfm_apilocust_apiXXX.py  --master  --master-bind-port 9800 --headless -u 800 -r 50 --expect-worker 10 -t 50m -s 10  --step-load --step-users 200 --step-time 10m --csv D:locustlog 

总共发起800并发请求,每秒启动50个用户,当启动到200用户数时,持续运行10分钟,运行步骤大致如下:

(1)4s启动到200

(2)200用户数:10分钟

(3)4s启动到400

(4)400用户数:10分钟

(5)4s启动到600

(6)600用户数:10分钟

(7)4s启动到800

(8)800用户数:10分钟

(9)800用户数:50-40=10分钟(小于10分钟)

压测结果如图:

可以得出系统qps最大也就550左右,后边随着并发数提升没有提升,唯一提升是平均响应时间。

通过 --step-load --step-users这样的命令就不用再折腾弄命令了。

关于压测结果图的生成,也很简单的,上面的压测命令会把压测的历史记录写到csv文件里,

读取csv文件再生成报表即可:

python用到的模块pyecharts

pyecharts文档地址:http://pyecharts.org/#/zh-cn/intro

贴个代码示例:

 1 # -*- coding = utf-8 -*-
 2 # ------------------------------
 3 # @time: 2020/8/15 16:05
 4 # @Author: drew_gg
 5 # @File: deal_csv.py
 6 # @Software: api_locust
 7 # ------------------------------
 8 
 9 import os
10 import time
11 import csv
12 import datetime
13 from pyecharts.charts import Line
14 from pyecharts import options as opts
15 from pyecharts.globals import ThemeType
16 
17 """
18 # pyecharts使用文档
19 # http://pyecharts.org/#/zh-cn/intro
20 """
21 
22 pl = os.getcwd().split('api_locust')
23 path_html = pl[0] + 'api_locust\resource\html\'
24 
25 
26 def report(interface_name, history_csv, stats_csv):
27     """
28     locust生成报表
29     :param interface_name:
30     :param history_csv:
31     :param stats_csv:
32     :return:
33     """
34     tm = []
35     uc = []
36     qps = []
37     fps = []
38     avg_time = []
39     all_r = ''
40     all_qps = ''
41     all_avg_time = ''
42     with open(history_csv, 'r') as f:
43         hc = csv.reader(f)
44         for x, i in enumerate(list(hc)):
45             if i:
46                 if x != 0:
47                     tm.append(time.strftime('%H:%M:%S', time.localtime(int(i[0]))))
48                     uc.append(str(round(float(i[1]), 2)))
49                     qps.append(str(round(float(i[4]), 2)))
50                     fps.append(str(round(float(i[5]), 2)))
51                     avg_time.append(str(round(float(i[20]), 2)))
52     with open(stats_csv, 'r') as f:
53         sc = csv.reader(f)
54         for x, i in enumerate(list(sc)):
55             if x != 0 and len(i) != 0:
56                 all_r = str(i[2])
57                 all_qps = str(round(float(i[9]), 2))
58                 all_avg_time = str(round(float(i[5]), 2))
59     locust_title = "[{0}]压测情况:[ARC:{1}, QPS: {2}, AVT: {3}]".format(interface_name, all_r, all_qps, all_avg_time)
60     locust_html_name = path_html + interface_name + str(datetime.datetime.now().strftime('%m%d%H%M%S')) + '.html'
61     line = (
62         Line(init_opts=opts.InitOpts(theme=ThemeType.CHALK, width="1800px", height="800px"))
63         .add_xaxis(tm)
64         .add_yaxis('user', uc, is_smooth=True)
65         .add_yaxis('qps', qps, is_smooth=True)
66         .add_yaxis('fps', fps, is_smooth=True)
67         .add_yaxis('avg_t', avg_time, is_smooth=True)
68         .set_global_opts(
69             title_opts=opts.TitleOpts(title=locust_title),
70             tooltip_opts=opts.TooltipOpts(trigger="axis"),
71             toolbox_opts=opts.ToolboxOpts(is_show=True, orient="vertical", pos_left="1%",  pos_top="10%"),
72             xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False,),
73         )
74     )
75     line.render(locust_html_name)
76 
77 
78 if __name__ == "__main__":
79     stats = "D:\api_locust\resource\csv\locust_exhibition_home.py0826095139_stats.csv"
80     history = "D:\api_locust\resource\csv\locust_exhibition_home.py0826095139_stats_history.csv"
81     report('a', history, stats)

关于报表的生成,不懂的自行去文档地址仔细研究研究,挺全的,各种报表样式都有。

另外,如果是分布式压测的话,不要手动去启动命令,自己写个py去自动创建生成多好:

 1 # -*- coding = utf-8 -*-
 2 # ------------------------------
 3 # @time: 2020/8/15 16:05
 4 # @Author: drew_gg
 5 # @File: locust_main.py
 6 # @Software: api_locust
 7 # ------------------------------
 8 
 9 import datetime
10 import subprocess
11 
12 
13 class CoverLocust:
14     """
15     封面压测封装类
16     """
17     def __init__(self, ltp):
18         """
19         初始化压测参数
20         :param ltp: 参数字典
21         """
22         self.user = ltp['user']
23         self.r = ltp['r']
24         self.slave = ltp['slave']
25         self.m_time = ltp['m_time']
26         self.port = ltp['port']
27         self.master_host = ltp['master_host']
28         self.csv = ltp['csv']
29         self.master_script = ltp['master_script']
30         self.slave_script = ltp['slave_script']
31         self.step_u = ltp['step_u']
32         self.step_t = ltp['step_t']
33         # 定义csv文件名称
34         self.csv_name = ltp["master_script"].split('\')[-1] + str(datetime.datetime.now().strftime('%m%d%H%M%S'))
35         self.csv_path = ltp['csv'] + self.csv_name
36         # 输出压测结果目录文件
37         self.stats_history_csv = self.csv_path + '_stats_history.csv'
38         self.stats_csv = self.csv_path + '_stats.csv'
39         self.failures_csv = self.csv_path + '_failures.csv'
40 
41     # 生成master命令
42     def locust_master(self):
43         """
44         运行master指令
45         :return:
46         """
47         master_cmd = "locust -f %s  --master  --master-bind-port %s --headless " % (self.master_script, self.port)
48         master_pra = "-u %s -r %s --expect-worker %s -t %s -s 10  --step-load --step-users %s --step-time %s --csv %s "
49                      % (self.user, self.r, self.slave, self.m_time, self.step_u, self.step_t, self.csv_path)
50         master_cmd = master_cmd + master_pra
51         print(master_cmd)
52         subprocess.Popen(master_cmd, creationflags=subprocess.CREATE_NEW_CONSOLE)
53         return self.stats_history_csv, self.stats_csv, self.failures_csv, self.csv_name
54 
55     # 生成slave命令
56     def locust_slave(self, slave_num):
57         """
58         运行slave指令
59         :param slave_num:
60         :return:
61         """
62         slave_cmd = "locust -f %s --master-host  %s --master-port %s --headless --worker" % (self.slave_script, self.master_host, self.port)
63         print(slave_cmd)
64         for i in range(slave_num):
65             subprocess.Popen(slave_cmd, creationflags=subprocess.CREATE_NEW_CONSOLE)
66 
67     # 杀掉压测进程
68     @classmethod
69     def close_process(cls):
70         """
71         杀掉命令进程
72         :return:
73         """
74         import os
75         os.system('taskkill /IM locust.exe /F')
 1 # -*- coding = utf-8 -*-
 2 # ------------------------------
 3 # @time: 2020/8/18 20:36
 4 # @Author: drew_gg
 5 # @File: locust_run.py
 6 # @Software: api_locust
 7 # ------------------------------
 8 
 9 import os
10 import time
11 from run_locust import locust_main as locust_m
12 from locust_common.common_excel import deal_csv as report
13 
14 pl = os.getcwd().split('api_locust')
15 path_csv = pl[0] + 'api_locust\resource\csv\'
16 path_script = pl[0] + 'api_locust\locust_view\kbh_api\locust_api\'
17 script_name = "locust_exhibition_home.py"
18 
19 # ************************************需维护更改的参数****************************#
20 # 并发数
21 user = 1400
22 # 每秒启动用户数
23 rate = 200
24 # 分布式压测启动的slave数量
25 num_slave = 10
26 # 本次压测执行的时长:h,m,s
27 run_time = '25m'
28 # master所在host/ip
29 master_host = "10.111.53.123"
30 # master 执行脚本
31 master_script = path_script + script_name
32 # slave 执行脚本
33 slave_script = path_script + script_name
34 # # csv存储文件的目录
35 # csv_path = path_csv + script_name.split('.')[0] + '_log\'
36 # 递压用户数
37 step_user = 400
38 # 递压持续时间
39 step_time = '5m'
40 # ************************************需维护更改的参数****************************#
41 
42 
43 locust_p = {
44     'user': user,
45     "r": rate,
46     "slave": num_slave,
47     "m_time": run_time,
48     "port": 9800,
49     "master_host": master_host,
50     "csv": path_csv,
51     "master_script": master_script,
52     "slave_script": slave_script,
53     "step_u": step_user,
54     "step_t": step_time
55 }
56 
57 if __name__ == "__main__":
58 
59     # *****************执行脚本标识*******************#
60     sign = "master"
61     # sign = "slave"
62     # *****************执行脚本标识*******************#
63     lm = locust_m.CoverLocust(locust_p)
64     lm.close_process()
65     if sign == "master":
66         # 启动master
67         history_csv, stats_csv, failures_csv, csv_name = lm.locust_master()
68         sleep_time = int(run_time[:-1])
69         # 延迟30s读取csv文件
70         if run_time[-1] == 'h':
71             sleep_time = sleep_time * 60 * 60 + 30
72         if run_time[-1] == 'm':
73             sleep_time = sleep_time * 60 + 30
74         if run_time[-1] == 's':
75             sleep_time = sleep_time + 30
76         time.sleep(sleep_time)
77         # 生成报表
78         report.report(script_name.split('.')[0], history_csv, stats_csv)
79     if sign == "slave":
80         # 启动slave  分多台跑的话需要用num_slave除以台数
81         slave_num = int(num_slave/2)
82         lm.locust_slave(slave_num)
这样要修改啥,直接修改就行,也可以自己写个页面,点一下按钮就可以压测。

 上面的这个压测结果图:

这个说明QPS还有升高的空间,目前的并发数还没到达瓶颈,还得再提升并发数【平均响应时间没有急剧提升】。当然,这个地方设置的between(0,0.5),

所以会出现800的并发结果qps达到960以上。

原文地址:https://www.cnblogs.com/drewgg/p/13524255.html