locust---详细使用HttpUser写压测请求(时间间隔、任务权重、前置、后置)(二)
1、示例
上一节,我们只是做了一个简单的示例,讲了如何使用HTTP请求压测,实际使用情况更复杂,比如压测时,大部分接口需要先登录(不同用户),再查询数据或者其他操作,操作后再退出登录,而且模拟真实用户请求时,用户不可能一直在请求接口,而是操作后等待几秒后再操作,这些我们下面代码都可以实现。
创建locustfile.py文件,代码如下:
# -*- coding: utf-8 -*-
# @Time : 2023/11/28 10:28
# @Author : 梗小旭
# @File : locustfile.py
from locust import task, HttpUser, between
import random
class MyUser(HttpUser):
# 当任务执行完成后,用户将在等待时间内(在这种情况下为1到5秒)睡眠。等待时间过后,它会选择一个新任务并不断重复。
wait_time = between(1, 5)
# 每个模拟用户启动时都会调用,注意不是模拟用户每次发送请求前调用,只是这个模拟用户生成时才调用。
def on_start(self):
self.client.post("/login", {"userName": "admin", "pwd": "123456"})
print("登录成功。。。")
# 当模拟的用户停止执行任务时,调用on_stop
def on_stop(self):
print("退出登录。。。")
@task
def get_data(self):
self.client.get("/data")
# 没被@task装饰,不会执行
def test(self):
self.client.get("/test")
# 用@task装饰的方法是locust的核心。对于每个正在运行的用户,Locust都会创建一个greenlet(微线程),这将调用这些方法
# @task加参数代表权重,在总的执行任务重,权重占比越大,执行次数越多
@task(3)
def get_item(self):
# name="/item"表示汇总该请求,因为是路径参数,每个路径都不一样,在统计时每个路径都会显示一次
self.client.get(f"/item/{random.choice(range(1, 10))}", name="/item")
if __name__ == '__main__':
import os
os.system("locust -f locustfile.py")
上面用的接口是用flask写的,比较简单,可以作为测试使用,代码如下:
from flask import Flask, request
app = Flask(__name__)
@app.route("/login", methods=["POST"])
def login():
userName = request.json.get("userName")
pwd = request.json.get("pwd")
if request.method == "POST":
if userName == "admin" and pwd == "123456":
return {"code": 200, "msg": "登录成功", "data": {"token": "z23323sdfsfddfwx", "userName": userName}}
else:
return {"code": 404, "msg": "用户名或密码错误", "data": {}}
@app.route('/item/<ids>')
def item(ids):
return {"code": 200, "msg": "成功", "data": {"id": ids}}
@app.route('/data')
def get_data():
return {"code": 200, "msg": "成功", "data": {"name": "zwx"}}
@app.route("/test")
def test():
return {"code": 200, "msg": "测试数据", "data": {}}
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5555, debug=True)
2、执行结果
下面我们启动脚本,可以在命令行执行locust -f locustfile.py,也可以直接使用os.system执行,执行后进入设置参数页面,如图我设置了虚拟用户数为5,Spawn rate设置为1(每秒生成1个用户),host为:http://127.0.0.1:5555,运行总时间为10s。设置完成后开始执行。
执行结果如下,由执行结果可以看出:
- 虚拟用户设置了5,所以on_start在每个用户启动时执行,登录成功打印了5次
- 虚拟用户设置了5,每个虚拟用户执行结束时执行on_stop,退出登录打印了5次
- /test没有被@task装饰,没有被locust识别执行
- /item设置的权重是3,/data是1,所以/item执行的次数是/data的3倍,但是这个数据是接近,不是完全的3倍
3、请求不设置name=“/item”
from locust import task, HttpUser, between
import random
class MyUser(HttpUser):
wait_time = between(1, 5)
@task
def get_item(self):
self.client.get(f"/item/{random.choice(range(1, 10))}")
从执行结果看,如果请求路径是不固定的,不设置name属性,执行结果会把每个路径展示一条数据。
4、不设置wait_time
# -*- coding: utf-8 -*-
# @Time : 2023/11/28 10:28
# @Author : 梗小旭
# @File : locustfile.py
from locust import task, HttpUser, between
import random
class MyUser(HttpUser):
# wait_time = between(1, 5)
# 每个模拟用户启动时都会调用,注意不是模拟用户每次发送请求前调用,只是这个模拟用户生成时才调用。
def on_start(self):
self.client.post("/login", {"userName": "admin", "pwd": "123456"})
print("登录成功。。。")
# 当模拟的用户停止执行任务时,调用on_stop
def on_stop(self):
print("退出登录。。。")
@task
def get_data(self):
self.client.get("/data")
def test(self):
self.client.get("/test")
# 用@task装饰的方法是locust的核心。对于每个正在运行的用户,Locust都会创建一个greenlet(微线程),这将调用这些方法
# @task加参数代表权重,在总的执行任务重,权重占比越大,执行次数越多
@task(3)
def get_item(self):
self.client.get(f"/item/{random.choice(range(1, 10))}", name="/item")
if __name__ == '__main__':
import os
os.system("locust -f locustfile.py")
如果不设置wait_time,启动参数和之前一样,虚拟用户是5,每秒启动1个用户,持续运行10s,执行的请求是几千个,没有间隔等待时间,会一直不间断执行。