Locust是什么?
Locust 是一個(gè)開源負(fù)載測試工具。使用 Python 代碼定義用戶行為,也可以仿真百萬個(gè)用戶。
Locust 是非常簡單易用,分布式,用戶負(fù)載測試工具。Locust 主要為網(wǎng)站或者其他系統(tǒng)進(jìn)行負(fù)載測試,能測試出一個(gè)系統(tǒng)可以并發(fā)處理多少用戶。
Locust 是完全基于時(shí)間的,因此單個(gè)機(jī)器支持幾千個(gè)并發(fā)用戶。相比其他許多事件驅(qū)動(dòng)的應(yīng)用,Locust 不使用回調(diào),而是使用輕量級(jí)的處理方式 gevent。
安裝
pip install locustio
如果你打算通過多進(jìn)程或多機(jī),分布式地運(yùn)行Locust,我們建議你也安裝pyzmq:
pip install pyzmq
TaskSet類
每個(gè)Locust類必須有一個(gè)指向一個(gè)TaskSet的task_set屬性。
TaskSet是任務(wù)的集合,這些任務(wù)是普通的python可調(diào)用對(duì)象。
當(dāng)負(fù)載測試啟動(dòng)的時(shí)候,產(chǎn)生的每一個(gè)Locust類的實(shí)例都會(huì)開始執(zhí)行它們的TaskSet。接下來發(fā)生的是,每個(gè)TaskSet會(huì)選擇它的任務(wù)中的一個(gè),并且調(diào)用它。接下來等待min_wait到max_wait毫秒,然后它會(huì)再選擇下一個(gè)要被調(diào)用的任務(wù),再等待,等等。
聲明任務(wù)
為TaskSet聲明任務(wù)最典型的方式是使用task裝飾器。
下面是一個(gè)例子:
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裝飾器帶一個(gè)可選的weight參數(shù),它用于指定任務(wù)的執(zhí)行比例。在下面的例子中,task2的執(zhí)行次數(shù)是task1的兩倍: -
TaskSet支持嵌套
class MyTaskSet(TaskSet):
@task
class SubTaskSet(TaskSet):
@task
def my_task(self):
pass
-
on_start函數(shù)
TaskSet類可以定義一個(gè)on_start方法,當(dāng)模擬用戶開始執(zhí)行TaskSet類的時(shí)候,on_start方法會(huì)被調(diào)用。
HttpLocust類
本文已經(jīng)包含了Locust用戶的任務(wù)調(diào)度部分,為了真正的給一個(gè)系統(tǒng)進(jìn)行負(fù)載測試,我們需要生成HTTP請(qǐng)求,HttpLocust類的存在,就是為了解決這個(gè)問題。當(dāng)使用HttpLocust類的時(shí)候,每個(gè)實(shí)例都有一個(gè)client屬性---它是能夠用于生成HTTP請(qǐng)求的HttpSession類的實(shí)例
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類,每個(gè)模擬用戶在請(qǐng)求之間都會(huì)等待5-15秒,并且/的請(qǐng)求次數(shù)是/about/的兩倍。
- 用心的讀者可能會(huì)覺得很奇怪:在TaskSet內(nèi)部我們使用
self.client而非self.locust.client開引用HttpSession實(shí)例,我們能這么做是因?yàn)椋?code>TaskSet類有一個(gè)便捷的被稱作client的屬性,它簡單的返回self.locust.client。
-
生成
GET請(qǐng)求的例子
response = self.client.get("/about")
print "Response status code:", response.status_code
print "Response content:", response.content
-
生成
POST請(qǐng)求的例子
response = self.client.post("/login", {"username":"testuser", "password":"secret"})
-
人工控制一個(gè)請(qǐng)求被視為成功還是失敗
默認(rèn)情況下,除非HTTP響應(yīng)碼是ok(2xx),否則請(qǐng)求就會(huì)被標(biāo)記為失敗。大多數(shù)情況下,默認(rèn)的情況就是我們想要的。然而有時(shí):比如說你期望返回404,或者是測試一個(gè)即使發(fā)生錯(cuò)誤,仍然返回200 OK的系統(tǒng),就存在人工控制locust將請(qǐng)求視為成功還是失敗的需求。 通過使用catch_response參數(shù)和with語句,可以把一個(gè)響應(yīng)碼是okay的請(qǐng)求標(biāo)記成失敗
with client.get("/", catch_response=True) as response:
if response.content != "Success":
response.failure("Got wrong response")
正如可以把響應(yīng)碼為OK的請(qǐng)求標(biāo)記為失敗,也可以使用catch_response參數(shù)和with語句,將返回http錯(cuò)誤代碼的請(qǐng)求在統(tǒng)計(jì)中報(bào)告為成功。
with client.get("/does_not_exist/", catch_response=True) as response:
if response.status_code == 404:
response.success()
-
安全模式
HTTP客戶端被配置成以安全模式運(yùn)行,任何由于連接錯(cuò)誤,超時(shí)之類導(dǎo)致失敗的請(qǐng)求都不會(huì)拋出異常,而是返回一個(gè)空的虛擬的Response對(duì)象,在Locust的統(tǒng)計(jì)中請(qǐng)求會(huì)被報(bào)告為一個(gè)失敗。被返回的虛擬的Response對(duì)象的content屬性被設(shè)置為None,status_code屬性被設(shè)置為0
-
將到具有動(dòng)態(tài)參數(shù)的URL的請(qǐng)求分組
對(duì)于網(wǎng)站來說,擁有URL中包含某種動(dòng)態(tài)參數(shù)的頁面是非常普遍的。通常在Locust的統(tǒng)計(jì)中,把這些URL分成一組是有意義的??梢酝ㄟ^給HttpSession實(shí)例的請(qǐng)求方法傳遞name參數(shù),來完成這件事。
例子:
# 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]")
啟動(dòng)
- 如果運(yùn)行的文件名稱為
locustfile.py則可以直接運(yùn)行
locust --host=http://example.com
- 如果locust file被放到了其他的地方,我們可以運(yùn)行
locust -f 當(dāng)前文件夾路徑/my_file.py --host=http://example.com
- 如果需要多線程分布式運(yùn)行l(wèi)ocust,啟動(dòng)的時(shí)候需要指定
master和slave
locust -f 當(dāng)前文件夾路徑/my_file.py --host=http://example.com --master
然后我們可以啟動(dòng)任意數(shù)量的slave進(jìn)程:(用master機(jī)器的ip替換192.168.0.14)
locust -f my_locustfile.py --slave --master-host=192.168.0.14
分布式運(yùn)行Locust
參數(shù)
| 屬性 | 解釋 |
|---|---|
-f |
文件名 |
--host |
運(yùn)行的接口的host |
--master |
以master的模式運(yùn)行l(wèi)ocust,web接口會(huì)運(yùn)行在這個(gè)節(jié)點(diǎn)上 |
--slave |
以slave模式運(yùn)行l(wèi)ocust。 |
--master-host=X.X.X.X |
和--slave一起使用,用來設(shè)置master節(jié)點(diǎn)的ip或主機(jī)名(默認(rèn)是127.0.0.1) |
--master-port=5557 |
和--slave一起使用,用來設(shè)置master節(jié)點(diǎn)的端口號(hào)(默認(rèn)是5557),注意:locust既會(huì)使用指定的端口號(hào),又會(huì)使用指定的端口號(hào)+1,因此如果設(shè)置為5557,那么locust既會(huì)使用5557,也會(huì)使用5558
|
--master-bind-host=X.X.X.X |
和--master一起使用,決定master節(jié)點(diǎn)綁定到哪一個(gè)網(wǎng)絡(luò)接口,默認(rèn)是*(所有可用的網(wǎng)絡(luò)接口)
|
min_wait和max_wait屬性
除了task_set屬性,也可以聲明min_wait和max_wait屬性,它們是一個(gè)模擬用戶在執(zhí)行任務(wù)之間等待的最大和最小時(shí)間,單位是毫秒。min_wait和max_wait默認(rèn)是1000,因此如果沒有聲明min_wait和max_wait,locust在執(zhí)行每個(gè)任務(wù)之間總是會(huì)等待1秒。
使用下面的locustfile,在任務(wù)之間每個(gè)用戶等待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