引言
當我們做Web系統(tǒng)性能測試方案時,壓力模擬工具的選擇通常是一個繞不開的環(huán)節(jié)。對于大部分互聯(lián)網(wǎng)公司的業(yè)務規(guī)模和測試資源投入,JMeter這個老牌開源性能測試工具能夠滿足大部分測試需求,它也可能是世面上書籍、博客教程豐富程度僅次于LoadRunner的性能測試工具。然而當我們的場景需要模擬的并發(fā)用戶數(shù)以千為單位時,使用JMeter的成本越來越大,甚至超出我們掌握的資源。此時,我們開始尋找更低成本的方案,而Locust,為這樣的方案帶來了一種可能。
簡介
Locust是開源、使用Python開發(fā)、基于事件、支持分布式并且提供Web UI進行測試執(zhí)行和結(jié)果展示的性能測試工具。而它之所以能夠在資源占用方面明顯優(yōu)于JMeter,一個關(guān)鍵點在于兩者模擬虛擬用戶的方式不同,JMeter通過線程來作為虛擬用戶,而Locust借助gevent庫對協(xié)程的支持,以greenlet來實現(xiàn)對用戶的模擬,相同配置下Locust能支持的并發(fā)用戶數(shù)相比JMeter可以達到一個數(shù)量級的提升。
Locust使用Python代碼定義測試場景,目前支持Python 2.7, 3.3, 3.4, 3.5, 和3.6。它自帶一個Web UI,用于定義用戶模型,發(fā)起測試,實時測試數(shù)據(jù),錯誤統(tǒng)計等,在最新未正式發(fā)布的v0.8a2(當前最新發(fā)布版本v0.8a1),還提供QPS、評價響應時間等幾個簡單的圖表。


本文不會介紹Locust最基礎的部署、運行等Quick start式內(nèi)容,這部分內(nèi)容請直接參照官網(wǎng)Quick start或者搜索Locust入門的博客,本文主要介紹一些目前網(wǎng)絡上還比較缺少的,真正要用Locust來做Web系統(tǒng)性能測試時通常需要用到的內(nèi)容或者可能遇到的問題
v0.8a2<a id="a2"></a>
如前文所說,當前官方最新發(fā)布的版本為v0.8a1,還不包含圖表特性,而在官方Github上已經(jīng)在v0.8a2完成了圖表特性的合并,想要提前體驗可以直接從Github獲取master分支的代碼,覆蓋`[PythonHome]\Lib\site-packages`中的locust目錄即可。
指定Web host
在Linux系統(tǒng)多網(wǎng)卡情況下,Locust自動選擇網(wǎng)卡時可能會遇到error: [Errno 97] Address family not supported by protocol錯誤,此時可以通過直接指定web host來解決問題,使用選項--web-host來指定可用的地址,例:
locust -f xxx.py --web-host=127.0.0.1
locust -f xxx.py --web-host=192.168.1.2
locust -f xxx.py --web-host=localhost
斷言
當我們沒有自定義斷言時,測試請求結(jié)果的狀態(tài)(success/fail)取決于Http請求是否有異常出現(xiàn),而在對我們的Web系統(tǒng)實施性能測試時,當我們需要更準確的業(yè)務成功率數(shù)據(jù)時,就需要通過對響應狀態(tài)碼、Response body等數(shù)據(jù)進行校驗來給出結(jié)果,此時,可以通過ResponseContextManager來實現(xiàn)。首先在場景代碼的發(fā)起請求參數(shù)中通過catch_response=True來捕獲響應數(shù)據(jù),然后對響應數(shù)據(jù)進行校驗,最后使用success()/failure()兩個方法來標識請求結(jié)果的狀態(tài)。例:
from locust import HttpLocust, TaskSet,task
class UserBehavior(TaskSet):
@task(2)
def foo(self):
with self.client.get("/", catch_response=True) as response:
if response.status_code == 200:
response.success()
@task(1)
def bar(self):
reqBody = '{"username":"ellen_key", "password":"education"}'
with self.client.post("/login", reqBody, catch_response=True) as response:
if response.content == "":
response.failure("No data")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
host = "http://foo.bar.com"
min_wait = 0
max_wait = 0
Json解析
Json作為一種輕量級的數(shù)據(jù)交換格式,以及被如今的互聯(lián)網(wǎng)系統(tǒng)廣泛采用。上一節(jié)的示例中,我們使用content獲取完整的響應內(nèi)容,實際測試實施中,對于動態(tài)的響應結(jié)果,可能更多的采用校驗關(guān)鍵字段的方式對于Json格式的響應數(shù)據(jù),要獲取特定字段的值,可以直接使用內(nèi)置的Json解析實現(xiàn),例:
對于如下的響應結(jié)果:
{
'code':0,
'data':[
{
'id':123
}
]
}
可以通過如下方式獲取其中的關(guān)鍵數(shù)據(jù):
with self.client.post("/login", reqBody, catch_response=True) as response:
json_resp = response.json()
code = json_resp["code"]
data_len = len(json_resp["data"])
id = json_resp["data"][0]["id"]
自定義標簽
從簡介的Summary report圖中可以看到,Locust的結(jié)果展示中,請求的默認名稱是url的path部分,而為了報告更直觀,或者當同一個業(yè)務有動態(tài)的path(如/user/[userid]),需要聚合時,可以通過name參數(shù)來自定義標簽實現(xiàn),例:
with self.client.get("/account/{accountID}", catch_response=True, name = "getAccount") as resp:
分布式運行
Locust的分布式運行,master和slave節(jié)點都需要有場景腳本,分別以如下命令啟動:
- master:
locust -f locustfile.py --master --web-host=x.x.x.x - slave:
locust -f locustfile.py --slave --master-host=x.x.x.x
master節(jié)點將運行Locust的Web UI服務,不會承擔任何施壓任務(不會模擬虛擬用戶)。
如前面的簡介,Locust模擬并發(fā)用戶是使用協(xié)程,也因此對于多核CPU的服務器,為良好的利用多核能力,建議一臺slave服務器運行與CPU核數(shù)相當?shù)膕lave。
總結(jié)
Locust作為一個年輕的、輕量級的性能測試工具,網(wǎng)絡上相關(guān)的應用文獻特別是中文文獻相對較少,而且多數(shù)是Quick start式的指引,對于一些實施的細節(jié)信息還比較欠缺,本文根據(jù)作者的實際應用經(jīng)驗,列舉了部分使用細節(jié),希望能為需要的朋友提供一點有用的信息。