Locust 使用教程
About
前言
What is Coroutine?
协程又称为微线程,纤程。英文名Coroutine:协程是一种用户态的轻量级线程
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复之前保存的寄存器上下文和栈
# 优点:
1. 无需线程上下文切换的开销
2. 无需原子操作(不会被线程调度机制打断的操作)锁定以及同步的开销
3. 高并发+高扩展性+低成本
# 缺点:
1. 无法利用多核资源:协程的本质是单线程,需要和进程配合才能运行在多CPU上
2. 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
What is Gevent?
gevent是一个基于协程的Python网络库,它使用greenlet在libev或libuv事件循环之上提供一个高级的同步API
# libev是一个高性能的事件循环库
What is Python GIL?
GIL 全局解释器锁 (global interrupter lock)
# 由来:
1. 解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁
# 引发的问题:
1. 任何进程中,同一时刻只能有一个线程在执行 (多cup的资源,只有1个cpu在使用,其它处于空闲状态)
# 应对方案:
多开进程去实现多线程任务
GIL并非是Python的特性,而是Python 解释器CPython解释器的特性
Python解释器有如下几类:
# CPython:
官方默认版本,使用C语言开发,是Python使用最广泛的解释器,有GIL.
# IPython:
IPython是基于CPython之上的交互式解释器,其它方面和CPython相同.
# PyPy:
PyPy采用JIT(Just In Time)也就是即时编译编译器,对Python代码执行动态编译,目的是加快执行速度,有GIL.
# Jython:
运行在Java平台上的解释器,把Python代码编译为Java字节码执行,没有GIL.
# IronPython:
IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码,没有GIL.
What is Locust?
一个易于使用的分布式用户负载测试工具。它旨在对网站(或其他系统)进行负载测试,并确定一个系统可以处理多少并发用户。
Locust是完全基于事件的,因此可以在单台机器中支持数以千计的用户在线。和其它基于事件的程序相比较,它是不需要使用回调的。相反,它通过gevent使用轻量级的进程。每一个locust测试你的网站时,实际上是真实的在内部运行它自己的进程(或greenlet,准确的说)。这样就允许你不使用复杂的回调方法,而是使用Python编写复杂的场景。
# gevent
在Python中实现协程的第三方库。协程又叫微线程Corouine。使用gevent可以获取极高的并发能力;
# flask
轻量级的web开发框架,和django相当;
#requests
支持http/https访问的库;
# msgpack-python
一种快速、紧凑的二进制序列化格式,使用与类似json的数据;
# six
提供了一些简单的工具封装Python2和Python3 之间的差异;
# pyzmq
支撑 Locust运行在多个进程或多个机器(分布式)
....
Locust 核心类介绍
- TaskSet()
定义了每个用户的任务集合,测试任务开始后,每个Locust用户会从TaskSet中随机挑选(如果定义了任务间的权重关系,那么就是按照权重关系随机挑选)一个任务执行,然后随机等待Locust类中定义的min_wait和max_wait(如果TaskSet类中也定义了min_wait或者max_wait,按照TaskSet中的为准)之间的一段时间,执行下一个任务。
# TaskSet 提供的常用方法
client # client 源码:return self.locust.client 返回 locust的client,用法与Request库类似
locust # 当任务集被实例化时,将引用根蝗虫类实例
parent # 任务集被实例化时,指向每个TaskSet所属的父类TaskSet (用于 TaskSet嵌套)
client # 指向TaskSet所属的父HttpLocust类的client属性,self.client与self.locust.client效果是一样的。如果TaskSet所属的父类是个Locust类,则没有这个client属性
- HttpLocust()
继承了Locust类,表示将要生成的每一个虚拟的HTTP用户,用来发送请求到进行负载测试的系统
# HttpLocust 继承 Locust -> class HttpLocust(Locust):
task_set # 定义locust执行任务行为的 任务集类 如:task_set = TestDemo
host # 要测试的 目标服务地址
min_wait = 1000 # 单位为ms 最小等待时间 最新版本 已弃用 (当前版本:0.14.5)
max_wait = 1000 # 单位为ms 最大等待时间 最新版本 已弃用 (当前版本:0.14.5)
# between(min_wait, max_wait)
wait_time = between(100, 1000) # 单位为ms 等待时间 任务执行间隔时间 随机从100~1000区间内取
- taks 装饰器 可控制任务执行权重比,defautl:weight=1 如下:
class ForumPage(TaskSet):
@task(100)
def read_thread(self):
pass
@task(7)
def create_thread(self):
pass
Locust安装
- pip install locust
- pip list 版本查看或 locust -v
关键
Quick start
import json
import os
from locust import HttpLocust, TaskSet, task, between
class Demo(TaskSet):
@task
def test_get(self):
self.client.get("http://www.baidu.com")
@task
def test_post(self):
responses = self.client.post(url='url', headers='headers', data='body')
# 对返回内容 进行断言
if responses.status_code == 200:
rst = json.loads(responses.text, strict=False)
if rst['code'] == '00000':
responses.success() # Locust ResponseContextManager类提供的 Report the response as successful
else:
responses.failure('code:%s ErrorMsg:%s' % (rst['code'], rst['errorMsg']))
else:
responses.failure('status_code:%s' % responses.status_code)
class WebsiteUser(HttpLocust):
task_set = Demo
host = 'http://www.baidu.com' # 目标服务地址
# min_wait = 1000 # 单位为ms 最小等待时间 最新版本 已弃用 (当前版本:0.14.5)
# max_wait = 1000 # 单位为ms 最大等待时间 最新版本 已弃用 (当前版本:0.14.5)
# between(min_wait, max_wait)
wait_time = between(2, 5) # 单位为s 等待时间 任务执行间隔时间
# 以下 便于当前脚本 本地调试
# 启动 当前脚本
if __name__ == "__main__":
cmd = 'locust -f locust_demo.py'
os.system(cmd)
- 启动
界面参数解读
- Number of users to simulate 虚拟用户数 VU
- users spawned/second 每秒启动的 VU 数
- RPS 真实数据= RPS/2 (每秒发出的请求数)
分布式(Linux)
- master 启动:
# test.py 要执行的 脚本
# --master 指定当前 运行 进程为 master (单机上可 同时 运行 master/slave)
# -P 指定 master 进程 对外提供访问的 端口
locust -f test.py --master -P 8181
- Slave 启动:
# test.py 要执行的 脚本
# --slave 指定当前运行的 进程为slave
# --master-host 指定 master服务的地址
# -P 指定 master 进程 对外提供访问的 端口
locust -f test.py --slave --master-host=192.168.1.20