zoukankan      html  css  js  c++  java
  • 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以上。

  • 相关阅读:
    net过滤表单和url参数
    html mailto
    sql提取汉字拼音首字母
    使用jquery获取radio的值
    net文件服务器配置
    如何将简体字保存到繁体数据库而不会出现乱码
    net直接下载文件
    java开发:笔记
    android开发:LogCat失效,adb失效
    编程记事本
  • 原文地址:https://www.cnblogs.com/drewgg/p/13524255.html
Copyright © 2011-2022 走看看