性能测试工具Locust的使用

一、写在前面 官网: https://www.locust.io/ 官方使用文档:https://docs.locust.io/en/latest/ 大并发量测试时,建议在linux系统下进行。 二、Locust安装 1.1、 ---> pip3 install locust 1.2 、 通过GitHub上克隆项目安装(Python3推荐):https://github.com/locustio/locust ,然后执行 ...\locust> python setup.py install 2、安装 pyzmq If you intend to run Locust distributed across multiple processes/machines, we recommend you to also install pyzmq. 如果打算运行Locust 分布在多个进程/机器,需要安装pyzmq. 通过pip命令安装。 /> pip install pyzmq 3、安装成功,CMD敲入命令验证。 /> locust --help 复制代码 Options: -h, --help show this help message and exit -H HOST, --host=HOST Host to load test in the following format: http://10.21.32.33 --web-host=WEB_HOST Host to bind the web interface to. Defaults to '' (all interfaces) -P PORT, --port=PORT, --web-port=PORT Port on which to run web host -f LOCUSTFILE, --locustfile=LOCUSTFILE Python module file to import, e.g. '../other.py'. Default: locustfile --master Set locust to run in distributed mode with this process as master --slave Set locust to run in distributed mode with this process as slave --master-host=MASTER_HOST Host or IP address of locust master for distributed load testing. Only used when running with --slave. Defaults to 127.0.0.1. --master-port=MASTER_PORT The port to connect to that is used by the locust master for distributed load testing. Only used when running with --slave. Defaults to 5557. Note that slaves will also connect to the master node on this port + 1. --master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --no-web Disable the web interface, and instead start running the test immediately. Requires -c and -r to be specified. -c NUM_CLIENTS, --clients=NUM_CLIENTS Number of concurrent clients. Only used together with --no-web -r HATCH_RATE, --hatch-rate=HATCH_RATE The rate per second in which clients are spawned. Only used together with --no-web -n NUM_REQUESTS, --num-request=NUM_REQUESTS Number of requests to perform. Only used together with --no-web -L LOGLEVEL, --loglevel=LOGLEVEL Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO. --logfile=LOGFILE Path to log file. If not set, log will go to stdout/stderr --print-stats Print stats in the console --only-summary Only print the summary stats -l, --list Show list of possible locust classes and exit --show-task-ratio print table of the locust classes' task execution ratio --show-task-ratio-json print json data of the locust classes' task execution ratio -V, --version show program's version number and exit 复制代码 参数说明: 复制代码 -h, --help 查看帮助 -H HOST, --host=HOST 指定被测试的主机,采用以格式:http://10.21.32.33 --web-host=WEB_HOST 指定运行 Locust Web 页面的主机,默认为空 ''。 -P PORT, --port=PORT, --web-port=PORT 指定 --web-host 的端口,默认是8089 -f LOCUSTFILE, --locustfile=LOCUSTFILE 指定运行 Locust 性能测试文件,默认为: locustfile.py --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE 以CSV格式存储当前请求测试数据。 --master Locust 分布式模式使用,当前节点为 master 节点。 --slave Locust 分布式模式使用,当前节点为 slave 节点。 --master-host=MASTER_HOST 分布式模式运行,设置 master 节点的主机或 IP 地址,只在与 --slave 节点一起运行时使用,默认为:127.0.0.1. --master-port=MASTER_PORT 分布式模式运行, 设置 master 节点的端口号,只在与 --slave 节点一起运行时使用,默认为:5557。注意,slave 节点也将连接到这个端口+1 上的 master 节点。 --master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --expect-slaves=EXPECT_SLAVES How many slaves master should expect to connect before starting the test (only when --no-web used). --no-web no-web 模式运行测试,需要 -c 和 -r 配合使用. -c NUM_CLIENTS, --clients=NUM_CLIENTS 指定并发用户数,作用于 --no-web 模式。 -r HATCH_RATE, --hatch-rate=HATCH_RATE 指定每秒启动的用户数,作用于 --no-web 模式。 -t RUN_TIME, --run-time=RUN_TIME 设置运行时间, 例如: (300s, 20m, 3h, 1h30m). 作用于 --no-web 模式。 -L LOGLEVEL, --loglevel=LOGLEVEL 选择 log 级别(DEBUG/INFO/WARNING/ERROR/CRITICAL). 默认是 INFO. --logfile=LOGFILE 日志文件路径。如果没有设置,日志将去 stdout/stderr --print-stats 在控制台中打印数据 --only-summary 只打印摘要统计 --no-reset-stats Do not reset statistics once hatching has been completed。 -l, --list 显示测试类, 配置 -f 参数使用 --show-task-ratio 打印 locust 测试类的任务执行比例,配合 -f 参数使用. --show-task-ratio-json 以 json 格式打印 locust 测试类的任务执行比例,配合 -f 参数使用. -V, --version 查看当前 Locust 工具的版本. 复制代码 4、Locust主要由下面的几个库构成: 1) gevent gevent是一种基于协程的Python网络库,它用到Greenlet提供的,封装了libevent事件循环的高层同步API。 2) flask Python编写的轻量级Web应用框架。 3) requests Python Http库 4) msgpack-python MessagePack是一种快速、紧凑的二进制序列化格式,适用于类似JSON的数据格式。msgpack-python主要提供MessagePack数据序列化及反序列化的方法。 5) six Python2和3兼容库,用来封装Python2和Python3之间的差异性 6) pyzmq pyzmq是zeromq(一种通信队列)的Python绑定,主要用来实现Locust的分布式模式运行 当我们在安装 Locust 时,它会检测我们当前的 Python 环境是否已经安装了这些库,如果没有安装,它会先把这些库一一装上。并且对这些库版本有要求,有些是必须等于某版本,有些是大于某版本。我们也可以事先把这些库全部按要求装好,再安装Locust时就会快上许多。 三、编写接口压测脚本文件locustfile.py 复制代码 1 from locust import HttpLocust, TaskSet, task 2 3 class ScriptTasks(TaskSet): 4 def on_start(self): 5 self.client.post("/login", { 6 "username": "test", 7 "password": "123456" 8 }) 9 10 @task(2) 11 def index(self): 12 self.client.get("/") 13 14 @task(1) 15 def about(self): 16 self.client.get("/about/") 17 18 @task(1) 19 def demo(self): 20 payload={} 21 headers={} 22 self.client.post("/demo/",data=payload, headers=headers) 23 24 class WebsiteUser(HttpLocust): 25 task_set = ScriptTasks 26 host = "http://example.com" 27 min_wait = 1000 28 max_wait = 5000 复制代码 脚本解读: 复制代码 1、创建ScriptTasks()类继承TaskSet类: 用于定义测试业务。 2、创建index()、about()、demo()方法分别表示一个行为,访问http://example.com。用@task() 装饰该方法为一个任务。1、2表示一个Locust实例被挑选执行的权重,数值越大,执行频率越高。在当前ScriptTasks()行为下的三个方法得执行比例为2:1:1 3、WebsiteUser()类: 用于定义模拟用户。 4、task_set : 指向一个定义了的用户行为类。 5、host: 指定被测试应用的URL的地址 6、min_wait : 用户执行任务之间等待时间的下界,单位:毫秒。 7、max_wait : 用户执行任务之间等待时间的上界,单位:毫秒。 复制代码 脚本使用场景解读: 在这个示例中,定义了针对http://example.com网站的测试场景:先模拟用户登录系统,然后随机地访问首页(/)和关于页面(/about/),请求比例为2:1,demo方法主要用来阐述client对post接口的处理方式;并且,在测试过程中,两次请求的间隔时间为1->5秒间的随机值。 从脚本中可以看出,脚本主要包含两个类,一个是WebsiteUser(继承自HttpLocust,而HttpLocust继承自Locust),另一个是ScriptTasks(继承自TaskSet)。事实上,在Locust的测试脚本中,所有业务测试场景都是在Locust和TaskSet两个类的继承子类中进行描的。 那如何理解Locust和TaskSet这两个类呢?简单地说,Locust类就好比是一群蝗虫,而每一只蝗虫就是一个类的实例。相应的,TaskSet类就好比是蝗虫的大脑,控制着蝗虫的具体行为,即实际业务场景测试对应的任务集。 四、Locust类 实例脚本 伪代码: 复制代码 from locust import HttpLocust, TaskSet, task class WebsiteTasks(TaskSet): def on_start(self): #进行初始化的工作,每个Locust用户开始做的第一件事 payload = { "username": "test_user", "password": "123456", } header = { "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", } self.client.post("/login",data=payload,headers=header)#self.client属性使用Python request库的所有方法,调用和使用方法和requests完全一致; @task(5) #通过@task()装饰的方法为一个事务,方法的参数用于指定该行为的执行权重,参数越大每次被虚拟用户执行的概率越高,默认为1 def index(self): self.client.get("/") @task(1) def about(self): self.client.get("/about/") class WebsiteUser(HttpLocust): host = "https://github.com/" #被测系统的host,在终端中启动locust时没有指定--host参数时才会用到 task_set = WebsiteTasks #TaskSet类,该类定义用户任务信息,必填。这里就是:WebsiteTasks类名,因为该类继承TaskSet; min_wait = 5000 #每个用户执行两个任务间隔时间的上下限(毫秒),具体数值在上下限中随机取值,若不指定默认间隔时间固定为1秒 max_wait = 15000 复制代码 伪代码中对https://github.com/网站的测试场景,先模拟用户登录系统,然后随机访问首页/和/about/,请求比例5:1,并且在测试过程中,两次请求的间隔时间1-5秒的随机值; on_start方法,在正式执行测试前执行一次,主要用于完成一些初始化的工作,例如登录操作; WebsiteTasks类中如何去调用 WebsiteUser(HttpLocust)类中定义的字段和方法呢? 通过在WebsiteTasks类中self.locust.xxoo xxoo就是我们在WebsiteUser类中定义的字段或方法; 伪代码: 复制代码 from locust import HttpLocust, TaskSet, task import hashlib import queue class WebsiteTasks(TaskSet): @task(5) def index(self): data = self.locust.user_data_queue #获取WebsiteUser里面定义的ser_data_queue队列 md5_data=self.locust.md5_encryption() #获取WebsiteUser里面定义的md5_encryption()方法 self.client.get("/") class WebsiteUser(HttpLocust): host = "https://github.com/" task_set = WebsiteTasks min_wait = 5000 max_wait = 15000 user_data_queue = queue.Queue() def md5_encryption(self,star): '''md5加密方法''' obj = hashlib.md5() obj.update(bytes(star,encoding="utf-8")) result = obj.hexdigest() return result 复制代码 伪代码中测试场景如何表达? 代码主要包含两个类: WebsiteUser继承(HttpLocust,而HttpLocust继承自Locust) WebsiteTasks继承(TaskSet) 在Locust测试脚本中,所有业务测试场景都是在Locust和TaskSet两个类的继承子类中进行描述; 简单说:Locust类就类似一群蝗虫,而每只蝗虫就是一个类的实例。TaskSet类就类似蝗虫的大脑,控制蝗虫的具体行为,即实际业务场景测试对应的任务集; 源码中:class Locust(object)和class HttpLocust(Locust) 复制代码 1 class Locust(object): 2 """ 3 Represents a "user" which is to be hatched and attack the system that is to be load tested. 4 5 The behaviour of this user is defined by the task_set attribute, which should point to a 6 :py:class:`TaskSet ` class. 7 8 This class should usually be subclassed by a class that defines some kind of client. For 9 example when load testing an HTTP system, you probably want to use the 10 :py:class:`HttpLocust ` class. 11 """ 12 13 host = None 14 """Base hostname to swarm. i.e: http://127.0.0.1:1234""" 15 16 min_wait = 1000 17 """Minimum waiting time between the execution of locust tasks""" 18 19 max_wait = 1000 20 """Maximum waiting time between the execution of locust tasks""" 21 22 task_set = None 23 """TaskSet class that defines the execution behaviour of this locust""" 24 25 stop_timeout = None 26 """Number of seconds after which the Locust will die. If None it won't timeout.""" 27 28 weight = 10 29 """Probability of locust being chosen. The higher the weight, the greater is the chance of it being chosen.""" 30 31 client = NoClientWarningRaiser() 32 _catch_exceptions = True 33 34 def __init__(self): 35 super(Locust, self).__init__() 36 37 def run(self): 38 try: 39 self.task_set(self).run() 40 except StopLocust: 41 pass 42 except (RescheduleTask, RescheduleTaskImmediately) as e: 43 44 class HttpLocust(Locust): 45 """ 46 Represents an HTTP "user" which is to be hatched and attack the system that is to be load tested. 47 48 The behaviour of this user is defined by the task_set attribute, which should point to a 49 :py:class:`TaskSet ` class. 50 51 This class creates a *client* attribute on instantiation which is an HTTP client with support 52 for keeping a user session between requests. 53 """ 54 55 client = None 56 """ 57 Instance of HttpSession that is created upon instantiation of Locust. 58 The client support cookies, and therefore keeps the session between HTTP requests. 59 """ 60 def __init__(self): 61 super(HttpLocust, self).__init__() 62 if self.host is None: 63 raise LocustError("You must specify the base host. Either in the host attribute in the Locust class, or on the command line using the --host option.") 64 self.client = HttpSession(base_url=self.host) 复制代码 在Locust类中,静态字段client即客户端的请求方法,这里的client字段没有绑定客户端请求方法,因此在使用Locust时,需要先继承Locust类class HttpLocust(Locust),然后在self.client =HttpSession(base_url=self.host)绑定客户端请求方法; 对于常见的HTTP(s)协议,Locust已经实现了HttpLocust类,其self.client=HttpSession(base_url=self.host),而HttpSession继承自requests.Session。因此在测试HTTP(s)的Locust脚本中,可以通过client属性来使用Python requests库的所 有方法,调用方式与 reqeusts完全一致。另外,由于requests.Session的使用,client的方法调用之间就自动具有了状态记忆功能。常见的场景就是,在登录系统后可以维持登录状态的Session,从而后续HTTP请求操作都能带上登录状态; Locust类中,除了client属性,还有几个属性需要关注: task_set ---> 指向一个TaskSet类,TaskSet类定义了用户的任务信息,该静态字段为必填; max_wait/min_wait ---> 每个用户执行两个任务间隔的上下限(毫秒),具体数值在上下限中随机取值,若不指定则默认间隔时间为1秒; host --->被测试系统的host,当在终端中启动locust时没有指定--host参数时才会用到; weight--->同时运行多个Locust类时,用于控制不同类型的任务执行权重; Locust流程,测试开始后,每个虚拟用户(Locust实例)运行逻辑都会遵守如下规律: 先执行Website
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信