简介
基于python的性能测试框架
Locust是易于使用的分布式的负载测试工具。主要对网站进行负载测试,确定系统可以处理多少个并发用户。
locust节点基于协程通过gevent可支持数千并发用户
安装
安装locustio:pip install locustio
安装pyzmq:pip install pyzmq
pyzmq 通信队列的库,支持locust以分布式队列运行
原理
简单使用
1、写压测脚本
from locust import HttpLocust, TaskSet, task
class Userbehave(TaskSet):
@task(1)
def get_blog(self):
# 定义请求头
header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"}
req = self.client.get("/imyalost", headers=header, verify=False)
if req.status_code == 200:
print("success")
else:
print("fails")
class WebsiteUser(HttpLocust):
task_set = Userbehave
min_wait = 1000
max_wait = 2000
host = "https://www.baidu.com"
2、启动性能测试,运行locust -f test.py
3、浏览器打开http://localhost:8089,开始负载测试
locustfile
locustfile:待执行性能测试脚本
一个性能测试脚本中至少需要有一个Locust类或其子类
负载
用Locust 类来定义用户,每个负载为Locust类的一个实例
包括用户的行为及属性.
Locust类
task_set : 指定用户行为集
min_wait :指定多个用户之间执行任务的最小等待时间
max_wait:指定多个用户之间执行任务的最大等待时间
wait_time = between(5, 15)
between: 使模拟用户在每次执行任务后等待介于最小值和最大值之间的随机时间。
wait_time=constant :
wait_time=constant_pacing:
wait_function : 自定义多个用户之间执行任务的等待时间,
如:wait_function = lambda self: random.expovariate(1) * 1000
stop_timeout = 300:设置脚本执行多长时间
host: 要加载主机的URL前缀;也可以在命令行中用–host指定。
weight=3: 当一个脚本中包含多个locust的子类,且在命令行中没有指定Locust,压测时会随机选择locust。如果希望某个locust更常执行,可设置weight
from locust import HttpLocust
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000
host = "https://www.baidu.com"
HttpLocust
1、HttpLocust类是Locust的子类,此类在实例化时比Locust会多了一个client属性,该属性支持发出HTTP请求、在请求之间保留用户session
HTTP客户端
1、初始化HttpLocust实例时会创建一个client属性,它是HttpSession可以用于发出HTTP请求的一个实例
respose = self.client.get("/mobile/api/goods/gettypes")
result = respose.json()
HttpSession
1、HttpSession类实际上是requests.Session的一个子类,可用于发出get,post,put,delete,head,patch和options等HTTP请求并报告给Locust的用于统计。
2、HttpSession实例会在请求之间保存cookie,以便它可以用来登录网站、保持请求会话。
session = HttpSession(base_url=self.host)
session.trust_env = self.trust_env
self.client = session
手动控制请求是成功还是失败
1、HTTP客户端配置默认为以safe_mode运行,任何由于连接错误、超时或者类似错误引起的异常,都会返回一个空的Response对象,这个请求将会再locust统计中标记为failure,返回的虚拟对象Response’content属性将会被置为空,status_code为0。一般不用再使用try…exception处理异常。
默认情况下,返回2xx的状态码的都会标记为success,之外的情况都会被标记为failure,如果想手动改变这种情况,需要手动控制。
with self.client.get("/", catch_response=True) as response:
if response.content != b"Success":
response.failure("Got wrong response")
FastHttpLocust
1、FastHttpLocust使用的客户端非python-request包,而是Locust附带的备用HTTP客户端geventhttpclient,可通过更快的HTTP客户端提高Locust的性能。
2、使用geventhttpclient进行HTTP请求的性能提高了5到6倍
3、使用
from locust import TaskSet, task, between
from locust.contrib.fasthttp import FastHttpLocust
class MyTaskSet(TaskSet):
@task
def index(self):
response = self.client.get("/")
class MyLocust(FastHttpLocust):
task_set = MyTaskSet
wait_time = between(1, 60)
geventhttpclient
任务集
1、任务集是用来指定用户行为的集合
2、定义任务集类时需继承TaskSet类,任务集中包含一个或者多个任务
from locust import TaskSet,task
class UserBehavior(TaskSet):
@task
def on_start(self):
login(self)
3、任务集方法interrupt():停止执行任务集
4、任务集属性 locust
5、on_start()
6、on_stop()
7、setup()
8、teardown()
9、client属性 :在TaskSet中使用的client参数为self.locust.client
@property
def client(self):
return self.locust.client
TaskSequence类
1、是TaskSet的子类,任务将按照定义的任务执行
class MyTaskSequence(TaskSequence):
@seq_task(1)
def first_task(self):
pass
@seq_task(2)
def second_task(self):
pass
@seq_task(3)
@task(10)
def third_task(self):
pass
声明任务
1、使用@task装饰器把一个函数装饰成一个任务,
2、@task使用可选的weight参数指定任务执行的比重
task2的执行量是task1的两倍:
from locust import Locust, TaskSet, task
from locust.wait_time import between
class MyTaskSet(TaskSet):
wait_time = between(5, 15)
@task(3)
def task1(self):
pass
@task(6)
def task2(self):
pass
class MyLocust(Locust):
task_set = MyTaskSet
3、不使用@task,在TaskSet中指定tasks,同样可定义任务
@task装饰器实际上只是填充task属性
class MyTaskSet(TaskSet):
tasks = [my_task]
tasks = {my_task: 3, another_task: 1}
任务嵌套
class ForumPage(TaskSet):
@task(20)
def read_thread(self):
pass
@task(1)
def new_thread(self):
pass
@task(5)
def stop(self):
self.interrupt()
class UserBehaviour(TaskSet):
tasks = {ForumPage:10}
@task
def index(self):
pass
设置断言
assert result[‘code’] ==0
locust参数化
with open("D:\\python\\locust\\mobile.txt") as f:
mobile_id = f.readline()
mobile_ids = []
for i in mobile_id:
data = int(i)
mobile_ids.append(data)
ran = random.randint(0,5)
#随机取出一个数据
mobile_id = mobile_ids[ran]
mobile = str(mobile_id)
运行locust
1、压测脚本文件名是 locustfile.py
$ locust
2、压测脚本文件名不是 locustfile.py
$ locust -f locust_files/my_locust_file.py
3、如果HttpLocust中未指定host
$ locust -f locust_files/my_locust_file.py --host=http://example.com
没有web ui 运行locust
1、–no-web:表示不使用web界面运行测试,与-c -r -t同时使用
-c:表示设置虚拟用户数
-r:设置每秒启动虚拟用户数
-t:设置运行时间
–stop-timeout :指定多长时间后停止执行任务
$ locust -f locust_files/my_locust_file.py --no-web -c 1000 -r 100
–csv=example :导出运行结果
运行分布式locust
1、主机中使用–master标记来启用一个locust,但是master节点的机器不会发起请求,只会收集数据展示。
$ locust -f locust_files/my_locust_file.py --master
2、在从机使用–save标记启动一台到多台locust salve机器节点,与标记–master-host一起使用
$ locust -f locust_files/my_locust_file.py --slave --master-host=192.168.0.100
3、如果要运行不带Web UI的Locust分布式,则应在启动主节点时指定–expect-slaves,以指定预期要连接的从节点的数量。然后它将等待直到连接了所有从属节点,然后才能开始测试。
运行locust,逐步加载负载
locust -f --no-web -c 1000 -r 100 --run-time 1h30m --step-load --step-clients 300 --step-time 20m
–step-load :指定逐步加载模式
–step-clients : 指定每次加载负载量
–step-time :指定加载负载后运行时长
脚本中运行locust
os.system(“locust -f api_get_post.py --host=host”)
使用docker运行locust
locust控制台
1、启动locust就可以打开locust控制台
2、在控制台可以输入并发用户数及所有用户在多长时间内启动等。
报告
Type:请求类型,即接口的请求方法;
Name:请求路径;
requests:当前已完成的请求数量;
fails:当前失败的数量;
Median:响应时间的中间值,即50%的响应时间在这个数值范围内,单位为毫秒;
Average:平均响应时间,单位为毫秒;
Min:最小响应时间,单位为毫秒;
Max:最大响应时间,单位为毫秒;
Content Size:所有请求的数据量,单位为字节;
reqs/sec:每秒钟处理请求的数量,即QPS;