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_locust\fm_api\locust_api\XXX.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以上。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM