Locust是什么?
Locust 是一个开源负载测试工具。使用 Python 代码定义用户行为,也可以仿真百万个用户。
Locust 是非常简单易用,分布式,用户负载测试工具。Locust 主要为网站或者其他系统进行负载测试,能测试出一个系统可以并发处理多少用户。
Locust 是完全基于时间的,因此单个机器支持几千个并发用户。相比其他许多事件驱动的应用,Locust 不使用回调,而是使用轻量级的处理方式 gevent。
安装
pip install locustio
如果你打算通过多进程或多机,分布式地运行Locust
,我们建议你也安装pyzmq
:
pip install pyzmq
TaskSet类
每个Locust
类必须有一个指向一个TaskSet
的task_set
属性。
TaskSet
是任务的集合,这些任务是普通的python可调用对象。
当负载测试启动的时候,产生的每一个Locust
类的实例都会开始执行它们的TaskSet
。接下来发生的是,每个TaskSet
会选择它的任务中的一个,并且调用它。接下来等待min_wait
到max_wait
毫秒,然后它会再选择下一个要被调用的任务,再等待,等等。
声明任务
为TaskSet声明任务最典型的方式是使用task
装饰器。
下面是一个例子:
def index(l):
l.client.get("/")
def stats(l):
l.client.get("/stats/requests")
class UserTasks(TaskSet):
# one can specify tasks like this
tasks = [index, stats]
# but it might be convenient to use the @task decorator
@task(3)
def task1(self):
self.client.get("/does_not_exist")
@task(6)
def task2(self):
pass
class WebsiteUser(HttpLocust):
"""
Locust user class that does requests to the locust web server running on localhost
"""
host = "http://127.0.0.1:8089"
min_wait = 2000
max_wait = 5000
task_set = UserTasks
-
@task
装饰器带一个可选的weight
参数,它用于指定任务的执行比例。在下面的例子中,task2
的执行次数是task1
的两倍: -
TaskSet
支持嵌套
class MyTaskSet(TaskSet):
@task
class SubTaskSet(TaskSet):
@task
def my_task(self):
pass
-
on_start
函数
TaskSet类可以定义一个on_start方法,当模拟用户开始执行TaskSet类的时候,on_start方法会被调用。
HttpLocust类
本文已经包含了Locust用户的任务调度部分,为了真正的给一个系统进行负载测试,我们需要生成HTTP请求,HttpLocust类的存在,就是为了解决这个问题。当使用HttpLocust类的时候,每个实例都有一个client属性---它是能够用于生成HTTP请求的HttpSession类的实例
from locust import HttpLocust, TaskSet, task
class MyTaskSet(TaskSet):
@task(2)
def index(self):
self.client.get("/")
@task(1)
def about(self):
self.client.get("/about/")
class MyLocust(HttpLocust):
task_set = MyTaskSet
min_wait = 5000
max_wait = 15000
- 使用上面的
Locust
类,每个模拟用户在请求之间都会等待5-15
秒,并且/的请求次数是/about/
的两倍。
- 用心的读者可能会觉得很奇怪:在TaskSet内部我们使用
self.client
而非self.locust.client
开引用HttpSession
实例,我们能这么做是因为:TaskSet
类有一个便捷的被称作client的属性,它简单的返回self.locust.client
。
-
生成
GET
请求的例子
response = self.client.get("/about")
print "Response status code:", response.status_code
print "Response content:", response.content
-
生成
POST
请求的例子
response = self.client.post("/login", {"username":"testuser", "password":"secret"})
-
人工控制一个请求被视为成功还是失败
默认情况下,除非HTTP响应码是ok(2xx),否则请求就会被标记为失败。大多数情况下,默认的情况就是我们想要的。然而有时:比如说你期望返回404,或者是测试一个即使发生错误,仍然返回200 OK的系统,就存在人工控制locust将请求视为成功还是失败的需求。 通过使用catch_response参数和with语句,可以把一个响应码是okay的请求标记成失败
with client.get("/", catch_response=True) as response:
if response.content != "Success":
response.failure("Got wrong response")
正如可以把响应码为OK的请求标记为失败,也可以使用catch_response参数和with语句,将返回http错误代码的请求在统计中报告为成功。
with client.get("/does_not_exist/", catch_response=True) as response:
if response.status_code == 404:
response.success()
-
安全模式
HTTP客户端被配置成以安全模式运行,任何由于连接错误,超时之类导致失败的请求都不会抛出异常,而是返回一个空的虚拟的Response对象,在Locust的统计中请求会被报告为一个失败。被返回的虚拟的Response对象的content属性被设置为None,status_code属性被设置为0
-
将到具有动态参数的URL的请求分组
对于网站来说,拥有URL中包含某种动态参数的页面是非常普遍的。通常在Locust的统计中,把这些URL分成一组是有意义的。可以通过给HttpSession实例的请求方法传递name参数,来完成这件事。
例子:
# Statistics for these requests will be grouped under: /blog/?id=[id]
for i in range(10):
client.get("/blog?id=%i" % i, name="/blog?id=[id]")
启动
- 如果运行的文件名称为
locustfile.py
则可以直接运行
locust --host=http://example.com
- 如果locust file被放到了其他的地方,我们可以运行
locust -f 当前文件夹路径/my_file.py --host=http://example.com
- 如果需要多线程分布式运行locust,启动的时候需要指定
master
和slave
locust -f 当前文件夹路径/my_file.py --host=http://example.com --master
然后我们可以启动任意数量的slave进程:(用master机器的ip替换192.168.0.14)
locust -f my_locustfile.py --slave --master-host=192.168.0.14
分布式运行Locust
参数
属性 | 解释 |
---|---|
-f |
文件名 |
--host |
运行的接口的host |
--master |
以master的模式运行locust,web接口会运行在这个节点上 |
--slave |
以slave模式运行locust。 |
--master-host=X.X.X.X |
和--slave 一起使用,用来设置master节点的ip或主机名(默认是127.0.0.1) |
--master-port=5557 |
和--slave 一起使用,用来设置master节点的端口号(默认是5557),注意:locust既会使用指定的端口号,又会使用指定的端口号+1,因此如果设置为5557,那么locust既会使用5557,也会使用5558 |
--master-bind-host=X.X.X.X |
和--master 一起使用,决定master节点绑定到哪一个网络接口,默认是*(所有可用的网络接口) |
min_wait和max_wait属性
除了task_set
属性,也可以声明min_wait
和max_wait
属性,它们是一个模拟用户在执行任务之间等待的最大和最小时间,单位是毫秒
。min_wait和max_wait默认是1000
,因此如果没有声明min_wait
和max_wait
,locust
在执行每个任务之间总是会等待1
秒。
使用下面的locustfile,在任务之间每个用户等待5-15
秒:
from locust import Locust, TaskSet, task
class MyTaskSet(TaskSet):
@task
def my_task(self):
print "executing my_task"
class MyLocust(Locust):
task_set = MyTaskSet
min_wait = 5000
max_wait = 15000
参考:
http://timd.cn/2015/09/17/locust/
https://my.oschina.net/u/2306127/blog/482625