locust的安裝與使用

Contentshtml

Locust這一款開源性能測試工具。然而,當前在網絡上針對Locust的教程極少,無論是中文仍是英文,基本都是介紹安裝方法和簡單的測試案例演示,但對於較複雜測試場景的案例演示卻基本沒有,所以不少測試人員都感受難以將Locust應用到實際的性能測試工做當中。python

通過一段時間的摸索,包括通讀Locust官方文檔和項目源碼,而且在多個性能測試項目中對Locust進行應用實踐,事實證實,Locust基本能知足平常的性能測試需求,LoadRunner能實現的功能Locust也基本都能實現。可是在error和併發用戶數以前沒有提供明確的對應關係圖,不能肯定最佳的併發量。設計場景能力有點欠佳,不過對腳本設計非常靈活,能夠在此做必定的彌補。web

本文將從Locust的功能特性出發,結合實例對Locust的使用方法進行介紹。考慮到大衆廣泛對LoadRunner比較熟悉,在講解Locust時也會採用LoadRunner的一些概念進行類比。算法

概述

先從Locust的名字提及。Locust的原意是蝗蟲,原做者之因此選擇這個名字,估計也是聽過這麼一句俗語,「蝗蟲過境,寸草不生」。api

Locust工具生成的併發請求就跟一大羣蝗蟲通常,對咱們的被測系統發起攻擊,以此檢測系統在高併發壓力下是否能正常運轉。瀏覽器

壓力發生器的核心要點有三點:一是真實模擬用戶操做,二是模擬有效併發,三是模擬實際的場景。網絡

Locust測試框架中,測試場景是採用純Python腳本進行描述的。對於最多見的HTTP(S)協議的系統,Locust採用Python的requests庫做爲客戶端,使得腳本編寫大大簡化,富有表現力的同時且極具美感。而對於其它協議類型的系統,Locust也提供了接口,只要咱們能採用Python編寫對應的請求客戶端,就能方便地採用Locust實現壓力測試。從這個角度來講,Locust能夠用於壓測任意類型的系統。session

在模擬有效併發方面,Locust的優點在於其摒棄了進程和線程,徹底基於事件驅動,使用gevent提供的非阻塞IOcoroutine來實現網絡層的併發請求,所以即便是單臺壓力機也能產生數千併發請求數;再加上對分佈式運行的支持,理論上來講,Locust能在使用較少壓力機的前提下支持極高併發數的測試。數據結構

locust的安裝

安裝locust

在dos下輸入pip install locustio 回車
若是提示未找到pip命令,則須要進入python安裝目錄,找到D:\Python27\Scripts路徑,並將該路徑添加至環境變量中。併發

安裝pyzmq

在dos下輸入pip install pyzmq 回車

腳本編寫

編寫Locust腳本,是使用Locust的第一步,也是最爲重要的一步。

簡單示例

先來看一個最簡單的示例。

from locust import HttpLocust, TaskSet, task 

