Locust-入门
背景:
目前网上的教程基本都是1.0之前的,locust丛1.0版本就发生了较多的变化,网上的教程基本不可用了。本文基于locust最新版本2.5.1,作为笔记也作为入门教程分享。
(备注:只讲 框架的使用 ,不涉及性能测试理论知识)
一、什么是Locust
Locust 是一种易于使用、可直接使用pyhton编写脚本运行且可扩展的性能测试工具。
二、特点
- 直接使用python 编写测试脚本
- 支持分布式和可扩展-支持数十万并发用户
- 提供友好的web界面
- 可以测试任何系统
- 小且灵活
locust 的web 运行界面
locust 提供了友好的web界面用于监控性能测试过程中的相关数据
启动页
测试监控界面
type | 请求类型 | |
Name | 请求名称 | 这个可以自定义,传name参数即可 |
Requests | 当前已完成的请求数量 | |
Fails | 失败的请求数量 | |
Requests | 当前已完成的请求数量 | |
Median | 响应时间的中间值,即50%的响应时间在这个数值范围内,单位为毫秒 | |
90%ile | 90%的响应时间在正态分布平均值下方,即小于这个值 | |
Min | 最小响应时间,单位为毫秒 | |
Max | 最大响应时间,单位为毫秒 | |
average Size | 平均每个请求的数据量,单位为字节 | |
current RPS | 每秒钟处理请求的数量 |
RPS(TPS)
响应时间
Users
测试任务统计
支持下载测试报告
进程信息,这里启动了5个进程,用户数为500,被平均分给了5个进程,
三、编写任务
名词解释:
任务:简单的理解就是,你想要你脚本的虚拟用户去做哪些事,比如请求某一个接口,或者执行某一个事件。
用户:可以理解为,执这个任务的实例主体,或者在locust 中,也可以认为是一群蝗虫
旧版本使用的是TaskSet进行任务或者请求编写,然后在使用HttpLocust进行任务或者请求声明,以及基础属性配置,一般会进行思考时间、host、task_set设置任务类等;新版本将HttpLocust重写成User,并且HttpUser继承于User,所以推荐使用HttpUser进行任务声明;另外TaskSet中的task_set已被删除,如果仍要使用TaskSet,则需要在HttpUser中使用tasks进行存储
TaskSet 类 进行任务编写
TaskSet是定义用户将执行的一组任务的类,然后通过虚拟用户调用并执行这一组任务
单个任务集合:
from locust import TaskSet, task,User import os ''' 通过TaskSet 编写任务
''' class Task_1(TaskSet): @task def task1(self): print('task1----------') @task def task2(self): print('task2----------') @task def task3(self): print('task3----------') class task_conf(User): tasks = [Task_1] if __name__ == '__main__': os.system('locust -f TaskSet定义用户任务.py --web-host "127.0.0.1"')
多个任务集合
切记 不要忘记调用调用 self.interrupt() 以跳出当前任务集
from locust import TaskSet, task,User import os ''' TaskSet类定义了每个用户的任务集合, 注意:如果存在多个任务集合,需要在每个任务集合中调用interrupt()方法, 否则用户一旦进入到这个用户,则无法跳出这个任务集合(会一直执行这个任务集) ''' class Task_1(TaskSet): @task def task1(self): print('task1----------') @task def task2(self): print('task2----------') @task def task3(self): print('task3----------') #调用interrupt() 非常重要,否则用户将难以自拔 @task def logout(self): self.interrupt() class Task_2(TaskSet): @task def task21(self): print('task21----------') @task def task22(self): print('task22----------') @task def task23(self): print('task23----------') @task def logout(self): self.interrupt() class task_conf(User): tasks = [Task_1,Task_2]
if __name__ == '__main__': os.system('locust -f TaskSet定义用户任务_多个.py --web-host "127.0.0.1"')
User类 编写任务
User 执行测试任务的主体类,用户的行为由其任务定义
from locust import TaskSet, task,User import os ''' 通过TaskSet 定义任务 ''' class Task_1(User): @task def task1(self): print('task1----------') @task def task2(self): print('task2----------') @task def task3(self): print('task3----------') if __name__ == '__main__': os.system('locust -f User定义用户任务.py --web-host "127.0.0.1"')
任务属性
测试开始时,locust将为每一个模拟用户创建一个User类的实例,每个实例都在他们自己的微线程中执行,当这些用户运行时,开始选中要执行的任务,休眠一段时间,然后选一个新的任务,继续执行,以此类推。
这里我们为用户添加任务的方式有两种
- 使用@task 装饰器
- 设置tasks属性
@task
通过@task 定义用户任务 任务 ,同时还可以通过@task(int) 设置每个任务的权重
from locust import task,User
import os
# 通过@task 定义用户任务 任务 ,同时还可以通过@task(int) 设置每个任务的权重
class task_2(User):
@task(2)
def task1(self):
print('执行任务1')
@task(2)
def task2(self):
print('执行任务2')
@task(1)
def task3(self):
print('执行任务3')
if __name__ == '__main__':
os.system('locust -f task装饰器声明任务.py --web-host="127.0.0.1"')
tasks
tasks属性可以是一个 Task 列表,也可以是一个 {'Task':int} 的dict, Task可以是 一个测试方法或者函数,也可以是任务集合TakSet类
以User类为例
from locust import User
import os
'''
继承TaskSet,不按顺序执行任务,
'''
# 通过tasks 定义测试任务
class task_1(User):
def task1(self):
print('执行任务1')
def task2(self):
print('执行任务2')
def task3(self):
print('执行任务3')
# 通过tasks 定义测试任务 并设置对应任务执行权重
tasks = [task1, task2, task3]
# tasks = {task1:1,task2:2,task3:2}
if __name__ == '__main__':
os.system('locust -f tasks属性声明用户任务.py --web-host="127.0.0.1"')
任务标记@tag
可以通过标记的方式,执行负载测试时,让虚拟用户只执行指定的测试任务
from locust import User,tag
'''
设置tag,用于设置用户 执行指定标记的任务
'''
class myUser(User):
@tag('回归')
def task_1(self):
print('回归任务')
@tag('预发')
def task_2(self):
print('任务2')
@tag('回归','预发')
def task_3(self):
print('回归任务+预发任务')
tasks = [task_1,task_2,task_3]
if __name__ == '__main__':
import os
os.system('locust -f locust_user_tag.py --tags 回归 --web-host="127.0.0.1"')
User类的一些通用属性
Locust 将为每个用户生成一个 User 类的实例。用户类可以定义一些通用属性。
wait_time 属性:
用于模拟用户每次执行任务后的延迟时间(等同思考时间),如果未指定,则下一个任务将在完成后立即执行。
- constant(x) 固定时间
- between(x,y) 最小值和最大值之间的随机时间
- constant_packing(x) 每x秒 最多运行一次任务
- constant_throughtput(x) 每秒最多运行x次
constant
from locust import constant, task,User import os ''' wait_time = constant() 等待一个固定的时间 ''' class Task_1(User): @task def task1(self): print('task1----------') @task def task2(self): print('task2----------') @task def task3(self): print('task3----------') # 用户执行每个任务,会固定等待5s wait_time = constant(5) if __name__ == '__main__': os.system('locust -f task_wait_constant.py --web-host "127.0.0.1"')
between
from locust import between, task, User import os ''' wait_time = between() 等待一个最小值和最大值之间的随机时间 不含最大时间 ''' class Task_1(User): @task def task1(self): print('task1----------') @task def task2(self): print('task2----------') @task def task3(self): print('task3----------') # 用户执行每个任务,会固定等待[1,5) 秒 wait_time = between(1,5) if __name__ == '__main__': os.system('locust -f task_wait_between.py --web-host "127.0.0.1"')
weight权重属性
用于设置特定类型的用户的 权重值,在未设置的情况下,locust将为每个用户类生产相同数量的用户实例
比如app用户是web用户的3倍
from locust import User # app用户数量是web用户数量的3倍 class appUser(User): weight = 3 def task_1(self): print('app任务1') def task_2(self): print('app任务2') tasks = [task_1,task_2] class webUser(User): weight = 1 def task_A(self): print('web任务1') def task_B(self): print('web任务2') tasks = [task_A, task_B] if __name__ == '__main__': import os os.system('locust -f locust_user_weight.py --web-host="127.0.0.1"')
host 主机属性:
用于加载主机的url 前缀,(比如:http://baidu.com)
也可以在 webui中指定,或者命令参数中指定--host
from locust import task,HttpUser import os ''' 主机属性 host ''' class task_s(HttpUser): host = 'http://wthrcdn.etouch.cn' @task def task_1(self): url = '/weather_mini?city=杭州' # body = {'city':'杭州'} res = self.client.request(method='get',url=url) print(res.json()) if __name__ == '__main__': os.system('locust -f locust_host.py --web-host="127.0.0.1"')
前后置方法 on_start和on_stop方法
用户将 on_start在它开始运行时调用它的方法
on_stop在它停止运行时调用它的方法。
from locust import User,constant ''' 每个虚拟用户 执行前 会执行一次该方法(在一次测试结束后,只会执行一次) ''' class myuser(User): wait_time = constant(2) def on_start(self): print('登录') def on_stop(self): print('登出') def task_1(self): print('任务1') tasks = [task_1] if __name__ == '__main__': import os os.system('locust -f locust_start_stop.py --web-host="127.0.0.1"')
HttpUser类
HttpUser是最常用的 User ,它通过client 发送Http请求,client是httpsession的一个实例(requests模块的session),故在locust中,通过client 发送的请求,具有天然的保持会话能力。
发送http请求
from locust import HttpUser,task
import os
class TaskA(HttpUser):
#登录
def on_start(self):
url = 'https://www.processon.com/login/quick_login'
data = {'type': 'account_login',
'login_email': 12345678901,
'login_password': '123456',
}
r = self.client.request('post', url=url, data=data)
#登录成功调用个人信息接口
@task
def test_login(self):
url = 'https://www.processon.com/setting/account'
r = self.client.request('post', url=url)
print(r.text)
if __name__ == '__main__':
os.system('locust -f http_通过session请求.py --web-host="127.0.0.1"')
响应检查
HttpUser 支持设置响应检查点
使用catch_response参数、with语句和对response.failure() 标记为失败
from locust import HttpUser, task
import os
from json import JSONDecodeError
import jsonpath
class task_s(HttpUser):
@task
def task_1(self):
get_url = 'http://wthrcdn.etouch.cn/weather_mini?city=杭州'
with self.client.request(method='get', url=get_url,catch_response=True) as response:
try:
# 获取响应内容的status 字段值
status = response.json()['status']
# 获取响应时间
# rt = response.elapsed.total_seconds()
# print(rt)
# 如果status为1000则为成功,否则为失败
if status == 1000:
response.success()
# if rt <= 0.001:
# response.success()
# else:
# response.failure('响应超时')
else:
response.failure('非法的参数')
except JSONDecodeError:
response.failure('Response could not be decoded as JSON')
if __name__ == '__main__':
os.system('locust -f locust_HttpUse_检查响应.py --web-host="127.0.0.1"')
FastHttpUser (locust大杀器)
Locust 的默认 HTTP 客户端使用python-requests,而requests库是一个同步阻塞库(每个请求发送完成之后都在等待响应的回来,这在高并发场景下是致命的)
正因为如此,Locust 还附带FastHttpUser使用geventhttpclient代替。它提供了一个非常相似的 API,并且使用的 CPU 时间显着减少,通常情况下将给定硬件上每秒的最大请求数增加了 5 到 6 倍。
使用上:只需继承 FastHttpUser 就可以了,其他和 HttpUser 没有什么太大的差别
from locust import task,FastHttpUser import os import logging as log class task_s(FastHttpUser): host = 'http://wthrcdn.etouch.cn' @task def task_1(self): get_url = '/weather_mini?city=杭州' self.client.request(method='get', path=get_url) # with self.client.request(method='get', path=get_url,catch_response=True) as response: # status = response.json()['status'] # if status ==1000: # response.success() # # else: # response.failure('请求失败') if __name__ == '__main__': os.system('start locust -f 通过FastHttpUser多进程发送请求.py --master --web-host="127.0.0.1"') for i in range(8): os.system('start locust -f 通过FastHttpUser多进程发送请求.py --worker')
并发数1500,tps在9000左右
对比jmeter,并发数1500, tps在 8000左右
四、运行方式
命令参数运行
#进入当前模块文件目录,直接输入 locust #非当前文件目录 locust -f xx/xx.py #指定host locust -f xx/xx.py --host=https://www.cnblogs.com #指定locust webui 界面地址, locust -f xx/xx.py --web-host ="127.0.0.1" #不带ui界面运行, locust -f xx/xx.py --headless -u 1000 -r 100 --run-time 5m --headless 没有webui的情况下运行 -u 要生成的用户数 -r 每秒启动的用户数 --run-time 5m 设置测试执行时间 这里是5分钟,时间到了就会停止运行
#多进程运行 主模式启动 8089端口用于web界面 ,5557用于从机交互 locust -f xx/xx.py --master 启动一个进行执行 locust -f xx/xx.py --worker --master-host=192.168.0.14 (如果单机器运行,则可以省略后面的参数 --master-host=xxx.xxx.xxx.xxx)
配置文件方式运行
locust 支持配置文件方式运行
(本质上也是命令行运行,只不过是把命令参数写在了配置文件中,防止每次输的时候 写错)
默认情况下,locust在~./.locust.conf 和 ./locust.conf ,还可以使用 --config 来指定配置文件运行
# -*- coding: UTF-8 -* ''' # locust 默认读取配置文件的优先级顺序(覆盖读取) # ~/locust.conf -> ./locust.conf ->(file specified using --conf) # 注意:如果同时存在 两个配置文件,locust.conf 和 diy.conf # 此时使用 locust --config = diy.conf 读取的将还是locust.conf ''' # 要运行的py文件 locustfile = ./my_locust_file.py # 设置是否带webui运行 headless = false # 设置weiui的地址 web-host= 127.0.0.1 # 设置 host host = http://wthrcdn.etouch.cn # 设置虚拟用户数 users = 500 # 设置每秒增加的用户数 spawn-rate = 10 # 设置运行时间,满足设置的运行时间后,将停止运行 run-time = 1m
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具