Locust是一款易于使用的分布式用户负载测试工具。它用于对网站(或其他系统)进行负载测试,并确定系统可以处理多少并发用户。
这个想法是,在测试期间,一群蝗虫(Locust)会攻击你的网站。您定义了每个蝗虫Locust(或测试用户)的行为,并且实时地从Web UI监视群集过程。这将有助于您在让真正的用户进入之前进行测试并识别代码中的瓶颈。
Locust完全基于事件,因此可以在一台计算机上支持数千个并发用户。与许多其他基于事件的应用程序相比,它不使用回调。相反,它通过协程(gevent)机制使用轻量级过程。每个蝗虫蜂拥到你的网站实际上是在自己的进程内运行(或者是greenlet,这是正确的)。这允许您在Python中编写非常富有表现力的场景,而不会使代码复杂化。
安装
# pip3 安装locust
pip3 install locust# 查看是否安装成功locust -h# 运行 Locust 分布在多个进程/机器库pip3 install pyzmq# webSocket 压测库pip3 install websocket-client
编写压测脚本 test.py
from locust import HttpLocust, TaskSet, task
# 定义用户行为
class UserBehavior(TaskSet):
@task
def baidu_index(self):
self.client.get("/")
class WebsiteUser(HttpLocust):
task_set = UserBehavior # 指向一个定义的用户行为类
min_wait = 3000 # 执行事务之间用户等待时间的下界(单位:毫秒)
max_wait = 6000 # 执行事务之间用户等待时间的上界(单位:毫秒)
UserBehavior类继承TaskSet类,用于描述用户行为。
baidu_index() 方法表示一个用户为行,访问百度首页。使用@task装饰该方法为一个事务。client.get()用于指请求的路径“/”,因为是百度首页,所以指定为根路径。
WebsiteUser类用于设置性能测试。
task_set :指向一个定义的用户行为类。
min_wait :执行事务之间用户等待时间的下界(单位:毫秒)。
max_wait :执行事务之间用户等待时间的上界(单位:毫秒)。
启动压测
locust -f test.py --host=https://www.baidu.com
访问 http://localhost:8089 进入压测首页
Number of users to simulate 模拟用户数Hatch rate (users spawned/second) 每秒钟增加用户数点击 “Start swarming” 进入压测页面
Type 请求的类型,例如GET/POST
Name 请求的路径
Request 当前请求的数量
Fails 当前请求失败的数量
Median 中间值,单位毫秒,请求响应时间的中间值
Average 平均值,单位毫秒,请求的平均响应时间
Min 请求的最小服务器响应时间,单位毫秒
Max 请求的最大服务器响应时间,单位毫秒
Average size 单个请求的大小,单位字节
Current RPS 代表吞吐量(Requests Per Second的缩写),指的是某个并发用户数下单位时间内处理的请求数。等效于QPS,其实可以看作同一个统计方式,只是叫法不同而已。
在没有Web UI的情况下运行locust - 可以打开cmd 通过使用–no-web参数,
-c指定要生成的Locust用户数
-r每秒启动虚拟用户数
先cd到脚本当前目录,然后执行指令
> locust -f locustfile.py --host=[http://192.168.x.xx:80](http://192.168.x.xx/) --no-web -c 1 -r 1
设置运行时间
如果要指定测试的运行时间,可以使用–run-time
> locust -f locustfile.py --host=[http://192.168.x.xx:80](http://192.168.x.xx/) --no-web -c 1 -r 1 --run-time 10
–csv=example参数保存CSV文件到当前脚本目录example_distribution.csv、example_requests.csv
> locust -f locustfile.py --host=[http://192.168.x.xx:80](http://192.168.x.xx/) --no-web --csv=example -c 1 -r 1 -t 10s
参数说明:
参数 说明
-h, --help 查看帮助
-H HOST, --host=HOST 指定被测试的主机,采用以格式:http://10.21.32.33
–web-host=WEB_HOST 指定运行 Locust Web 页面的主机,默认为空 ‘’。
-P PORT, --port=PORT, --web-port=PORT 指定 --web-host 的端口,默认是8089
-f LOCUSTFILE, --locustfile=LOCUSTFILE 指定运行 Locust 性能测试文件,默认为: locustfile.py
–csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE 以CSV格式存储当前请求测试数据。
–master Locust 分布式模式使用,当前节点为 master 节点。
–slave Locust 分布式模式使用,当前节点为 slave 节点。
–master-host=MASTER_HOST 分布式模式运行,设置 master 节点的主机或 IP 地址,只在与 --slave 节点一起运行时使用,默认为:127.0.0.1.
–master-port=MASTER_PORT 分布式模式运行, 设置 master 节点的端口号,只在与 --slave 节点一起运行时使用,默认为:5557。注意,slave 节点也将连接到这个端口+1 上的 master 节点。
–master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces).
–master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558.
–expect-slaves=EXPECT_SLAVES How many slaves master should expect to connect before starting the test (only when --no-web used).
–no-web no-web 模式运行测试,需要 -c 和 -r 配合使用.
-c NUM_CLIENTS, --clients=NUM_CLIENTS 指定并发用户数,作用于 --no-web 模式。
-r HATCH_RATE, --hatch-rate=HATCH_RATE 指定每秒启动的用户数,作用于 --no-web 模式。
-t RUN_TIME, --run-time=RUN_TIME 设置运行时间, 例如: (300s, 20m, 3h, 1h30m). 作用于 --no-web 模式。
-L LOGLEVEL, --loglevel=LOGLEVEL 选择 log 级别(DEBUG/INFO/WARNING/ERROR/CRITICAL). 默认是 INFO.
–logfile=LOGFILE 日志文件路径。如果没有设置,日志将去 stdout/stderr
–print-stats 在控制台中打印数据
–only-summary 只打印摘要统计
–no-reset-stats Do not reset statistics once hatching has been completed。
-l, --list 显示测试类, 配置 -f 参数使用
–show-task-ratio 打印 locust 测试类的任务执行比例,配合 -f 参数使用.
–show-task-ratio-json 以 json 格式打印 locust 测试类的任务执行比例,配合 -f 参数使用.
-V, --version 查看当前 Locust 工具的版本.
一旦单台机器不够模拟足够多的用户时,Locust支持运行在多台机器中进行压力测试。
为了实现这个,你应该在 master 模式中使用–master标记来启用一个 Locust 实例。这个实例将会运行你启动测试的 Locust 交互网站并查看实时统计数据。master 节点的机器自身不会模拟任何用户。相反,你必须使用 --slave 标记启动一台到多台 Locustslave 机器节点,与标记 --master-host 一起使用(指出master机器的IP/hostname)。常用的做法是在一台独立的机器中运行master,在slave机器中每个处理器内核运行一个slave实例。注意:master 和每一台 slave 机器,在运行分布式测试时都必须要有 locust 的测试文件。
在 master 模式下启动 Locust:
locust -f my_loucstfile.py --master
在每个 slave 中执行
locust -f my_locustfile.py --slave --master-host=192.168.0.14
参数说明
参数
–master
设置 Locust 为 master 模式。网页交互会在这台节点机器中运行。
–slave
设置 Locust 为 slave 模式。
–master-host=X.X.X.X
可选项,与 --slave 一起结合使用,用于设置 master 模式下的 master 机器的IP/hostname(默认设置为127.0.0.1)
–master-port=5557
可选项,与 --slave 一起结合使用,用于设置 master 模式下的 master 机器中 Locust 的端口(默认为5557)。注意,locust 将会使用这个指定的端口号,同时指定端口+1的号也会被占用。因此,5557 会被使用,Locust将会使用 5557 和 5558。
–master-bind-host=X.X.X.X`
可选项,与 --master 一起结合使用。决定在 master 模式下将会绑定什么网络接口。默认设置为*(所有可用的接口)。
–master-bind-port=5557
可选项,与 --master 一起结合使用。决定哪个网络端口 master 模式将会监听。默认设置为 5557。注意 Locust 会使用指定的端口号,同时指定端口+1的号也会被占用。因此,5557 会被使用,Locust 将会使用 5557 和 5558。
–expect-slaves=X
在 no-web 模式下启动 master 时使用。master 将等待X连接节点在测试开始之前连接。
进行测试测试,需要通过编写性能测试脚本实现。所以,我们要熟悉 Locust 提供了哪些类和方法,它们分别实现什么操作。
对于常见的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实例)的运行逻辑都会遵循如下规律:
from locust import HttpLocust, TaskSet, task
class UserTask(TaskSet):
@task
def tc_index(self):
self.client.get("/")
class UserOne(HttpLocust):
task_set = UserTask
weight = 1
min_wait = 1000
max_wait = 3000
stop_timeout = 5
host = "https://www.baidu.com"
class UserTwo(HttpLocust):
weight = 2
task_set = UserTask
host = "https://www.baidu.com"
每一个模拟的用户可以看做一个 HttpLocust 类的实例,HttpLocust 类有如下属性:
task_set
指向一个 TaskSet 类,TaskSet 类定义了每个用户的行为。
min_wait
用户执行任务之间等待时间的下界,单位:毫秒。如果TaskSet类中有覆盖,以TaskSet 中的定义为准。
max_wait
用户执行任务之间等待时间的上界,单位:毫秒。如果TaskSet类中有覆盖,以TaskSet中的定义为准。
host
如果是 Web 服务的测试,host 相当于是提供 URL 前缀的默认值,但是如果在命令行中指定了 --host 选项,则以命令行中指定的为准。如果不是 Web 服务测试,使用默认的 None 就好。
stop_timeout
设置 Locust 多少秒后超时,如果为 None ,则不会超时。
weight
一个Locust实例被挑选执行的权重,数值越大,执行频率越高。在一个 locustfile.py 文件中可以同时定义多个 HttpLocust 子类,然后分配他们的执行权重,例如:
然后在终端启动测试:
locust -f load_test.py UserOne UserTwo
TaskSet类定义了每个用户的任务集合,测试任务开始后,每个 Locust 用户会从 TaskSet 中随机挑选一个任务执行,然后随机等待 HttpLocust 类中定义的 min_wait和 max_wait 之间的一段时间,执行下一个任务。
from locust import HttpLocust, TaskSet, task
class stay(TaskSet):
def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """
print("start test")
@task(3)
def readBook(self):
print('I am reading a book.')
@task(7)
def listenMusic(self):
print('I am listening to music.')
@task(1)
def logOut(self):
self.interrupt()
class UserTask(TaskSet):
tasks = {stay:2}
@task(1)
def leave(self):
print('I don not like this page.')
class User(HttpLocust):
task_set = UserTask
host = "https://www.baidu.com"
on_start():
定义每个 Locust 用户开始做的第一件事。
@task
通过@task()装饰的方法为一个事务。方法的参数用于指定该行为的执行权重。参数越大每次被虚拟用户执行的概率越高。如果不设置默认为1。
interrupt(reschedule=True)
顶层的TaskSet(即被绑定到某个Locust类的task_set的第一层TaskSet)不能调用这个方法。reschedule置为True时,从被嵌套任务出来马上选择新任务执行,如果置为False,从被嵌套任务出来后,随机等待min_wait和max_wait之间的一段时间,再选择新任务执行。
tasks 属性
tasks = {stay:2} 表示每个用户执行 stay 的频率是2,也就的 UserTask 的两倍。
然后在终端启动测试:
locust -f tc_load_test2.py --no-web -c 10 -r 10 -t 10s
性能测试工具要模拟用户的业务操作,就需要通过脚本模拟用户的行为。在前面的比喻中说到,TaskSet类好比蝗虫的大脑,控制着蝗虫的具体行为
具体地,TaskSet类实现了虚拟用户所执行任务的调度算法,包括规划任务执行顺序(schedule_task)、挑选下一个任务(execute_next_task)、执行任务(execute_task)、休眠等待(wait)、中断控制(interrupt)等等。在此基础上,我们就可以在TaskSet子类中采用非常简洁的方式来描述虚拟用户的业务测试场景,对虚拟用户的所有行为(任务)进行组织和描述,并可以对不同任务的权重进行配置。
在TaskSet子类中定义任务信息时,可以采取两种方式,@task装饰器和tasks属性。
采用@task装饰器定义任务信息时,描述形式如下:
from locust import TaskSet, task
class UserBehavior(TaskSet):
@task(1)
def test_job1(self):
self.client.get('/job1')
@task(2)
def test_job2(self):
self.client.get('/job2')
from locust import HttpLocust, TaskSet, task
class WebsiteTasks(TaskSet):
def on_start(self):
self.client.post("/login", {
"username": "test",
"password": "123456"
})
@task(2)
def index(self):
self.client.get("/")
@task(1)
def about(self):
self.client.get("/about/")
class WebsiteUser(HttpLocust):
task_set = WebsiteTasks
host = "http://debugtalk.com"
min_wait = 1000
max_wait = 5000
在这个示例中,定义了针对http://debugtalk.com网站的测试场景:先模拟用户登录系统,然后随机地访问首页(/)和关于页面(/about/),请求比例为2:1;并且,在测试过程中,两次请求的间隔时间为1~5秒间的随机值。