文章略長
Locust學習筆記彙總
html
如有錯誤,請指正python
內容以官網爲準
https://locust.io/git
Locust簡介 Locust是什麼?
Locust
是一個簡單易用的分佈式用戶負載測試工具。它用於web站點(或其餘系統)的負載測試,並計算一個系統能夠處理多少併發用戶。github
在測試中,一羣locusts(蝗蟲)會攻擊你的網站。每一個locusts (或者測試用戶)的行爲由您定義,集羣過程由web UI實時監控。這將幫助你在容許實際用戶使用以前測試並肯定代碼中的瓶頸。web
Locust
徹底基於事件,所以能夠在一臺計算機上支持數千個併發用戶。與許多其餘基於事件的應用程序不一樣,它不使用回調。相反,它經過gevent使用輕量級進程。每一個彙集站點上的蝗蟲其實是在它本身的進程中運行的(正確的說是greenlet)。這容許你使用Python編寫很是有表現力的場景,而不用回調使代碼複雜化。docker
Locust功能特性
用普通的Python編寫用戶測試場景
不須要笨拙的UI或龐大的XML,只需像一般那樣編碼便可。基於協程而不是回調,您的代碼看起來和行爲都與正常的、阻塞Python代碼同樣。shell分佈式和可擴展——支持成千上萬的用戶
Locust支持在多臺機器上運行負載測試。因爲基於事件,即便一個Locust節點也能夠在一個進程中處理數千個用戶。這背後的部分緣由是,即便你模擬了那麼多用戶,也不是全部用戶都積極的訪問你的系統。一般,用戶無所事事,想知道下一步該怎麼作。每秒請求數不等於在線用戶數。數據庫基於web的UI
Locust具備簡潔的HTML + JS用戶界面,可實時顯示相關的測試細節。並且因爲UI是基於Web的,所以它是跨平臺且易於擴展的。json能夠測試任何系統
儘管Locust是面向web的,但它幾乎能夠用於測試任何系統。只須要未測試的內容編寫一個客戶端,而後用Locust訪問!超級簡單!windows可控
Locust很小,很容易被入侵,咱們打算保持這種狀態。事件I / O和協程的全部繁重工做都委託給gevent。替代測試工具的脆弱性是咱們建立Locust的緣由。
Locust背景
Locust
的誕生是由於咱們厭倦了現有的解決方案。對我來講,他們都沒有解決正確的問題,沒有抓住重點。咱們已經嘗試了Apache JMeter和Tsung。
這兩種工具均可以使用;咱們已經在工做中屢次使用了前一種方法。JMeter附帶UI界面,您可能會認爲這是一件好事。可是您很快就會意識到,經過某些點擊界面「編碼」你的測試方案是一種陷阱。其次,JMeter是線程綁定的。這意味着對於要模擬的每一個用戶,都須要一個單獨的線程。不用說,在一臺機器上對成千上萬的用戶進行基準測試是不可行的。
另外一方面,Tsung沒有這些線程問題,由於它是用Erlang編寫的。它能夠利用BEAM自身提供的輕量級流程,而且能夠愉快地擴展規模。可是在定義測試場景時,Tsung和JMeter同樣有限。它提供了基於XML的DSL來定義用戶在測試時的行爲方式。我想您能夠想象「編碼」這一點的恐怖。完成後顯示各類圖形或報告,須要對測試生成的日誌文件進行後期處理。只有這樣,您才能瞭解測試的具體狀況。
無論怎樣,咱們在創造Locust
的時候已經嘗試解決這些問題。但願以上這些痛點都不存在。
我猜你可能會說咱們真的只是在這裏撓癢癢。咱們但願其餘人會發現它和咱們同樣有用。
安裝
Locust能夠在PyPI上使用,而且能夠與pip一塊兒安裝。
1$ pip3 install locust
若是您想要最新版本,可使用pip直接從咱們的Git存儲庫安裝。例如,要使用Python 3安裝master分支:
1pip3 install -e git://github.com/locustio/locust.git@master#egg=locustio
安裝了Locust以後,您的shell中應該可使用Locust命令。(若是您沒有使用virtualenv—您應該使用—請確保您的python腳本目錄位於您的路徑上)。
要查看可用的選項,請運行:
1$ locust --help
Python版本支持
在Python 3.六、3.7和3.8
Windows上安裝locust
在Windows上,運行pip install locustio
便可。
可是,若是沒有成功,那麼能夠先安裝爲pyzmq、gevent和greenlet預先構建的二進制包來修復它。
你能夠在這裏找到一個非官方的集合,預先創建的python包的windows:
http://www.lfd.uci.edu/~gohlke/pythonlibs/
下載預構建的.whl
文件後,可使用如下方法進行安裝:
1$ pip install name-of-file.whl
而後可使用pip install locustio
進行安裝。
注意:
在Windows上運行Locust應該能夠很好地開發和測試您的負載測試腳本。可是,在運行大規模測試時,建議您在Linux機器上這樣作,由於gevent在Windows下的性能不好。
macOS上安裝Locust
當前是使用Homebrew在OS X上安裝gevent的最短路徑。
安裝Homebrew。
安裝libev(gevent的依賴):
1brew install libev
增長打開文件最大數限制
機器上的每一個HTTP鏈接打開一個新文件(技術上稱爲文件描述符)。操做系統能夠爲可打開的文件的最大數量設置一個較低的限制。若是該限制小於測試中模擬用戶的數量,則會發生故障。
將操做系統的默認最大文件數限制增長到大於你要運行的模擬用戶數的數量。如何執行此操做取決於所使用的操做系統。
快速入門Locust
例子locustfile.py
下面是一個簡單的locustfile.py的小例子:
1from locust import HttpLocust, TaskSet, between
2
3def login(l):
4 l.client.post("/login", {"username":"ellen_key", "password":"education"})
5
6def logout(l):
7 l.client.post("/logout", {"username":"ellen_key", "password":"education"})
8
9def index(l):
10 l.client.get("/")
11
12def profile(l):
13 l.client.get("/profile")
14
15class UserBehavior(TaskSet):
16 tasks = {index: 2, profile: 1}
17
18 def on_start(self):
19 login(self)
20
21 def on_stop(self):
22 logout(self)
23
24class WebsiteUser(HttpLocust):
25 task_set = UserBehavior
26 wait_time = between(5.0, 9.0)
這裏咱們定義了一些Locust任務,它們是普通的Python可調用函數,帶有一個參數(一個Locust
類實例)。這些任務收集在tasks屬性中的TaskSet
類下。而後,咱們有一個表明用戶的HttpLocust
類,在這個類中定義了模擬用戶在執行任務之間應等待的時間,以及哪一個TaskSet
類應定義用戶的「行爲」。TaskSet
類能夠嵌套。
HttpLocust
類繼承自Locust
類,而且添加了一個client屬性,該屬性是HttpSession
的實例,可用於發出HTTP請求。
默認狀況下,咱們再也不設置代理以提升性能。若是確實想要測試請求經過HTTP代理,你能夠繼承HttpLocust
類,並將trust_env字段設置爲True。有關更多細節,請參閱請求的文檔。
咱們聲明任務的另外一種方法(一般更方便)是使用@task裝飾器。下面代碼與上面的代碼效果同樣:
1from locust import HttpLocust, TaskSet, task, between
2
3class UserBehaviour(TaskSet):
4 def on_start(self):
5 """ on_start is called when a Locust start before any task is scheduled """
6 self.login()
7
8 def on_stop(self):
9 """ on_stop is called when the TaskSet is stopping """
10 self.logout()
11
12 def login(self):
13 self.client.post("/login", {"username":"ellen_key", "password":"education"})
14
15 def logout(self):
16 self.client.post("/logout", {"username":"ellen_key", "password":"education"})
17
18 @task(2)
19 def index(self):
20 self.client.get("/")
21
22 @task(1)
23 def profile(self):
24 self.client.get("/profile")
25
26class WebsiteUser(HttpLocust):
27 task_set = UserBehaviour
28 wait_time = between(5, 9)
Locust
類(以及HttpLocust
,由於它是一個子類)還容許您指定任務執行之間的等待時間(wait_time = between(5, 9)
)以及其餘用戶行爲。使用between函數,能夠在指定的最大值和最小值之間隨機選擇時間,可是能夠經過將wait_time設置爲任意函數來使用任何用戶定義的時間分佈。例如,對於平均時間爲1秒的指數分佈等待時間:
1import random
2
3class WebsiteUser(HttpLocust):
4 task_set = UserBehaviour
5 wait_time = lambda self: random.expovariate(1)*1000
啓動Locust
要使用上述Locust文件運行Locust,若是該文件名爲locustfile.py且位於當前工做目錄中,則能夠運行:$ locust
若是Locust文件位於與locustfile.py在不一樣的子目錄/或者文件名不同,則使用參數-f
+文件名:$ locust -f locust_files/my_locust_file.py
要在多個進程中運行Locust,咱們能夠經過指定--master
:$ locust -f locust_files/my_locust_file.py --master
而後咱們將啓動任意數量的從屬進程:$ locust -f locust_files/my_locust_file.py --slave
若是要在多臺機器上運行Locust,則在啓動從屬服務器時還必須指定主服務器主機(在單臺計算機上運行Locust時不須要,由於主服務器主機默認爲127.0.0.1):$ locust -f locust_files/my_locust_file.py --slave --master-host=192.168.0.100
還能夠在配置文件(locust.conf或~/.locust.conf)或以LOCUST_前綴的env vars中設置參數
例如:(這將與上一個命令執行相同的操做)$ LOCUST_MASTER_HOST=192.168.0.100 locust
注意:要查看全部可用選項,請鍵入:locust—help
打開Locust的Web界面
使用上述命令行之一啓動Locust後,應打開瀏覽器並輸入http://127.0.0.1:8089或者http://localhost:8089(若是您在本地運行Locust)。而後,你會看到如下界面:
(或者瀏覽器中訪問ipv6本地地址:http://[::1]:8089, 也可)

若是您在逐步負載模式
下運行Locust,,則應該使用如下Locust UI,以下所示:

而後在上述幾面中輸入數量,以及要訪問的URL,點擊Start便可看到響應數據,以下圖:

Locust--CSV存儲測試數據
Locust的測試結果保存到CSV文件,在這種狀況下,有兩種方法能夠執行此操做。
首先,經過Web UI運行Locust時,能夠在「Download Data」選項卡下獲得CSV文件。
其次,可使用標籤運行Locust,該標籤將按期保存兩個CSV文件。若是計劃使用--no-web
標籤以自動化方式運行Locust,這將特別有用:
1$ locust -f examples/basic.py --csv=example --no-web -t10m
文件將被命名爲example_response_times.csv
和 example_stats.csv
(使用--csv=example
)並記錄Locust構建的信息。
若是你想要更快(慢)的寫入速度,也能夠自動以寫入頻率:
1import locust.stats
2# 默認爲2秒
3locust.stats.CSV_STATS_INTERVAL_SEC = 5
此數據將寫入兩個文件,並將_response_times.csv
和_stats.csv
添加到你提供的名稱中:
1$ cat example_response_times.csv
2"Name","# requests","50%","66%","75%","80%","90%","95%","98%","99%","99.9%","99.99%","100%"
3"GET /",31,4,4,4,4,4,4,4,4,4,4,4
4"/does_not_exist",0,"N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A"
5"GET /stats/requests",38,3,4,4,4,4,5,5,5,5,5,5
6"None Total",69,3,4,4,4,4,4,5,5,5,5,5
和
1$ cat example_stats.csv
2"Type","Name","# requests","# failures","Median response time","Average response time","Min response time","Max response time","Average Content Size","Requests/s"
3"GET","/",51,0,4,3,2,6,12274,0.89
4"GET","/does_not_exist",0,56,0,0,0,0,0,0.00
5"GET","/stats/requests",58,0,3,3,2,5,1214,1.01
6"None","Total",109,56,3,3,2,6,6389,1.89
編寫一個locustfile
locustfile是普通的python文件。惟一的要求是至少聲明一個類(咱們稱之爲locust類),該類繼承自locust類。
Locust類
一個Locust類表明一個用戶(或者一個集羣Locust)。Locust將爲每一個正在模擬的用戶生成(孵化)一個Locust類實例。Locust類一般應該定義一些屬性。
task_set屬性
task_set屬性應該指向一個TaskSet類,這個類定義了用戶的行爲,下面將對其進行更詳細的描述。
wait_time屬性
除了task_set屬性,還應該聲明一個wait_time
方法。它用於肯定模擬用戶在執行任務之間將等待多長時間。Locust提供了一些內置的函數,返回一些經常使用的wait_time方法。
最多見的是 between
。它用於使模擬用戶在每次執行任務後等待介於最小值和最大值之間的隨機時間。其餘內置的等待時間函數是constant
和constant_pacing
。
使用如下locustfile,每一個用戶將在任務之間等待5到15秒:
1from locust import Locust, TaskSet, task, between
2
3class MyTaskSet(TaskSet):
4 @task
5 def my_task(self):
6 print("executing my_task")
7
8class User(Locust):
9 task_set = MyTaskSet
10 wait_time = between(5, 15)
wait_time方法應該返回秒數(或幾分之一秒),也能夠在TaskSet類上聲明,在這種狀況下,它將僅用於該TaskSet。
也能夠直接在Locust或TaskSet類上聲明本身的wait_time方法。接下來的Locust類將開始休眠1秒鐘,而後休眠1秒,2秒,3秒,等等。
1class MyLocust(Locust):
2 task_set = MyTaskSet
3 last_wait_time = 0
4
5 def wait_time(self):
6 self.last_wait_time += 1
7 return self.last_wait_time
weight (權重)屬性
若是文件中存在多個locust類,而且命令行中沒有指定locust,則每一個新生成的locust將從現有locust中隨機選擇。不然,你能夠從相同的文件中像下面這樣指定使用哪一個locust:$ locust -f locust_file.py WebUserLocust MobileUserLocust
若是你想讓這些locust中的一個執行得更頻繁,你能夠給這些類設置一個權重屬性。例如,Web用戶是mobile用戶的三倍:
1class WebUserLocust(Locust):
2 weight = 3
3 ...
4
5class MobileUserLocust(Locust):
6 weight = 1
7 ...
host屬性
host屬性host屬性是要加載的URL前綴(https://cn.bing.com);一般,是在Locust的Web UI或命令行中指定的,在啓動Locust時使用--host
。
若是在locust類中聲明瞭一個host屬性,則在命令行或Web請求中未指定--host
的狀況下將使用該屬性。。
TaskSet類
若是Locust類表明蝗蟲羣,則能夠說TaskSet類表明蝗蟲的大腦。每一個Locust類必須設置一個task_set屬性,該屬性指向TaskSet。
顧名思義,TaskSet是任務的集合。這些任務是普通的python可調用對象,而且,若是咱們正在對拍賣網站進行負載測試,則能夠完成諸如「加載起始頁」,「搜索某些產品」和「競標」之類的工做。
啓動負載測試時,派生的Locust類的每一個實例將開始執行其TaskSet。接下來的狀況是每一個TaskSet將選擇一個任務並調用它。而後,它將等待Locust類的wait_time方法指定的秒數(除非已直接在TaskSet上聲明瞭wait_time方法,在這種狀況下,它將使用本身的方法)。
而後它將再次選擇要調用的新任務,再次等待,依此類推。
聲明任務
TaskSet聲明任務的典型方式是使用task
裝飾器。
這裏有一個例子:
1from locust import Locust, TaskSet, task
2
3class MyTaskSet(TaskSet):
4 @task
5 def my_task(self):
6 print("Locust instance (%r) executing my_task" % (self.locust))
7
8class MyLocust(Locust):
9 task_set = MyTaskSet
@task使用可選的weight參數,該參數可用於指定任務的執行率。在如下示例中,task2的執行量是task1的兩倍:
1from locust import Locust, TaskSet, task
2from locust.wait_time import between
3
4class MyTaskSet(TaskSet):
5 wait_time = between(5, 15)
6
7 @task(3)
8 def task1(self):
9 pass
10
11 @task(6)
12 def task2(self):
13 pass
14
15class MyLocust(Locust):
16 task_set = MyTaskSet
tasks屬性
使用@task裝飾器來聲明任務是一種方便的方法,一般也是最好的方法。可是,也能夠經過設置tasks
屬性來定義TaskSet的任務(使用@task裝飾器實際上只填充tasks屬性)。
tasks屬性要麼是python可調用項的列表,要麼是
這些任務是接收一個參數的python可調用函數——正在執行任務的TaskSet類實例。
1from locust import Locust, TaskSet
2
3def my_task(l):
4 pass
5
6class MyTaskSet(TaskSet):
7 tasks = [my_task]
8
9class MyLocust(Locust):
10 task_set = MyTaskSet
若是將tasks屬性指定爲列表,那麼每次執行任務時,都將從tasks屬性中隨機選擇該任務。可是,若是任務是字典(將可調用對象做爲鍵,將整數做爲值),則將隨機選擇要執行的任務,但將int值做爲比率。所以,任務看起來像這樣:{my_task: 3, another_task: 1}
my_task被執行的可能性是other_task的3倍。
TaskSets可嵌套
TaskSet的一個很是重要的特性是它們能夠嵌套,由於真實的網站一般以分層的方式構建,包含多個子部分。所以,嵌套任務集將容許咱們定義一種行爲,以更現實的方式來模擬用戶。例如,咱們可使用如下結構定義· - ----- TaskSet:
Main user behaviour
Watch movie
Filter movies
Read thread
Reply
New thread
View next page
Index page
Forum page
Browse categories
About page
嵌套TaskSet的方式就像使用task屬性指定任務時同樣,但不是引用python函數,而是引用另外一個TaskSet:
1class ForumPage(TaskSet):
2 @task(20)
3 def read_thread(self):
4 pass
5
6 @task(1)
7 def new_thread(self):
8 pass
9
10 @task(5)
11 def stop(self):
12 self.interrupt()
13
14class UserBehaviour(TaskSet):
15 tasks = {ForumPage:10}
16
17 @task
18 def index(self):
19 pass
所以,在上面的示例中,若是在執行UserBehaviour TaskSet時選擇了要執行的ForumPage,則ForumPage TaskSet將開始執行。而後,ForumPage TaskSet將選擇其本身的任務之一,執行它,等待,依此類推。
關於上述示例,須要注意一點,那就是在ForumPage的stop方法中調用self.interrupt()。這樣作其實是中止執行ForumPage任務集,並在UserBehaviour實例中繼續執行。若是咱們在ForumPage的某處沒有調用interrupt()方法,Locust將永遠不會中止運行已經啓動的ForumPage任務。可是經過使用中斷功能,咱們能夠與任務權重一塊兒定義模擬用戶離開論壇的可能性。
也可使用@task裝飾器在類中內聯聲明嵌套的TaskSet,就像聲明普通任務時同樣:
1class MyTaskSet(TaskSet):
2 @task
3 class SubTaskSet(TaskSet):
4 @task
5 def my_task(self):
6 pass
引用Locust實例,或父TaskSet實例
TaskSet實例的屬性locust指向它的locust實例,屬性parent指向它的父TaskSet(它將在基本TaskSet中指向Locust實例)。
TaskSequence類
TaskSequence類是一個TaskSet,可是它的任務是按順序執行的。
要定義此順序,您應該執行如下操做:
1 @seq_task(1)
2 def first_task(self):
3 pass
4
5 @seq_task(2)
6 def second_task(self):
7 pass
8
9 @seq_task(3)
10 @task(10)
11 def third_task(self):
12 pass
在上面的示例中,執行順序定義爲先執行first_task,而後執行second_task,最後執行Third_task 10次。能夠看到,可使用@task裝飾器組合@seq_task,固然也能夠將TaskSet嵌套在TaskSequences中,反之亦然。
Setups, Teardowns, on_start, 和on_stop
Locust還支持Locust級setup
和teardown
,TaskSet級setup
和teardown
,TaskSet
'、 on_start
和on_stop
.
Setups 和 Teardowns
setup
和teardown
,不管是在Locust
仍是TaskSet
上運行,都是隻運行一次的方法。setup
是在任務開始運行以前運行,而teardown
是在全部任務完成並退出Locust以後運行的。這使你可以在Locust任務運行以前執行一些準備工做(如建立數據庫),並在Locust退出以前進行清理(如刪除數據庫)。
要使用它,只需在Locust或TaskSet類上聲明一個setup或teardown。這些方法將爲你運行。
on_start和on_stop方法
TaskSet類能夠聲明on_start
方法或on_stop
方法。
當模擬用戶開始執行該TaskSet類時,將調用on_start
方法;而當TaskSet中止時,將調用on_stop <locust.core.TaskSet.on_stop()
方法。
事件順序
因爲許多設置和清除操做是相互依賴的,所以如下是它們的執行順序:
Locust setup (一次)
TaskSet setup (一次)
TaskSet on_start (每一個locust一次)
TaskSet tasks…
TaskSet on_stop (每一個locust一次)
TaskSet teardown (一次)
Locust teardown (一次)
一般,setup和teardown方法應該是互補的。
發送HTTP請求
到目前爲止,咱們僅介紹了Locust用戶的任務調度部分。爲了實際測試系統,咱們須要發送HTTP請求。爲了幫助咱們作到這一點,存在HttpLocust
類。當使用這個類時,每一個實例得到一個client屬性,該屬性將是HttpSession的一個實例,可用於發送HTTP請求。
HttpLocust類
表示一個HTTP「用戶」,該「用戶」將被孵化並攻擊要加載測試的系統。
此用戶的行爲由task_set屬性定義,該屬性應指向TaskSet
類。
該類在實例化時建立一個client屬性,該屬性是一個HTTP client ,支持在請求之間保持用戶會話。
client= None
在Locust實例化後建立的HttpSession實例。客戶端支持cookie,所以在HTTP請求之間的會話。
在繼承HttpLocust類時,咱們可使用它的client屬性對服務器發出HTTP請求。
這是一個Locust文件的例子,能夠用兩個URL負載測試站點 ;/ 和 /about/:
1from locust import HttpLocust, TaskSet, task, between
2
3class MyTaskSet(TaskSet):
4 @task(2)
5 def index(self):
6 self.client.get("/")
7
8 @task(1)
9 def about(self):
10 self.client.get("/about/")
11
12class MyLocust(HttpLocust):
13 task_set = MyTaskSet
14 wait_time = between(5, 15)
使用上面的Locust類,每一個模擬用戶將在請求之間等待5到15秒,而且 / 被請求的時間將是 /about/ 的兩倍。
細心的讀者會發現奇怪的是,咱們可使用TaskSet中的self.client而不是self.locust.client來引用HttpSession實例。咱們能夠這樣作是由於TaskSet
類有一個方便的屬性client,該屬性僅返回self. custt .client。
使用HTTP客戶端
HttpLocust的每一個實例在client屬性中都有一個HttpSession
實例。HttpSession類其實是request.Session
的子類,可用於發出HTTP請求,該請求將使用get,post,put,put,delete,head,patch和options方法將其統計數據報給Locust。HttpSession實例將在請求之間保存cookie,以便用於登陸網站並在請求之間保持會話。也能夠從Locust實例的TaskSet實例中引用client屬性,以便輕鬆地檢索客戶端併發出HTTP請求。
下面是一個簡單的示例,它向 / about 路徑發出GET請求(在這種狀況下,咱們假設self是TaskSet
或HttpLocust
類的實例:
1response = self.client.get("/about")
2print("Response status code:", response.status_code)
3print("Response content:", response.text)
這裏有一個POST請求的例子:
1response = self.client.post("/login",
2 {"username":"testuser",
3 "password":"secret"}
4 )
安全模式
HTTP客戶端配置爲以safe_mode運行。這樣作的目的是,因爲鏈接錯誤、超時或相似緣由而失敗的任何請求都不會引起異常,而是返回一個空的虛擬Response對象。該請求將在Locust的統計信息中標記爲失敗。返回的虛擬Response的content屬性將設置爲None,其status_code=0。
手動控制請求是成功仍是失敗
默認狀況下,除非HTTP響應代碼爲OK(<400),不然請求將被標記爲失敗的請求。大多數狀況下,此默認值是你想要的。可是,有時(例如,在測試URL端點時,你指望返回404,或者在測試一個設計糟糕的系統時,即便出現錯誤也可能返回200 OK)——須要手動控制Locust是否應該將請求標記爲成功或失敗。
經過使用catch_response參數和with語句,即便響應代碼正確,也能夠將請求標記爲失敗:
1with self.client.get("/", catch_response=True) as response:
2 if response.content != b"Success":
3 response.failure("Got wrong response")
正如能夠將具備OK響應代碼的請求標記爲失敗同樣,也能夠將catch_response參數與with語句一塊兒使用,以標記致使HTTP錯誤代碼的請求在統計中仍被報告爲成功:
1with self.client.get("/does_not_exist/", catch_response=True) as response:
2 if response.status_code == 404:
3 response.success()
將帶有動態參數的URL請求分組
網站的url包含一些動態參數的頁面是很常見的。一般在Locust的統計信息中將這些URL分組在一塊兒是頗有意義的。這能夠經過將名稱參數傳遞給HttpSession的不一樣請求方法來完成。
例如:
1# 這些請求的統計數據將納入如下類別: /blog/?id=[id]
2for i in range(10):
3 self.client.get("/blog?id=%i" % i, name="/blog?id=[id]")
公共庫--Common libraries
一般,將共享公共庫的多個locustfiles分組。在這種狀況下,在項目中根目錄定義爲調用Locust的目錄很是重要,建議全部的locust文件都位於項目根目錄下。
平面文件結構以下:
project root
commonlib_config.py
commonlib_auth.py
locustfile_web_app.py
locustfile_api.py
locustfile_ecommerce.py
locustfile可使用如下命令導入公共庫,例如:import commonlib_auth
。可是,這種方法並不能清楚地將公共庫與Locust文件分開。
子目錄能夠是一種更簡潔的方法(請參見下面的示例),但locust只導入與運行的locustfile所在目錄相關的模塊。若是但願從項目根目錄(即運行locust命令的位置)導入,請確保在loucst文件導入任何公共庫以前編寫sys.path.append(os.getcwd())
,這將使項目根目錄(即當前工做目錄)可導入。
project root
init.py
common/
`init.py`
`config.py`
`auth.py`
locustfiles/
`init.py`
`web_app.py`
`api.py`
`ecommerce.py`
經過以上項目結構,locust文件可使用如下方法導入公共庫:
1sys.path.append(os.getcwd())
2import common.auth
Locust--分佈式運行
若是一臺計算機不足以模擬所需的用戶數量,那麼Locust將支持運行分佈在多臺計算機上的負載測試。
可使用--master
標誌在主模式下啓動Locust的一個實例。這個實例將運行Locust的web接口,您能夠在這裏啓動測試並實時查看統計信息。主節點自己不模擬任何用戶。相反,您必須使用--slave
標誌啓動一個或多個從Locust節點,與--master-host
(指定主節點的IP /主機名)一塊兒使用。
常見的設置是在一臺機器上運行一個主程序,而後在從計算機上每一個處理器內核運行一個從屬實例。
注意:
在運行Locust分佈式系統時,主計算機和每一個從屬計算機都必須具備蝗蟲測試腳本的副本。
當分佈式運行的時候,建議啓動的模擬用戶數量要大於
Locust類的數量X從機的數量
。
不然,因爲當前的實現,可能會獲得與Locust類的weight
屬性不對應的Locust類分佈。
並且,若是孵化率低於從屬節點的數量,則孵化將在「突發」中發生,其中全部從屬節點將孵化單個用戶,而後休眠數秒鐘,孵化另外一個用戶,休眠並重復。
例如:
要在master模式下啓動Locust:locust -f my_locustfile.py --master
選項--master
將Locust設置爲主模式, web接口將在此節點上運行。
-- slave
將Locust設置爲從屬模式。
--master-host=X.X.X.X
可選,與-- slave
一塊兒使用,設置主節點的主機名/IP(默認爲127.0.0.1)
--master-port=5557
可選,與-- slave
一塊兒使用,用於設置主節點的端口號(默認爲5557)。
注意,locust將使用指定的端口,以及端口號+1。所以,若是使用5557,則locust將同時使用端口5557和5558。
--master-bind-host=X.X.X.X
可選,與-- master
一塊兒使用。肯定主節點將綁定到哪一個網絡接口。默認爲*(全部可用的接口)。
--master-bind-port=5557
可選,與-- master
一塊兒使用。肯定主節點將監聽的網絡端口。默認爲5557。
注意,locust將使用指定的端口,以及端口號+1。所以,若是使用5557,則locust將同時使用端口5557和5558。
--expect-slaves=X
使用--no-web
啓動主節點時使用。而後,主節點將一直等到鏈接了X個從節點以後纔開始測試。
使用Docker進行分佈式運行
詳見 性能測試Locust--(5)Docker運行 [詳見後文]
非UI模式下分佈式運行Locust
詳見 性能測試Locust--(6)非UI模式下分佈式運行Locust [詳見後文]
逐步負載模式下分佈式運行Locust
詳見 性能測試Locust--(4)逐步負載模式 [詳見後文]
提升蝗蟲的性能
若是你打算運行大規模負載測試,你可能會對使用Locust附帶的備用HTTP client 感興趣。
詳見 [Increase Locust’s performance with a faster HTTP client]
https://docs.locust.io/en/stable/increase-performance.html#increase-performance
Locust--逐步負載模式
若是想在不一樣的用戶負載下監控服務性能,並探測能夠實現的最大tps,能夠在啓用「逐步負載」模式運行Locust--stp-load
1$ locust -f locust_files/my_locust_file.py --step-load
選項
--step-load
啓用「Step Load--逐步負載」模式, 以監視當用戶負載增長時性能指標如何變化。
--step-clients
在「逐步負載」模式下,客戶端數量逐步增長。與--step-load
一塊兒使用。
--step-time
在「逐步負載」模式下,每一個Step的進持續時間,例如(300s,20m,3h,1h30m等)。與--step-load
一塊兒使用。
Locust在非Web UI的狀況下「逐步負載」模式運行
若是要在沒有Web UI的狀況下以逐步負載方式運行Locust,則可使用--step-clients
和--step-time
來執行此操做:
1$ locust -f --no-web -c 1000 -r 100 --run-time 1h30m --step-load --step-clients 300 --step-time 20m
Locust 將逐步蜂擁而至,一旦時間到了,將關閉它們。
Locust在逐步負載模式下分佈式運行
若是你想要在逐步負載模式下分佈式運行Locust,你應該在啓動主節點時指定--step-load
選項,來分步式彙集locust。而後在Locust UI中將顯示 --step-cients
選項和 --step-time
選項。
Locust--Docker運行Locust
爲了簡單起見,咱們提供了一個能夠獨立運行的Docker映像,能夠做爲主映像,也能夠做爲從映像。
環境變量
LOCUST_MODE
standalone、master 或者 slave。
默認是standalone。LOCUSTFILE_PATH
容器內部到locustfile的路徑。默認爲/locustfile.py
.LOCUST_MASTER_HOST
master的主機名。LOCUST_MASTER_PORT
與master通訊的端口。默認爲5557LOCUST_OPTS
傳遞給Locust的其餘選項。默認爲''
運行測試
運行測試最簡單的方法是使用內置的測試文件構建映像。一旦編寫了locustfile,就可使用一個簡單的Dockerfile
將其打包到Docker映像中:
須要將構建的映像推送到Dockerhub,AWS ECR或GCR等Docker存儲庫中,以便分佈式基礎架構可以提取該鏡像。請參閱所選存儲庫的文檔,以瞭解如何經過存儲庫進行身份驗證以獲取鏡像。
爲了在本地調試,您能夠運行一個容器並將locustfile做爲volume傳遞進來:
要在沒有Web UI的獨立模式下運行,可使用LOCUST_OPTS
環境變量添加所需的選項:
若是您是Kubernetes用戶,則可使用[Helm chart]
https://github.com/helm/charts/tree/master/stable/locust
Locust--非UI模式下運行Locust
能夠在沒有Web UI的狀況下運行Loccust.
例如,若是要以某種自動化流程(例如CI服務器)運行Locust,經過使用--no-web
標記和-c
和-r
:
1$ locust -f locust_files/my_locust_file.py --no-web -c 1000 -r 100
-c
指定要生成的Locust用戶數;-r
指定孵化率(每秒產生的用戶數)。
爲測試設置時間限制
若是要指定測試的運行時間,可使用 --run-time
或者 -t
:
1$ locust -f --no-web -c 1000 -r 100 --run-time 1h30m
一旦時間到,Locust將關閉。
容許任務在關閉時完成其迭代
默認狀況下,Locust將當即中止任務。若是想讓任務完成迭代,則可使用--stop-timeout <seconds>
。
1$ locust -f --no-web -c 1000 -r 100 --run-time 1h30m --stop-timeout 99
非Web UI的狀況下分佈式運行Locust
在非UI狀況下想分佈式運行Locust,應該在啓動主節點時指定--expect-slaves
選項,指定但願鏈接的從節點的數量。而後,將一直等到鏈接了諸多從節點以後纔開始測試。
Locust--使用更快的HTTP client提升Locust性能
Locust默認的HTTP客戶端使用python-requests。由於requests是一個維護良好的python程序包,它提供了許多python開發人員都熟悉的優質API。所以,在許多狀況下,建議使用使用請求的默認HttpLocust
。
可是,若是計劃運行大規模的測試,Locust提供了一個替代的HTTP 客戶端 FastHttpLocust
,它使用geventhttpclient而不是requests。
該客戶端的速度明顯提升,其性能是HTTP-requests的5 ~ 6倍。這並不必定意味着每一個CPU內核能夠模擬的用戶數量將自動增長5 ~ 6倍,由於這還取決於負載測試腳本。
總之,若是你的Locust腳本在執行HTTP-requests時花費了大量的CPU時間,那麼你可能會看到顯著的性能提高。
如何使用FastHttpLocust
代替HttpLocust的子類是FastHttpLocust:
1from locust import TaskSet, task, between
2from locust.contrib.fasthttp import FastHttpLocust
3
4class MyTaskSet(TaskSet):
5 @task
6 def index(self):
7 response = self.client.get("/")
8
9class MyLocust(FastHttpLocust):
10 task_set = MyTaskSet
11 wait_time = between(1, 60)
注意
與默認python-requests的HttpLocust相比,FastHttpLocust使用一個徹底不一樣的API實現另外一個HTTP client 。所以,取決於如何使用HttpClient,FastHttpLocust可能沒法替代HttpLocust。
在FastHttpLocust的客戶端實現中,SSL域名檢查被關閉。所以,它將容許經過無效的SSL證書而不會產生任何問題。
API
FastHttpSession類
classFastHttpSession(base_url, **kwargs)
init(base_url, **kwargs) | x.init(…) 初始化X,詳見 help |
get(path, **kwargs) | 發送GET請求 |
head(path, **kwargs) | 發送HEAD請求 |
options(path, **kwargs) | 發送OPTION請求 |
patch(path, data=None, **kwargs) | 發送PATCH請求 |
post(path, data=None, **kwargs) | 發送POST請求 |
put(path, data=None, **kwargs) | 發送PUT請求 |
request(method, path, name=None, data=None, catch_response=False, stream=False, headers=None, auth=None, **kwargs)
發送HTTP請求並返回locust.contrib.fasthttp.FastResponse
對象.
Parameters:
method --建立新Request對象方法。
path --Path將與已指定的base host URL鏈接。也能夠是完整URL,在這種狀況下,將請求完整URL,而且忽略host。
name --可選,在Locust的統計信息中能夠指定一個參數做爲標籤,而不是URL路徑。這可用於將請求的不一樣URL分組到Locust的統計信息中的單個條目中。
catch-response --可選,Boolean,若是設置了Boolean參數,可用於使請求返回上下文管理器,以用做with語句的參數。即便響應代碼正常(2xx),也能夠根據響應的內容將請求標記爲失敗。
反之亦然,即便沒有響應代碼(即500或404),也可使用catch_response來捕獲請求,而後將其標記爲成功。data -- 可選,請求體-body, Dict或bytes
headers -- 可選,請求頭,Dict
auth -- 可選,驗證(用戶名,密碼)元組,以啓用基本HTTP驗證。
stream -- 可選,若是設置爲true,則不會當即使用響應主體,而是能夠經過訪問Response對象上的stream屬性來使用它。
將流設置爲True的另外一個做用是:不會將下載響應內容的時間記錄到Locust報告中的請求時間。
classFastResponse(ghc_response, request=None, sent_request=None)
content
Unzips, 若有必要,並緩衝接收到的Body. 當心大文件!
headers= None
相似於Dict的對象,包含響應標頭
text
以解碼字符串的形式返回響應的文本內容(python2上的unicode)
Locust--CSV存儲測試數據
Locust的測試結果保存到CSV文件,在這種狀況下,有兩種方法能夠執行此操做。
首先,經過Web UI運行Locust時,能夠在「Download Data」選項卡下獲得CSV文件。
其次,可使用標籤運行Locust,該標籤將按期保存兩個CSV文件。若是計劃使用--no-web
標籤以自動化方式運行Locust,這將特別有用:
1$ locust -f examples/basic.py --csv=example --no-web -t10m
文件將被命名爲example_response_times.csv
和 example_stats.csv
(使用--csv=example
)並記錄Locust構建的信息。
若是你想要更快(慢)的寫入速度,也能夠自動以寫入頻率:
1import locust.stats
2# 默認爲2秒
3locust.stats.CSV_STATS_INTERVAL_SEC = 5
此數據將寫入兩個文件,並將_response_times.csv
和_stats.csv
添加到你提供的名稱中:
1$ cat example_response_times.csv
2"Name","# requests","50%","66%","75%","80%","90%","95%","98%","99%","99.9%","99.99%","100%"
3"GET /",31,4,4,4,4,4,4,4,4,4,4,4
4"/does_not_exist",0,"N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A"
5"GET /stats/requests",38,3,4,4,4,4,5,5,5,5,5,5
6"None Total",69,3,4,4,4,4,4,5,5,5,5,5
和
1$ cat example_stats.csv
2"Type","Name","# requests","# failures","Median response time","Average response time","Min response time","Max response time","Average Content Size","Requests/s"
3"GET","/",51,0,4,3,2,6,12274,0.89
4"GET","/does_not_exist",0,56,0,0,0,0,0,0.00
5"GET","/stats/requests",58,0,3,3,2,5,1214,1.01
6"None","Total",109,56,3,3,2,6,6389,1.89
使用定製的客戶端測試其餘系統
以HTTP爲主要目標構建Locust。可是,經過編寫觸發request_success
和request_failure
事件的自定義客戶端,能夠很容易的將其擴展,用來對任何基於request/response
的系統進行負載測試。
Locust client示例--XML-RPC
如下是Locust類XmlRpcLocust
的示例,該類提供XML-RPC客戶端XmlRpcClient並跟蹤全部發出的請求:
1import time
2import xmlrpclib
3
4from locust import Locust, TaskSet, events, task, between
5
6
7class XmlRpcClient(xmlrpclib.ServerProxy):
8 """
9 Simple, sample XML RPC client implementation that wraps xmlrpclib.ServerProxy and
10 fires locust events on request_success and request_failure, so that all requests
11 gets tracked in locust's statistics.
12 """
13 def __getattr__(self, name):
14 func = xmlrpclib.ServerProxy.__getattr__(self, name)
15 def wrapper(*args, **kwargs):
16 start_time = time.time()
17 try:
18 result = func(*args, **kwargs)
19 except xmlrpclib.Fault as e:
20 total_time = int((time.time() - start_time) * 1000)
21 events.request_failure.fire(request_type="xmlrpc", name=name, response_time=total_time, exception=e)
22 else:
23 total_time = int((time.time() - start_time) * 1000)
24 events.request_success.fire(request_type="xmlrpc", name=name, response_time=total_time, response_length=0)
25 # In this example, I've hardcoded response_length=0. If we would want the response length to be
26 # reported correctly in the statistics, we would probably need to hook in at a lower level
27
28 return wrapper
29
30
31class XmlRpcLocust(Locust):
32 """
33 This is the abstract Locust class which should be subclassed. It provides an XML-RPC client
34 that can be used to make XML-RPC requests that will be tracked in Locust's statistics.
35 """
36 def __init__(self, *args, **kwargs):
37 super(XmlRpcLocust, self).__init__(*args, **kwargs)
38 self.client = XmlRpcClient(self.host)
39
40
41class ApiUser(XmlRpcLocust):
42
43 host = "http://127.0.0.1:8877/"
44 wait_time = between(0.1, 1)
45
46 class task_set(TaskSet):
47 @task(10)
48 def get_time(self):
49 self.client.get_time()
50
51 @task(5)
52 def get_random_number(self):
53 self.client.get_random_number(0, 100)
若是你之前編寫過 Locust的測試,你應該知道一個名爲 ApiUser 的類,它是一個普通的 Locust 類,它的 task_set屬性是一個 TaskSet 類的子類,而這個子類帶有多個 task。
然而,ApiUser 繼承自 XmlRpcLocust,您能夠在 ApiUser 的正上方看到它。XmlRpcLocust 類在 client 屬性下提供 XmlRpcClient 的實例。XmlRpcClient 是標準庫的 xmlrclib. serverproxy
的裝飾器。它基本上只是代理函數調用,可是添加了觸發用於將全部調用報告給 Locust 統計數據的 locust.events.request_success
和 locust.events.request_failure
的重要功能。
下面是 XML-RPC 服務器的實現,它能夠做爲上述代碼的服務器:
1import random
2import time
3from SimpleXMLRPCServer import SimpleXMLRPCServer
4
5
6def get_time():
7 time.sleep(random.random())
8 return time.time()
9
10def get_random_number(low, high):
11 time.sleep(random.random())
12 return random.randint(low, high)
13
14server = SimpleXMLRPCServer(("localhost", 8877))
15print("Listening on port 8877...")
16server.register_function(get_time, "get_time")
17server.register_function(get_random_number, "get_random_number")
Locust--Locust API以及延伸擴展--0.14.4
Locust延伸擴展
Locust附帶了不少事件,這些事件提供了以不一樣方式擴展Locust的鉤子(hooks )。
事件監聽器能夠在模塊級註冊到Locust文件中。這裏有一個例子:
1from locust import events
2
3def my_success_handler(request_type, name, response_time, response_length, **kw):
4 print "Successfully fetched: %s" % (name)
5
6events.request_success += my_success_handler
注意:
強烈建議你在偵聽器中添加通配符關鍵字參數(上面代碼中的** kw),以防止在之後的版本中添加新參數時代碼崩潰。
要查看全部可用事件,請參閱事件[掛鉤](https://docs.locust.io/en/stable/api.html#events)。
添加網絡路由
Locust使用Flask來提供Web UI,所以很容易將Web端點添加到Web UI。只需將Flask應用程序導入您的locustfile並設置一條新路徑:
1from locust import web
2
3@web.app.route("/added_page")
4def my_added_page():
5 return "Another page"
如今應該可以啓動locust並瀏覽到:http://127.0.0.1:8089/added_page
Locust日誌記錄
Locust附帶有基本的日誌記錄配置,該配置能夠選擇使用--loglevel
和/或--logfile
來修改配置。若是要控制日誌記錄配置,則能夠提供--skip-log-setup
標誌,該標誌將忽略其餘參數。
Options選項
--skip-log-setup
禁用Locust的日誌記錄設置。相反,配置是由Locust test或Python默認設置提供配置。
--loglevel
在DEBUG/INFO/WARNING/ERROR/CRITICAL之間選擇。默認值爲INFO。簡寫爲-L
。
--logfile
日誌文件的路徑。若是未設置,則日誌將轉到stdout / stderr。
Locust API
API的話以官網爲準,如下是官網連接
API 官網連接 :https://docs.locust.io/en/stable/api.html
Locust 類
class Locust
表示一個策劃並將要對系統進行負載測試的「用戶」。
此用戶的行爲由task_set
屬性定義,該屬性應該指向TaskSet類。
此類一般應由定義某種客戶端的類繼承。例如,在對HTTP系統進行負載測試時,您可能但願使用HttpLocust
類。task_set= None
TaskSet類,定義此Locust的執行行爲
wait_time= None
該方法,返回執行Locust任務之間的時間(以秒爲單位)。能夠爲單個TaskSet覆蓋。
例如:
1from locust import Locust, between
2class User(Locust):
3 wait_time = between(3, 25)
weight= 10
Locust被選中執行的機率。權重越高,被選中的機會越大。
HTTPLocust 類
class HttpLocust
表示一個策劃並將要對系統進行負載測試的HTTP「用戶」。
該HTTP用戶的行爲由task_set
屬性定義,該屬性應該指向TaskSet
類。
這個類在實例化時會建立一個 client 屬性,這個屬性的值是一個支持在請求間保持用戶會話(user session)的 HTTP 客戶端。
client=None
在 locust 實例化時建立的 HttpSession 實例。客戶端支持 cookies,所以在 HTTP 請求間保持會話。
TaskSet類
class TaskSet(parent)
該類定義locust
用戶將要執行的一組任務。
當 TaskSet開始運行時,它將從 tasks 屬性中選擇一個任務並執行,而後調用這個任務的 wait_function 方法,以後再調用另外一個任務,以此類推。
其中 wait_function 方法定義並返回一個以毫秒爲單位的睡眠時間,wait_function 方法定義的睡眠時間的默認是介於 min_wait 和 max_wait 之間且均勻分佈的隨機數;而後它將調度另外一個任務執行,等等。
TaskSets能夠嵌套,這意味着一個 TaskSet 的 tasks 屬性能夠包含其餘的 TaskSet。若是計劃執行嵌套的 TaskSet ,則將實例化它並從當前執行的 TaskSet 進行調用。而後,當前運行的 TaskSet 中的執行將被移交給嵌套的 TaskSet ,嵌套的 TaskSet 將繼續運行,直到遇到由 TaskSet.interrupt()
方法拋出的 InterruptTaskSet 異常時終止。(而後在第一個任務集中繼續執行)。
client
引用根Locust
實例的client屬性。
interrupt(reschedule=True)
中斷TaskSet並將執行控制移交給父TaskSet。
若是reschedule
的值爲True,父 locust 將當即從新調度並執行下一個任務。
這個方法不該該由根 TaskSet(即當即附加到 Locust 類的 task_set 屬性)調用,而應該由層次結構中更深層次的嵌套 TaskSet 類調用。
locust= None
當TaskSet實例化後,會引用根Locust類實例。
parent= None
實例化TaskSet時,將引用父TaskSet或Locust類實例。對於嵌套TaskSet類頗有用。
schedule_task(task_callable, args=None, kwargs=None, first=False)
將任務添加到Locust的任務執行隊列中。
參數:
task_callable: 要調度的Locust任務計劃表
args: 將傳遞給可調用任務(task_callable)的參數
kwargs: 關鍵字字典參數,將傳遞給可調用(task_callable)的任務.
first: 可選關鍵字參數。若是爲 True,任務會被放到隊列的首位。
tasks= []
列表中包含表示 locust 用戶任務的可調用對象。
若是該參數值是一個列表,那麼將從中隨機挑選任務進行執行。
若是該參數值是一個元素爲二元組 (callable, int) 的列表或元素爲 callable: int 的字典,那麼將隨機選擇要執行的任務,可是每一個任務將根據其對應的 int 類型的值進行加權。因此在下面的例子中,ThreadPage 被選中的可能性是 write_post 的15倍:
1class ForumPage(TaskSet):
2 tasks = {ThreadPage:15, write_post:1}
wait_time()
該方法返回執行任務之間的時間(以秒爲單位)。
例如:
1from locust import TaskSet, between
2class Tasks(TaskSet):
3 wait_time = between(3, 25)
任務裝飾器 task decorator
task(weight=1)
使用一個便捷裝的飾器,以便可以爲類中的TaskSet內聯聲明任務。
1class ForumPage(TaskSet):
2 @task(100)
3 def read_thread(self):
4 pass
5
6 @task(7)
7 def create_thread(self):
8 pass
TaskSequence類(任務序列類)
classTaskSequence(parent)
定義 locust 用戶將要執行的任務序列。
當 TaskSequence 開始執行時,它將從 tasks 屬性值中根據任務的索引選擇一個任務進行執行,而後調用它的定義了一個睡眠時間的 wait_fucntion 方法。wait_function 定義的睡眠時間默認爲介於 min_wait 和 max_wait 之間且均勻分佈的一個隨機數,單位爲毫秒。而後再調用索引爲 index + 1 / % 的任務,以此類推。
TaskSequence 能夠與 TaskSet 嵌套,這意味着 TaskSequence 的 tasks 屬性能夠包含 TaskSet 實例和其餘TaskSequence 實例。若是計劃執行嵌套的 TaskSet,則將實例化它並從當前執行的 TaskSet 調用它。而後,當前運行的 TaskSet 中的執行將被移交給嵌套的 TaskSet ,這個嵌套的 TaskSet 將繼續運行,直到遇到由 TaskSet.interrupt()
拋出 InterruptTaskSet
異常時終止,而後在第一個 TaskSet 中繼續執行。
在這個類中,任務應該被定義成一個列表,或者簡單地由 @task_seq 裝飾器定義。
client
引用根 Locust 實例的client
屬性。
interrupt(reschedule=True)
中斷 TaskSet 並將執行控制權交給父 TaskSet。
若是 reschedule 的值爲 True,父 locust 將當即從新調度並執行下一個任務。
這個方法不該該由根 TaskSet (即當即附加到 Locust 類的 task_set 屬性)調用,而應該由層次結構中更深層次的嵌套 TaskSet 類調用。
schedule_task(task_callable, args=None, kwargs=None, first=False)
添加一個任務到Locust 的任務執行隊列。
參數:
task_callable:要調度的 locust 任務。
args:要傳遞給 task_callable 的參數。
kwargs:要傳遞給 task_callable 的關鍵字參數的字典。
first:可選關鍵字參數。若是爲 True,任務會被放到隊列的首位。
wait_time()
該方法返回執行任務之間的時間(以秒爲單位)。
例如:
1from locust import TaskSet, between
2class Tasks(TaskSet):
3 wait_time = between(3, 25)
seq_task裝飾器
seq_task(order)
用於在類中內聯聲明 TaskSequence 的任務。
例如:
1class NormalUser(TaskSequence):
2 @seq_task(1)
3 def login_first(self):
4 pass
5
6 @seq_task(2)
7 @task(25) # You can also set the weight in order to execute the task for `weight` times one after another.
8 def then_read_thread(self):
9 pass
10
11 @seq_task(3)
12 def then_logout(self):
13 pass
HttpSession 類
between(min_wait, max_wait)
返回一個函數,該函數將在min_wait和max_wait之間返回一個隨機數。
例如:
1class User(Locust):
2 # wait between 3.0 and 10.5 seconds after each task
3 wait_time = between(3.0, 10.5)
constant(wait_time)
返回一個函數,該函數只返回wait_time參數指定的數字。
例如:
1class User(Locust):
2 wait_time = constant(3)
constant_pacing(wait_time)
返回一個函數,該函數將跟蹤任務的運行時間,每次調用它時,它將返回一個等待時間,該等待時間將嘗試使任務執行之間的總時間等於wait_time參數指定的時間。
在如下示例中,不管任務執行時間如何,任務老是每秒執行一次:
1class User(Locust):
2 wait_time = constant_pacing(1)
3 class task_set(TaskSet):
4 @task
5 def my_task(self):
6 time.sleep(random.random())
若是任務執行超過了指定的wait_time,則在開始下一個任務以前的等待時間爲0。
HttpSession 類
**class HttpSession(base_url, *args, *kwargs)*
用於執行Web請求和在請求之間保留(會話)Cookie的類(以便可以登陸和註銷網站)。每一個請求都被記錄下來,以便Locust能夠顯示統計信息。
這是Python的 requests 庫的requests.Session
類的拓展,工做原理與是極其類似的。然而,發送請求的方法(get、post、delete、put、head、options、patch、request)如今能夠接受一個 url 參數,這個參數只是 URL的路徑部分,在這種狀況下,URL的主機部分將取 HttpSession.base_url (繼承自一個 Locust 類的 host 屬性)的值。
發送請求的每一個方法還接受兩個額外的可選參數,這些參數是特定於 Locust ,在Python的 requests 庫中不存在的:
參數:
name
可選參數。能夠指定爲 Locust 的統計信息中的標籤,用於代替 URL 路徑。這能夠用於將被請求的不一樣 URL 分組到 Locust 統計數據中的一個條目中。catch_response
可選參數。若是要設置,能夠是一個布爾值。能夠用來使請求返回爲做爲with 語句的參數的上下文管理器。這將容許根據響應內容將請求標記爲失敗,即便響應代碼是 ok (2xx) ,反之亦然。可使用 catch_response 捕捉請求,而後將其標記爲成功,即便響應代碼不是 ok (例如 500 或 404)。
__init__(base_url, \*args, \*\* kwargs)
x.init(…) 初始化x; see help(type(x)) for signature
delete(url, \*\*kwargs)
發送一個 DELETE 請求,返回一個 Response 對象。
參數:
url:新 Request 對象的URL。
**kwargs:request 的可選參數。
返回值類型:requests.Response 對象。
get(url, \*\*kwargs)
發送一個 GET 請求,返回一個 Response 對象。
參數:
url:新 Request 對象的URL。
**kwargs:request 的可選參數。
返回值類型:requests.Response 對象。
head(url, \*\*kwargs)
發送一個 HEAD 請求,返回一個 Response 對象。
參數:
url:新 Request 對象的URL。
**kwargs:request 的可選參數。
返回值類型:requests.Response 對象。
options(url, \*\*kwargs)
發送一個 OPTIONS 請求,返回一個 Response 對象。
參數:
url:新 Request 對象的URL。
**kwargs:request 的可選參數。
返回值類型:requests.Response 對象。
patch(url,data=None , \*\*kwargs)
發送一個 PATCH 請求,返回一個 Response 對象。
參數:
url:新 Request 對象的URL。
data:可選參數。發送到請求主體中的字典、bytes 或 file-like 對象。
**kwargs:request 的可選參數。
返回值類型:requests.Response 對象。
post(url,data=None , json=None, \*\*kwargs)
發送一個 POST 請求,返回一個 Response 對象。
參數:
url:新 Request 對象的URL。
data:可選參數。發送到請求主體中的字典、bytes 或 file-like 對象。
**kwargs:request 的可選參數。
json:可選參數。要發送到請求主體中的 json 格式數據。
返回值類型:requests.Response 對象。
put(url,data=None , \*\*kwargs)
發送一個 PUT 請求,返回一個 Response 對象。
參數:
url:新 Request 對象的URL。
data:可選參數。發送到請求主體中的字典、bytes 或 file-like 對象。
**kwargs:request 的可選參數。
返回值類型:requests.Response 對象。
request(method, url, name=None , catch_response=False, **kwargs)
構造併發送一個requests.Request
。返回 requests.Response
對象。
參數:
method:新 Request 對象的方法。
url:新 Request 對象的URL。
name:可選參數。
能夠指定爲 Locust 的統計信息中的標籤,用於代替 URL 路徑。這能夠用於將被請求的不一樣 URL 分組到 Locust 統計數據中的一個條目中。
catch_response可選參數。若是要設置,能夠是一個布爾值。能夠用來使請求返回爲做爲with 語句的參數的上下文管理器。這將容許根據響應內容將請求標記爲失敗,即便響應代碼是 ok (2xx) ,反之亦然。可使用 catch_response捕捉請求,而後將其標記爲成功,即便響應代碼不是 ok (例如 500 或 404)。
params:可選參數。要發送到Request
的查詢字符串的字典或 bytes 對象。
data:可選參數。要發送到 Request
主體中的字典或 bytes 對象。
headers:可選參數。與 Request
一塊兒發送的表示 HTTP headers 的字典。
cookies:可選參數。與 Request
一塊兒發送的表示 cookies 的 dict 或 CookieJar 對象。
files:可選參數。用於多部分編碼上傳的元素爲 filename: filename: file-like-objects
的字典。
auth:可選參數:用於啓用 Basic/Digest或自定義的 HTTP Auth 的元組或可調用對象。
timeout:可選參數。以浮點數或(鏈接超時、讀取超時)元組的形式等待服務器發送數據的時間(以秒爲單位)。
allow_redirects:可選參數。布爾類型。默認值爲 True。表示是否容許重定向。
proxies:可選參數。字典類型。鍵表示代理使用的協議,鍵值表示代理的URL。
stream:可選參數。是否當即下載響應內容。默認值爲 False
。
verify:可選參數。若是爲True
,則會驗證 SSL 證書。也能夠提供一個 CA_BUNDLE 路徑。
cert:可選參數。若是提供一個字符串。那麼應該是指向SSL 客戶端證書(.pem文件)的路徑;若是是一個元組,則應該是 (‘cert’, ‘key’)。
Response類
這個類實際上是位於python-requests庫中的,可是因爲 Locust在構造HTTP 請求的時候要用到這個類,而且在編寫 Locust負載測試時,這個類也很是重要,因此就把這個類包含在了 API 文檔裏。您還能夠查看請求文檔中的Response
類。
class ResponseResponse
對象,它包含服務器對HTTP請求的響應。
apparent_encoding
明顯的編碼,由chardet庫提供。
close()
用於釋放連接。一旦調用此方法,就不能再次訪問基礎raw
對象。注意:一般不該該顯式調用它。
content
響應的內容,以字節爲單位。
cookies= None
服務器發回的一堆cookie。
elapsed= None
發送請求到響應到達之間的時間間隔(使用 timedelta 對象表示)。此屬性專門度量從發送請求的第一個字節到完成對報頭的解析所花費的時間。所以,它不受響應內容或 stream
關鍵字參數值的影響。
encoding= None
訪問 r.text 時解碼操做要用到的編碼方式。
headers= None
不區分大小寫的響應頭字典。
例如,headers['content-encoding']
將會返回響應頭中鍵爲 Content-Encoding
的鍵值。
history= None
請求歷史記錄中的響應
對象列表。任何重定向響應都將在這裏結束。該列表從最先的請求到最近的請求進行排序。
is_permanent_redirect
若是此響應是重定向的永久版本之一,則返回 True,不然返回 False。
is_redirect
若是此響應是能夠自動處理的格式良好的HTTP重定向(經過 session.resolve_reredirect()
判斷),則返回True,不然返回 False。
iter_content(chunk_size=1, decode_unicode=False)
迭代響應數據。當對請求設置stream=True時,這能夠避免當即將內容讀入內存以得到較大的響應。數據塊大小是應該讀入內存的字節數。這不必定是解碼時返回的每一個項的長度。
chunk_size的類型必須是int或None。None的值將根據流的值發揮不一樣的功能。
stream=True將在到達數據塊時讀取數據,不管塊的大小如何。
若是stream=False,則以單個塊的形式返回數據。
若是decode_unicode爲True,那麼將使用基於響應的最佳可用編碼對內容進行解碼。
iter_lines(chunk_size=512, decode_unicode=False, delimiter=None)
迭代響應數據,一次一行。當對請求設置stream=True時,這能夠避免當即將內容讀入內存以得到較大的響應。注意
:這種方法是不安全的。
json(**kwargs)
返回響應的 json 編碼內容(若是有的話)。
**kwargs-- 表示要傳給jason.loads
函數的可選參數。
ValueError --若是響應的主體中不包含有效的 json 數據,則將引起 ValueError 異常。
links
返回已解析的響應頭連接(若是有的話)。
next
返回一個PreparedRequest 對象,用於表示重定向鏈中的下一個請求(若是有的話)。
ok
若是 status_code
小於400,返回 True;若是不小於400,返回 False。
此屬性檢查響應的狀態代碼是否在400到600之間,以查看是否存在客戶端錯誤或服務器錯誤。若是狀態碼在200到400之間,則返回 True ,而不是檢查響應代碼是否爲 200 OK
。
raise_for_status()
若是發生HTTPError,則引起存儲的HTTPError
。
reason= None
響應HTTP狀態的文本緣由.
例如:「Not Found」 或者 「OK」.
request= None
這是響應的PreparedRequest
對象。
status_code= None
響應的HTTP狀態的整數代碼。
例如404或200。
text
使用Unicode字符表示的響應的內容。
若是 Response.encoding 是 None,則使用 chardet
猜想編碼。
響應內容的編碼按照 RFC 2616 的規定,由 HTTP headers 惟一肯定。若是能夠利用非 HTTP 知識更好地猜想編碼,應該在訪問該特性以前爲r.encoding
設置合適的值。
url= None
響應的最終URL位置。
ResponseContextManager類
class ResponseContextManager(response)
能夠充當上下文管理器的 Response 類,提供手動控制HTTP 請求在在 Locost 的統計數據中應該標記爲成功仍是失敗的能力。
這個類是 Response
類的子類。包含兩個額外的方法:success
和 failure
。
failure(exc)
將響應報告爲失敗。
其中參數 exc 能夠是一個Python的異常類或者一個字符串。若是是一個字符串,那麼將使用這個字符串來實例化 CatchResponseError 類。
例如:
1with self.client.get("/", catch_response=True) as response:
2 if response.content == b"":
3 response.failure("No data")
success()
報告響應成功
例如:
1with self.client.get("/does/not/exist", catch_response=True) as response:
2 if response.status_code == 404:
3 response.success()
InterruptTaskSet異常
exception InterruptTaskSet(reschedule=True)
在 Locust 任務內拋出這個異常時,將會中斷這個 Locust 正在執行的當前任務。
事件鉤子
事件鉤子都是 locust.events.EventHook 類的實例。
class EventHook
簡單事件類,用於爲 locust 中不一樣類型的事件提供鉤子。
下面的代碼演示如何使用這個類:
1my_event = EventHook()
2def on_my_event(a, b, **kw):
3 print "Event was fired with arguments: %s, %s" % (a, b)
4my_event += on_my_event
5my_event.fire(a="foo", b="bar")
若是 reverse 的值爲 True,則處理程序將按照插入時的相反順序運行。
注意:
強烈建議你在事件監聽器中添加通配符關鍵字參數,以防止在之後的版本中添加新參數時代碼中斷。
可用的鉤子
下面的事件鉤子在 locust.events 模塊下可用:
request_success= <locust.events.EventHook object>
當一個請求成功完成時觸發。
監聽者應該使用以下參數:
request_type:使用的請求方法。
name:被調用的URL的路徑(若是在對客戶端的調用中使用了名稱,則重寫名稱)。
response_time:使用毫秒錶示的響應時間。
response_length:響應的 Content-Length 值。
request_failure= <locust.events.EventHook object>
當一個請求失敗時觸發。
事件觸發式將使用以下參數:
request_type:使用的請求方法。
name:被調用的URL的路徑(若是在對客戶端的調用中使用了名稱,則重寫名稱)。
response_time:用毫秒錶示的從發出請求到拋出異常時的時間間隔。
exception:拋出的異常的實例。
locust_error= <locust.events.EventHook object>
當 Locust 類的執行過程當中出現異常時觸發。
事件觸發式將使用以下參數:
locust_instance:異常發生時的 Locust 類的實例。
exception:拋出的異常。
tb:回溯對象(從 sys.exc_info()[2] 獲得)
report_to_master= <locust.events.EventHook object>
當 Locust 在 -slave 模式下運行時使用。用於將數據附加到按期發送給主服務器的數據字典上。當報告要發送到主服務器時,它會按期觸發。
注意:
Locust 使用的鍵 ‘stats’ 和 ‘errors’ 不該該被覆蓋。
事件觸發式將使用以下參數:
client_id:正在運行的 Locust 進程的客戶端 ID。
data:可修改的數據字典,以便附加應發送到主服務器的數據。
slave_report= <locust.events.EventHook object>
當 locust 在 -master 模式下運行使用。並在 Locust 主服務器從從屬服務器收到報告時觸發。
此事件可用於聚合來自 Locust 從屬服務器的數據。
事件觸發式將使用以下參數:
client_id:報告 Locust 從屬服務器的客戶端 ID。
data:來自從屬節點的數據字典。
hatch_complete= <locust.events.EventHook object>
當全部 locust 用戶都已經生成時觸發。
事件觸發式將使用以下參數:
user_count:孵化出的用戶數量。
quitting= <locust.events.EventHook object>
在退出 locust 進程時觸發。
第三方工具
支持其餘採樣器協議,報告等。
Locust 插件:https://github.com/SvenskaSpel/locust-plugins/
無需手動步驟便可自動執行分佈式運行
Locust集羣:https://github.com/SvenskaSpel/locust-swarm/(蝗蟲羣)
使用其餘語言
Locust主服務器和Locust從服務器經過交換msgpack消息進行通訊,這是許多語言所支持的。所以,您可使用任何喜歡的語言編寫Locust任務。爲了方便起見,一些庫充當了從屬運行程序。他們運行你的Locust任務,並按期向master報告。
Golang
Boomer:https://github.com/myzhan/boomer/
Java
Locust4j:https://github.com/myzhan/locust4j
Swarm: https://github.com/anhldbk/swarm
配置管理
部署Locust很容易,可是有些工具仍然能夠提供必定程度的便利。
tinx.locust是Ansible的一個安裝角色,用於配置和控制Locust系統服務,或使用ansible-container構建Locust docker映像。還管理locustfile和相應的測試數據。
文章合集
Selenium | Appium | Jenkins | Jmeter
軟件測試方法彙總 | Postman接口參數化 | 測試用例設計
免費福利 視頻教程
Selenium | Appium | Jenkins | Jmeter
往期性能推文:
03|性能綜述: 怎麼理解TPS、QPS、RT、吞吐量這些性能指標?
04|JMeter和LoadRunner:要知道工具僅僅只是工具
萬水千山老是情,點個「在看」 行不行!!?
本文分享自微信公衆號 - 軟測小生(ruancexiaosheng)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。