【性能学习】locust --hellp
1. Locust简介
Locust是使用Python语言编写实现的开源性能测试工具,简洁、轻量、高效,并发机制基于gevent协程,可以实现单机模拟生成较高的并发压力。
主要特点如下:
1) 使用普通的Python脚本用户测试场景
2) 分布式和可扩展,支持成千上万的用户
3) 基于Web的用户界面,用户可以实时监控脚本运行状态
4) 几乎可以测试任何系统,除了web http接口外,还可自定义clients测试其他类型系统
2. 安装
使用pip或easy_install,可以方便安装Locust
1 pip install locustio
安装完成后,可以在shell或cmd中运行locust命令,如查看可用的选项:
1 locust --help
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的分布式模式运行
3. 快速入门
1 Usage: locust [options] [LocustClass [LocustClass2 ... ]] 2 3 Options: 4 -h, --help show this help message and exit 5 -H HOST, --host=HOST Host to load test in the following format: 6 http://10.21.32.33 7 --web-host=WEB_HOST Host to bind the web interface to. Defaults to '' (all 8 interfaces) 9 -P PORT, --port=PORT, --web-port=PORT 10 Port on which to run web host 11 -f LOCUSTFILE, --locustfile=LOCUSTFILE 12 Python module file to import, e.g. '../other.py'. 13 Default: locustfile 14 --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE 15 Store current request stats to files in CSV format. 16 --master Set locust to run in distributed mode with this 17 process as master 18 --slave Set locust to run in distributed mode with this 19 process as slave 20 --master-host=MASTER_HOST 21 Host or IP address of locust master for distributed 22 load testing. Only used when running with --slave. 23 Defaults to 127.0.0.1. 24 --master-port=MASTER_PORT 25 The port to connect to that is used by the locust 26 master for distributed load testing. Only used when 27 running with --slave. Defaults to 5557. Note that 28 slaves will also connect to the master node on this 29 port + 1. 30 --master-bind-host=MASTER_BIND_HOST 31 Interfaces (hostname, ip) that locust master should 32 bind to. Only used when running with --master. 33 Defaults to * (all available interfaces). 34 --master-bind-port=MASTER_BIND_PORT 35 Port that locust master should bind to. Only used when 36 running with --master. Defaults to 5557. Note that 37 Locust will also use this port + 1, so by default the 38 master node will bind to 5557 and 5558. 39 --heartbeat-liveness=HEARTBEAT_LIVENESS 40 set number of seconds before failed heartbeat from 41 slave 42 --heartbeat-interval=HEARTBEAT_INTERVAL 43 set number of seconds delay between slave heartbeats 44 to master 45 --expect-slaves=EXPECT_SLAVES 46 How many slaves master should expect to connect before 47 starting the test (only when --no-web used). 48 --no-web Disable the web interface, and instead start running 49 the test immediately. Requires -c and -r to be 50 specified. 51 -c NUM_CLIENTS, --clients=NUM_CLIENTS 52 Number of concurrent Locust users. Only used together 53 with --no-web 54 -r HATCH_RATE, --hatch-rate=HATCH_RATE 55 The rate per second in which clients are spawned. Only 56 used together with --no-web 57 -t RUN_TIME, --run-time=RUN_TIME 58 Stop after the specified amount of time, e.g. (300s, 59 20m, 3h, 1h30m, etc.). Only used together with --no- 60 web 61 -L LOGLEVEL, --loglevel=LOGLEVEL 62 Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. 63 Default is INFO. 64 --logfile=LOGFILE Path to log file. If not set, log will go to 65 stdout/stderr 66 --print-stats Print stats in the console 67 --only-summary Only print the summary stats 68 --no-reset-stats [DEPRECATED] Do not reset statistics once hatching has 69 been completed. This is now the default behavior. See 70 --reset-stats to disable 71 --reset-stats Reset statistics once hatching has been completed. 72 Should be set on both master and slaves when running 73 in distributed mode 74 -l, --list Show list of possible locust classes and exit 75 --show-task-ratio print table of the locust classes' task execution 76 ratio 77 --show-task-ratio-json 78 print json data of the locust classes' task execution 79 ratio 80 -V, --version show program's version number and exit
3.1 示例
1 #coding:utf-8 2 from locust import HttpLocust, TaskSet, task 3 4 class UserBehavior(TaskSet): 5 def on_start(self): 6 """ on_start is called when a Locust start before any task is scheduled """ 7 self.login() 8 9 def login(self): 10 self.client.post("/login", {"username":"ellen_key", "password":"education"}) 11 12 @task(2) 13 def index(self): 14 self.client.get("/") 15 16 @task(1) 17 def profile(self): 18 self.client.get("/profile") 19 20 class WebsiteUser(HttpLocust): 21 task_set = UserBehavior 22 host='http://example.com' 23 min_wait = 5000 24 max_wait = 9000
上面是官方的示例demo,定义了针对http://example.com网站的测试场景:先模拟用户登录系统,然后随机地访问index(/)和profile页面(/profile/),请求比例为2:1;并且,在测试过程中,两次请求的间隔时间为5~9秒间的随机值。
3.2 运行
要运行上述locust脚本,如果文件名为locustfile.py且在当前目录下,可以这样运行:
1 locust
如果locust脚本文件目录不同或名称不同,需要使用-f指定文件(--host用来指定测试主机地址):
1 locust -f locust_files/my_locust_file.py --host=http://example.com
要运行分布在多个进程上的locust,我们需要使用--master启动主进程:
1 locust -f locust_files/my_locust_file.py --master --host=http://example.com
之后使用--slave启动任意数量的从进程:
1 locust -f locust_files/my_locust_file.py --slave --host=http://example.com
如果在多台机器上分布式运行locust,我们需要在启动从进程时指定master-host(默认为127.0.0.1):
1 locust -f locust_files/my_locust_file.py --slave --master-host=192.168.0.100 --host=http://example.com
3.3 Locust web模式
Locust默认使用该方式启动,启动后在本机打开http://localhost:8089/,可以看到Locust WEB页面,设置并发用户数及每秒请求数后即可开始性能测试。
3.4 Locust no-web模式
Locust也可使用no-web模式,使用命令如下:
1 locust -f locust_files/my_locust_file.py --no-web --csv=locust -c10 -r2 --run-time 1h30m
其中--no-web表示使用no-web模式,--csv表示运行结果文件名,-c 并发用户数,-r 每秒请求数,--run_time 运行时间
4. locustfile详解
locustfile中测试场景均是继承自Locust和TaskSet的子类,下面分别介绍Locust和TaskSet两个类。
4.1 Locust类
Locust类的client属性对应虚拟用户作为客户端的请求方法。在使用Locust时,需要先继承Locust类,然后在继承子类中的client属性中绑定客户端的实现类。
对于常见的HTTP(S)协议,Locust已经实现了HttpLocust类,其client属性绑定了HttpSession类,而HttpSession又继承自requests.Session。因此在测试HTTP(S)的Locust脚本中,我们可以通过client属性来使用Python requests库的所有方法,包括GET/POST/HEAD/PUT/DELETE/PATCH等,调用方式也与requests完全一致。另外,由于requests.Session的使用,因此client的方法调用之间就自动具有了状态记忆的功能。常见的场景就是,在登录系统后可以维持登录状态的Session,从而后续HTTP请求操作都能带上登录状态。
而对于HTTP(S)以外的协议,我们同样可以使用Locust进行测试,只是需要我们自行实现客户端。在客户端的具体实现上,可通过注册事件的方式,在请求成功时触发events.request_success,在请求失败时触发events.request_failure即可。然后创建一个继承自Locust类的类,对其设置一个client属性并与我们实现的客户端进行绑定。主要,我们就可以像使用HttpLocust类一样,测试其它协议类型的系统了。
在Locust类中,除了client属性,还有几个属性需要关注下:
task_set: 指向一个TaskSet类,TaskSet类定义了用户的任务信息,该属性为必填;
max_wait/min_wait: 每个用户执行两个任务间隔时间的上下限(毫秒),具体数值在上下限中随机取值,若不指定则默认间隔时间固定为1秒;
host:被测系统的host,当在终端中启动locust时没有指定--host参数时才会用到;
weight:同时运行多个Locust类时会用到,用于控制不同类型任务的执行权重。
测试开始后,每个虚拟用户(Locust实例)的运行逻辑都会遵循如下规律:
先执行WebsiteTasks中的on_start(只执行一次),作为初始化;
从WebsiteTasks中随机挑选(如果定义了任务间的权重关系,那么就是按照权重关系随机挑选)一个任务执行;
根据Locust类中min_wait和max_wait定义的间隔时间范围(如果TaskSet类中也定义了min_wait或者max_wait,以TaskSet中的优先),在时间范围中随机取一个值,休眠等待;
重复2~3步骤,直至测试任务终止。
4.2 Taskset类
TaskSet类实现了虚拟用户所执行任务的调度算法,包括规划任务执行顺序(schedule_task)、挑选下一个任务(execute_next_task)、执行任务(execute_task)、休眠等待(wait)、中断控制(interrupt)等等。在此基础上,我们就可以在TaskSet子类中采用非常简洁的方式来描述虚拟用户的业务测试场景,对虚拟用户的所有行为(任务)进行组织和描述,并可以对不同任务的权重进行配置。
在TaskSet子类中定义任务信息时,可以采取两种方式,@task装饰器和tasks属性。
采用@task装饰器定义任务信息时,描述形式如下:
1 from locust import TaskSet, task 2 class UserBehavior(TaskSet): 3 @task(1) 4 def test_job1(self): 5 self.client.get('/job1') 6 @task(2) 7 def test_job2(self): 8 self.client.get('/job2')
采用tasks属性定义任务信息时,描述形式如下:
1 from locust import TaskSet 2 def test_job1(obj): 3 obj.client.get('/job1') 4 def test_job2(obj): 5 obj.client.get('/job2') 6 class UserBehavior(TaskSet): 7 tasks = {test_job1:1, test_job2:2} 8 # tasks = [(test_job1,1), (test_job1,2)] # 两种方式等价
在如上两种定义任务信息的方式中,均设置了权重属性,即执行test_job2的频率是test_job1的两倍。
在TaskSet子类中除了定义任务信息,还有一个是经常用到的是on_start函数。这个和LoadRunner中的vuser_init功能相同,在正式执行测试前执行一次,主要用于完成一些初始化的工作。例如,当测试某个搜索功能,而该搜索功能又要求必须为登录态的时候,就可以先在on_start中进行登录操作;前面也提到,HttpLocust使用到了requests.Session,因此后续所有任务执行过程中就都具有登录状态了。
5. 自定义客户端测试其他系统
虽然,locust主要是为了测试HTTP而生。然而,它可以很容易地扩展到测试任何基于请求/响应的系统,只需要编写一个触发request_success和request_failure事件自定义客户端即可。
官网提供了详细的示例,我们简单修改下就可以用来对任意系统进行性能测试:
1 import time 2 from locust import Locust, TaskSet, events, task 3 import requests 4 5 6 class TestHttpbin(object): 7 def status(self): 8 try: 9 r = requests.get('http://httpbin.org/status/200') 10 status_code = r.status_code 11 print status_code 12 assert status_code == 200, 'Test Index Error: {0}'.format(status_code) 13 except Exception as e: 14 print e 15 16 17 class CustomClient(object): 18 def test_custom(self): 19 start_time = time.time() 20 try: 21 # add your custom test function here 22 TestHttpbin().status() 23 name = TestHttpbin().status.__name__ 24 except Exception as e: 25 total_time = int((time.time() - start_time) * 1000) 26 events.request_failure.fire(request_type="Custom", name=name, response_time=total_time, exception=e) 27 else: 28 total_time = int((time.time() - start_time) * 1000) 29 events.request_success.fire(request_type="Custom", name=name, response_time=total_time, response_length=0) 30 31 32 class CustomLocust(Locust): 33 def __init__(self, *args, **kwargs): 34 super(CustomLocust, self).__init__(*args, **kwargs) 35 self.client = CustomClient() 36 37 38 class ApiUser(CustomLocust): 39 min_wait = 100 40 max_wait = 1000 41 42 class task_set(TaskSet): 43 @task(1) 44 def test_custom(self): 45 self.client.test_custom()
上述脚本里,我们自定义一个测试类TestHttpbin,其中status方法用来校验接口返回码;我们只需要在CustomClient类的test_custom方法中添加自定义的测试方法TestHttpbin().status(),即可使用locust对该方法进行负载测试。
taffy框架就是这样做实现了一份代码同时进行功能自动化及性能测试。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!