class ScriptTasks(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/") 

        

    @task(1) 

    def demo(self): 

        payload={} 

        headers={} 

        self.client.post("/demo/",data=payload, headers=headers) 

        

class WebsiteUser(HttpLocust): 

    task_set = ScriptTasks 

    host = "http://example.com" 

    min_wait = 1000 

    max_wait = 5000

那麼,如上Python腳本是如何表達出以上測試場景的呢?在這個示例中,定義了針對http://example.com網站的測試場景:先模擬用戶登陸系統,而後隨機地訪問首頁(/)和關於頁面(/about/),請求比例爲2:1,demo方法主要用來闡述client對post接口的處理方式;而且,在測試過程當中,兩次請求的間隔時間爲1~5秒間的隨機值。

從腳本中能夠看出,腳本主要包含兩個類,一個是WebsiteUser(繼承自HttpLocust,而HttpLocust繼承自Locust),另外一個是ScriptTasks(繼承自TaskSet)。事實上,在Locust的測試腳本中,全部業務測試場景都是在LocustTaskSet兩個類的繼承子類中進行描述的。

那如何理解LocustTaskSet這兩個類呢?

簡單地說,Locust類就比如是一羣蝗蟲,而每一隻蝗蟲就是一個類的實例。相應的,TaskSet類就比如是蝗蟲的大腦,控制着蝗蟲的具體行爲,即實際業務場景測試對應的任務集。

這個比喻可能不是很準確,接下來,我將分別對LocustTaskSet兩個類進行詳細介紹。

class HttpLocust(Locust)

Locust類中,具備一個client屬性,它對應着虛擬用戶做爲客戶端所具有的請求能力,也就是咱們常說的請求方法。一般狀況下,咱們不會直接使用Locust類,由於其client屬性沒有綁定任何方法。所以在使用Locust時,須要先繼承Locust類,而後在繼承子類中的client屬性中綁定客戶端的實現類。

對於常見的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類中,除了client屬性,還有幾個屬性須要關注下:

  • task_set: 指向一個TaskSet類,TaskSet類定義了用戶的任務信息,該屬性爲必填;
  • max_wait/min_wait: 每一個用戶執行兩個任務間隔時間的上下限(毫秒),具體數值在上下限中隨機取值,若不指定則默認間隔時間固定爲1秒;
  • host:被測系統的host,當在終端中啓動locust時沒有指定--host參數時纔會用到;
  • weight:同時運行多個Locust類時會用到,用於控制不一樣類型任務的執行權重。

測試開始後,每一個虛擬用戶(Locust實例)的運行邏輯都會遵循以下規律:

  1. 先執行WebsiteTasks中的on_start(只執行一次),做爲初始化;
  2. WebsiteTasks中隨機挑選(若是定義了任務間的權重關係,那麼就是按照權重關係隨機挑選)一個任務執行;
  3. 根據Locust類min_waitmax_wait定義的間隔時間範圍(若是TaskSet類中也定義了min_wait或者max_wait,以TaskSet中的優先),在時間範圍中隨機取一個值,休眠等待;
  4. 重複2~3步驟,直至測試任務終止。

class TaskSet

再說下TaskSet類

性能測試工具要模擬用戶的業務操做,就須要經過腳本模擬用戶的行爲。在前面的比喻中說到,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')

在如上兩種定義任務信息的方式中,均設置了權重屬性,即執行test_job2的頻率是test_job1的兩倍。採用tasks屬性定義任務信息時,描述形式以下:

若不指定執行任務的權重,則至關於比例爲1:1

from locust import TaskSet
 
def test_job1(obj):
obj.client.get('/job1')
 
def test_job2(obj):
obj.client.get('/job2')
 
class UserBehavior(TaskSet):
tasks = {test_job1:1, test_job2:2}
# tasks = [(test_job1,1), (test_job1,2)] # 兩種方式等價

掌握了HttpLocustTaskSet,咱們就基本具有了編寫測試腳本的能力。此時再回過頭來看前面的案例,相信你們都能很好的理解了。在TaskSet子類中除了定義任務信息,還有一個是常常用到的,那就是on_start函數。這個和LoadRunner中的vuser_init功能相同,在正式執行測試前執行一次,主要用於完成一些初始化的工做。例如,當測試某個搜索功能,而該搜索功能又要求必須爲登陸態的時候,就能夠先在on_start中進行登陸操做;前面也提到,HttpLocust使用到了requests.Session,所以後續全部任務執行過程當中就都具備登陸態了。

腳本加強

然而,當面對較複雜的測試場景,可能有的同窗仍是會感受無從下手;例如,不少時候腳本須要作關聯或參數化處理,這些在LoadRunner中集成的功能,換到Locust中就不知道怎麼實現了。可能也是這方面的緣由,形成不少測試人員都感受難以將Locust應用到實際的性能測試工做當中。

其實這也跟Locust的目標定位有關,Locust的定位就是small and very hackable。可是小巧並不意味着功能弱,咱們徹底能夠經過Python腳本自己來實現各類各樣的功能,若是你們有疑問,咱們不妨逐項分解來看。

LoadRunner這款功能全面應用普遍的商業性能測試工具中,腳本加強無非就涉及到四個方面:

  • 關聯
  • 參數化
  • 檢查點
  • 集合點

先說關聯這一項。在某些請求中,須要攜帶以前從Server端返回的參數,所以在構造請求時須要先從以前請求的Response中提取出所需的參數,常見場景就是session_id。針對這種狀況,LoadRunner雖然可能經過錄制腳本進行自動關聯,可是效果並不理想,在實際測試過程當中也基本都是靠測試人員手動的來進行關聯處理。

LoadRunner中手動進行關聯處理時,主要是經過使用註冊型函數,例如web_reg_save_param,對前一個請求的響應結果進行解析,根據左右邊界或其它特徵定位到參數值並將其保存到參數變量,而後在後續請求中使用該參數。採用一樣的思想,咱們在Locust腳本中也徹底能夠實現一樣的功能,畢竟只是Python腳本,經過官方庫函數re.search就能實現全部需求。甚至針對html頁面,咱們也能夠採用lxml庫,經過etree.HTML(html).xpath來更優雅地實現元素定位。

而後再來看參數化這一項。這一項極其廣泛,主要是用在測試數據方面。但經過概括,發現其實也能夠歸納爲三種類型。

  • 循環取數據,數據可重複使用:e.g. 模擬3用戶併發請求網頁,總共有100個URL地址,每一個虛擬用戶都會依次循環加載這100個URL地址;
  • 保證併發測試數據惟一性,不循環取數據:e.g. 模擬3用戶併發註冊帳號,總共有90個帳號,要求註冊帳號不重複,註冊完畢後結束測試;
  • 保證併發測試數據惟一性,循環取數據:模擬3用戶併發登陸帳號,總共有90個帳號,要求併發登陸帳號不相同,但數據可循環使用。

經過以上概括,能夠確信地說,以上三種類型基本上能夠覆蓋咱們平常性能測試工做中的全部參數化場景。

LoadRunner中是有一個集成的參數化模塊,能夠直接配置參數化策略。那在Locust要怎樣實現該需求呢?

答案依舊很簡單,使用Python的listqueue數據結構便可!具體作法是,在WebsiteUser定義一個數據集,而後全部虛擬用戶在WebsiteTasks中就能夠共享該數據集了。若是不要求數據惟一性,數據集選擇list數據結構,從頭至尾循環遍歷便可;若是要求數據惟一性,數據集選擇queue數據結構,取數據時進行queue.get()操做便可,而且這也不會循環取數據;至於涉及到須要循環取數據的狀況,那也簡單,每次取完數據後再將數據插入到隊尾便可,queue.put_nowait(data)

最後再說下檢查點。該功能在LoadRunner中一般是使用web_reg_find這類註冊函數進行檢查的。在Locust腳本中,處理就更方便了,只須要對響應的內容關鍵字進行assert xxx in response操做便可。 

Locust運行模式

在開始運行Locust腳本以前,咱們先來看下Locust支持的運行模式。

運行Locust時,一般會使用到兩種運行模式:單進程運行和多進程分佈式運行。

單進程運行模式的意思是,Locust全部的虛擬併發用戶均運行在單個Python進程中,具體從使用形式上,又分爲no_webweb兩種形式。該種模式因爲單進程的緣由,並不能徹底發揮壓力機全部處理器的能力,所以主要用於調試腳本和小併發壓測的狀況。

當併發壓力要求較高時,就須要用到Locust的多進程分佈式運行模式。從字面意思上看,你們可能第一反應就是多臺壓力機同時運行,每臺壓力機分擔負載一部分的壓力生成。的確,Locust支持任意多臺壓力機(一主多從)的分佈式運行模式,但這裏說到的多進程分佈式運行模式還有另一種狀況,就是在同一臺壓力機上開啓多個slave的狀況。這是由於當前階段大多數計算機的CPU都是多處理器(multiple processor cores),單進程運行模式下只能用到一個處理器的能力,而經過在一臺壓力機上運行多個slave,就能調用多個處理器的能力了。比較好的作法是,若是一臺壓力機有N個處理器內核,那麼就在這臺壓力機上啓動一個masterNslave。固然,咱們也能夠啓動N的倍數個slave,可是根據個人試驗數據,效果跟N個差很少,所以只須要啓動Nslave便可。

腳本調試

Locust腳本編寫完畢後,一般不會那麼順利,在正式開始性能測試以前還須要先調試運行下。

不過,Locust腳本雖然爲Python腳本,但卻很難直接當作Python腳本運行起來,爲何呢?這主要仍是由於Locust腳本中引用了HttpLocustTaskSet這兩個類,若是要想直接對其進行調用測試,會發現編寫啓動腳本是一個比較困難的事情。由於這個緣由,剛接觸Locust的同窗可能就會以爲Locust腳本很差調試。

但這個問題也能克服,那就是藉助Locust的單進程no_web運行模式。

Locust的單進程no_web運行模式中,咱們能夠經過--no-web參數,指定併發數(-c)和總執行次數(-n),直接在Terminal中執行腳本。

在此基礎上,當咱們想要調試Locust腳本時,就能夠在腳本中須要調試的地方經過print打印日誌,而後將併發數和總執行次數都指定爲1,執行形式以下所示。

locust -f locustfile.py --no_web -c 1 -n 1

執行測試

經過這種方式,咱們就能很方便地對Locust腳本進行調試了。

Locust腳本調試經過後,就算是完成了全部準備工做,能夠開始進行壓力測試了。

Locust是經過在Terminal中執行命令進行啓動的,通用的參數有以下兩個:

  • -H, --host:被測系統的host,若在Terminal中不進行指定,就須要在Locust子類中經過host參數進行指定;
  • -f, --locustfile:指定執行的Locust腳本文件;

除了這兩個通用的參數,咱們還須要根據實際測試場景,選擇不一樣的Locust運行模式,而模式的指定也是經過其它參數來進行控制的。

單進程運行

no-web

若是採用no_web形式,則需使用--no-web參數,並會用到以下幾個參數。

  • -c, --clients:指定併發用戶數;
  • -n, --num-request:指定總執行測試;
  • -r, --hatch-rate:指定併發加壓速率,默認值位1。

D:\workSpaces\ApiAutoTest\TestCases\OpsUltraAPITest\MonitorAPITest>locust -f monitorAgent.py --no-web -c1 -n1
[2018-06-05 16:23:02,940] dengshihuang/INFO/locust.main: Starting Locust 0.8.1
[2018-06-05 16:23:02,941] dengshihuang/INFO/locust.runners: Hatching and swarming 1 clients at the rate 1 clients/s...
Name # reqs # fails Avg Min Max | Median req/s
--------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------
Total 0 0(0.00%) 0.00

[2018-06-05 16:23:03,941] dengshihuang/INFO/locust.runners: All locusts hatched: WebsiteUser: 1
[2018-06-05 16:23:03,943] dengshihuang/INFO/locust.runners: Resetting stats

[2018-06-05 16:23:03,944] dengshihuang/INFO/locust.runners: All locusts dead

[2018-06-05 16:23:03,944] dengshihuang/INFO/locust.main: Shutting down (exit code 0), bye.
Name # reqs # fails Avg Min Max | Median req/s
--------------------------------------------------------------------------------------------------------------------------------------------
POST /api/push 0 0(0.00%) 0 0 0 | 0 0.00
--------------------------------------------------------------------------------------------------------------------------------------------
Total 0 0(0.00%) 0.00

Percentage of the requests completed within given times
Name # reqs 50% 66% 75% 80% 90% 95% 98% 99% 100%
--------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------

  


若是採用web形式,,則一般狀況下無需指定其它額外參數,Locust默認採用8089端口啓動web;若是要使用其它端口,就可使用以下參數進行指定。web

  • -P, --port:指定web端口,默認爲8089.
D:\workSpaces\ApiAutoTest\TestCases\OpsUltraAPITest\MonitorAPITest>locust -f monitorAgent.py --port=8089
[2018-06-05 15:36:30,654] dengshihuang/INFO/locust.main: Starting web monitor at *:8089 [2018-06-05 15:36:30,684] dengshihuang/INFO/locust.main: Starting Locust 0.8.1


若是Locust運行在本機,在瀏覽器中訪問http://localhost:8089便可進入Locust的Web管理頁面;若是Locust運行在其它機器上,那麼在瀏覽器中訪問http://locust_machine_ip:8089便可。此時,Locust並無開始執行測試,還須要在Web頁面中配置參數後進行啓動。

Locust的Web管理頁面中,須要配置的參數只有兩個:

  • Number of users to simulate: 設置併發用戶數,對應中no_web模式的-c, --clients參數;
  • Hatch rate (users spawned/second): 啓動虛擬用戶的速率,對應着no_web模式的-r, --hatch-rate參數。

參數配置完畢後,點擊【Start swarming】便可開始測試。

多進程分佈式運行

無論是單機多進程,仍是多機負載模式,運行方式都是同樣的,都是先運行一個master,再啓動多個slave

啓動master時,須要使用--master參數;一樣的,若是要使用8089之外的端口,還須要使用-P, --port參數。

D:\workSpaces\ApiAutoTest\TestCases\OpsUltraAPITest\MonitorAPITest>locust -f monitorAgent.py --master --port=8089
[2018-06-05 15:36:30,654] dengshihuang/INFO/locust.main: Starting web monitor at *:8089 [2018-06-05 15:36:30,684] dengshihuang/INFO/locust.main: Starting Locust 0.8.1


啓動slave時須要使用--slave參數;在slave中,就不須要再指定端口了。master
啓動後,還須要啓動slave才能執行測試任務。

D:\workSpaces\ApiAutoTest\TestCases\OpsUltraAPITest\MonitorAPITest>locust -f monitorAgent.py --slave
[2018-06-05 15:36:30,654] dengshihuang/INFO/locust.main: Starting web monitor at *:8089 [2018-06-05 15:36:30,684] dengshihuang/INFO/locust.main: Starting Locust 0.8.1
D:\workSpaces\ApiAutoTest\TestCases\OpsUltraAPITest\MonitorAPITest>locust -f monitorAgent.py --slave --master-host=<locust_machine_ip>

masterslave都啓動完畢後,就能夠在瀏覽器中經過http://locust_machine_ip:8089進入Locust的Web管理頁面了。使用方式跟單進程web形式徹底相同,只是此時是經過多進程負載來生成併發壓力,在web管理界面中也能看到實際的slave數量。若是slavemaster不在同一臺機器上,還須要經過--master-host參數再指定master的IP地址。

測試結果展現

Locust在執行測試的過程當中,咱們能夠在web界面中實時地看到結果運行狀況。

相比於LoadRunnerLocust的結果展現十分簡單,主要就四個指標:併發數RPS響應時間異常率。但對於大多數場景來講,這幾個指標已經足夠了。

 

在上圖中,RPS平均響應時間這兩個指標顯示的值都是根據最近2秒請求響應數據計算獲得的統計值,咱們也能夠理解爲瞬時值。

若是想看性能指標數據的走勢,就能夠在Charts欄查看。在這裏,能夠查看到RPS平均響應時間在整個運行過程當中的波動狀況。

 

除了以上數據,Locust還提供了整個運行過程數據的百分比統計值,例如咱們經常使用的90%響應時間響應時間中位值;平均響應時間和錯誤數的統計,該數據能夠經過Download response time distribution CSV和Download request statistics CSV得到,數據展現效果以下所示。

 

相關文章
相關標籤/搜索