一、寫在前面
官方使用文檔:https://docs.locust.io/en/latest/
大並發量測試時,建議在linux系統下進行。
二、Locust安裝
1.1、 ---> pip3 install locust
1.2 、 通過GitHub上克隆項目安裝(Python3推薦):https://github.com/locustio/locust ,然后執行 ...\locust> python setup.py install
2、安裝 pyzmq
If you intend to run Locust distributed across multiple processes/machines, we recommend you to also install pyzmq.
如果打算運行Locust 分布在多個進程/機器,需要安裝pyzmq.
通過pip命令安裝。 /> pip install pyzmq
3、安裝成功,CMD敲入命令驗證。 /> locust --help
Options: -h, --help show this help message and exit -H HOST, --host=HOST Host to load test in the following format: http://10.21.32.33
--web-host=WEB_HOST Host to bind the web interface to. Defaults to '' (all interfaces) -P PORT, --port=PORT, --web-port=PORT Port on which to run web host -f LOCUSTFILE, --locustfile=LOCUSTFILE Python module file to import, e.g. '../other.py'. Default: locustfile --master Set locust to run in distributed mode with this process as master --slave Set locust to run in distributed mode with this process as slave --master-host=MASTER_HOST Host or IP address of locust master for distributed load testing. Only used when running with --slave. Defaults to 127.0.0.1. --master-port=MASTER_PORT The port to connect to that is used by the locust master for distributed load testing. Only used when running with --slave. Defaults to 5557. Note that slaves will also connect to the master node on this port + 1. --master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --no-web Disable the web interface, and instead start running the test immediately. Requires -c and -r to be specified. -c NUM_CLIENTS, --clients=NUM_CLIENTS Number of concurrent clients. Only used together with --no-web -r HATCH_RATE, --hatch-rate=HATCH_RATE The rate per second in which clients are spawned. Only used together with --no-web -n NUM_REQUESTS, --num-request=NUM_REQUESTS Number of requests to perform. Only used together with --no-web -L LOGLEVEL, --loglevel=LOGLEVEL Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO. --logfile=LOGFILE Path to log file. If not set, log will go to stdout/stderr --print-stats Print stats in the console --only-summary Only print the summary stats -l, --list Show list of possible locust classes and exit --show-task-ratio print table of the locust classes' task execution
ratio --show-task-ratio-json print json data of the locust classes' task execution
ratio -V, --version show program's version number and exit
參數說明:
-h, --help 查看幫助 -H HOST, --host=HOST 指定被測試的主機,采用以格式:http://10.21.32.33
--web-host=WEB_HOST 指定運行 Locust Web 頁面的主機,默認為空 ''。 -P PORT, --port=PORT, --web-port=PORT 指定 --web-host 的端口,默認是8089 -f LOCUSTFILE, --locustfile=LOCUSTFILE 指定運行 Locust 性能測試文件,默認為: locustfile.py --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE 以CSV格式存儲當前請求測試數據。 --master Locust 分布式模式使用,當前節點為 master 節點。 --slave Locust 分布式模式使用,當前節點為 slave 節點。 --master-host=MASTER_HOST 分布式模式運行,設置 master 節點的主機或 IP 地址,只在與 --slave 節點一起運行時使用,默認為:127.0.0.1. --master-port=MASTER_PORT 分布式模式運行, 設置 master 節點的端口號,只在與 --slave 節點一起運行時使用,默認為:5557。注意,slave 節點也將連接到這個端口+1 上的 master 節點。 --master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --expect-slaves=EXPECT_SLAVES How many slaves master should expect to connect before starting the test (only when --no-web used). --no-web no-web 模式運行測試,需要 -c 和 -r 配合使用. -c NUM_CLIENTS, --clients=NUM_CLIENTS 指定並發用戶數,作用於 --no-web 模式。 -r HATCH_RATE, --hatch-rate=HATCH_RATE 指定每秒啟動的用戶數,作用於 --no-web 模式。 -t RUN_TIME, --run-time=RUN_TIME 設置運行時間, 例如: (300s, 20m, 3h, 1h30m). 作用於 --no-web 模式。 -L LOGLEVEL, --loglevel=LOGLEVEL 選擇 log 級別(DEBUG/INFO/WARNING/ERROR/CRITICAL). 默認是 INFO. --logfile=LOGFILE 日志文件路徑。如果沒有設置,日志將去 stdout/stderr --print-stats 在控制台中打印數據 --only-summary 只打印摘要統計 --no-reset-stats Do not reset statistics once hatching has been completed。 -l, --list 顯示測試類, 配置 -f 參數使用 --show-task-ratio 打印 locust 測試類的任務執行比例,配合 -f 參數使用. --show-task-ratio-json 以 json 格式打印 locust 測試類的任務執行比例,配合 -f 參數使用. -V, --version 查看當前 Locust 工具的版本.
4、Locust主要由下面的幾個庫構成:
1) gevent
gevent是一種基於協程的Python網絡庫,它用到Greenlet提供的,封裝了libevent事件循環的高層同步API。
2) flask
Python編寫的輕量級Web應用框架。
3) requests
Python Http庫
4) msgpack-python
MessagePack是一種快速、緊湊的二進制序列化格式,適用於類似JSON的數據格式。msgpack-python主要提供MessagePack數據序列化及反序列化的方法。
5) six
Python2和3兼容庫,用來封裝Python2和Python3之間的差異性
6) pyzmq
pyzmq是zeromq(一種通信隊列)的Python綁定,主要用來實現Locust的分布式模式運行
當我們在安裝 Locust 時,它會檢測我們當前的 Python 環境是否已經安裝了這些庫,如果沒有安裝,它會先把這些庫一一裝上。並且對這些庫版本有要求,有些是必須等於某版本,有些是大於某版本。我們也可以事先把這些庫全部按要求裝好,再安裝Locust時就會快上許多。
三、編寫接口壓測腳本文件locustfile.py
1 from locust import HttpLocust, TaskSet, task 2
3 class ScriptTasks(TaskSet): 4 def on_start(self): 5 self.client.post("/login", { 6 "username": "test", 7 "password": "123456"
8 }) 9
10 @task(2) 11 def index(self): 12 self.client.get("/") 13
14 @task(1) 15 def about(self): 16 self.client.get("/about/") 17
18 @task(1) 19 def demo(self): 20 payload={} 21 headers={} 22 self.client.post("/demo/",data=payload, headers=headers) 23
24 class WebsiteUser(HttpLocust): 25 task_set = ScriptTasks 26 host = "http://example.com"
27 min_wait = 1000
28 max_wait = 5000
腳本解讀:
1、創建ScriptTasks()類繼承TaskSet類: 用於定義測試業務。 2、創建index()、about()、demo()方法分別表示一個行為,訪問http://example.com。用@task() 裝飾該方法為一個任務。1、2表示一個Locust實例被挑選執行的權重,數值越大,執行頻率越高。在當前ScriptTasks()行為下的三個方法得執行比例為2:1:1 3、WebsiteUser()類: 用於定義模擬用戶。 4、task_set : 指向一個定義了的用戶行為類。 5、host: 指定被測試應用的URL的地址 6、min_wait : 用戶執行任務之間等待時間的下界,單位:毫秒。 7、max_wait : 用戶執行任務之間等待時間的上界,單位:毫秒。
腳本使用場景解讀:
在這個示例中,定義了針對http://example.com
網站的測試場景:先模擬用戶登錄系統,然后隨機地訪問首頁(/
)和關於頁面(/about/
),請求比例為2:1,
demo方法主要用來闡述client對post接口的處理方式;並且,在測試過程中,兩次請求的間隔時間為1->
5
秒間的隨機值。
從腳本中可以看出,腳本主要包含兩個類,一個是WebsiteUser
(繼承自HttpLocust
,而HttpLocust
繼承自Locust
),另一個是ScriptTasks
(繼承自TaskSet
)。事實上,在Locust
的測試腳本中,所有業務測試場景都是在Locust
和TaskSet
兩個類的繼承子類中進行描的。
那如何理解Locust
和TaskSet
這兩個類呢?簡單地說,Locust類
就好比是一群蝗蟲,而每一只蝗蟲就是一個類的實例。相應的,TaskSet類
就好比是蝗蟲的大腦,控制着蝗蟲的具體行為,即實際業務場景測試對應的任務集。
四、Locust類
實例腳本
偽代碼:
from locust import HttpLocust, TaskSet, task class WebsiteTasks(TaskSet): def on_start(self): #進行初始化的工作,每個Locust用戶開始做的第一件事 payload = { "username": "test_user", "password": "123456", } header = { "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", } self.client.post("/login",data=payload,headers=header)#self.client屬性使用Python request庫的所有方法,調用和使用方法和requests完全一致; @task(5) #通過@task()裝飾的方法為一個事務,方法的參數用於指定該行為的執行權重,參數越大每次被虛擬用戶執行的概率越高,默認為1 def index(self): self.client.get("/") @task(1) def about(self): self.client.get("/about/") class WebsiteUser(HttpLocust): host = "https://github.com/" #被測系統的host,在終端中啟動locust時沒有指定--host參數時才會用到 task_set = WebsiteTasks #TaskSet類,該類定義用戶任務信息,必填。這里就是:WebsiteTasks類名,因為該類繼承TaskSet; min_wait = 5000 #每個用戶執行兩個任務間隔時間的上下限(毫秒),具體數值在上下限中隨機取值,若不指定默認間隔時間固定為1秒 max_wait = 15000
偽代碼中對https://github.com/網站的測試場景,先模擬用戶登錄系統,然后隨機訪問首頁/和/about/,請求比例5:1,並且在測試過程中,兩次請求的間隔時間1-5秒的隨機值;
on_start方法,在正式執行測試前執行一次,主要用於完成一些初始化的工作,例如登錄操作;
WebsiteTasks類中如何去調用 WebsiteUser(HttpLocust)類中定義的字段和方法呢?
通過在WebsiteTasks類中self.locust.xxoo xxoo就是我們在WebsiteUser類中定義的字段或方法;
偽代碼:
from locust import HttpLocust, TaskSet, task import hashlib import queue class WebsiteTasks(TaskSet): @task(5) def index(self): data = self.locust.user_data_queue #獲取WebsiteUser里面定義的ser_data_queue隊列 md5_data=self.locust.md5_encryption() #獲取WebsiteUser里面定義的md5_encryption()方法 self.client.get("/") class WebsiteUser(HttpLocust): host = "https://github.com/" task_set = WebsiteTasks min_wait = 5000 max_wait = 15000 user_data_queue = queue.Queue() def md5_encryption(self,star): '''md5加密方法''' obj = hashlib.md5() obj.update(bytes(star,encoding="utf-8")) result = obj.hexdigest() return result
偽代碼中測試場景如何表達?
代碼主要包含兩個類:
- WebsiteUser繼承(HttpLocust,而HttpLocust繼承自Locust)
- WebsiteTasks繼承(TaskSet)
在Locust測試腳本中,所有業務測試場景都是在Locust和TaskSet兩個類的繼承子類中進行描述;
簡單說:Locust類就類似一群蝗蟲,而每只蝗蟲就是一個類的實例。TaskSet類就類似蝗蟲的大腦,控制蝗蟲的具體行為,即實際業務場景測試對應的任務集;
源碼中:class Locust(object)和class HttpLocust(Locust)
1 class Locust(object): 2 """ 3 Represents a "user" which is to be hatched and attack the system that is to be load tested. 4 5 The behaviour of this user is defined by the task_set attribute, which should point to a 6 :py:class:`TaskSet <locust.core.TaskSet>` class. 7 8 This class should usually be subclassed by a class that defines some kind of client. For 9 example when load testing an HTTP system, you probably want to use the 10 :py:class:`HttpLocust <locust.core.HttpLocust>` class. 11 """ 12 13 host = None 14 """Base hostname to swarm. i.e: http://127.0.0.1:1234""" 15 16 min_wait = 1000 17 """Minimum waiting time between the execution of locust tasks""" 18 19 max_wait = 1000 20 """Maximum waiting time between the execution of locust tasks""" 21 22 task_set = None 23 """TaskSet class that defines the execution behaviour of this locust""" 24 25 stop_timeout = None 26 """Number of seconds after which the Locust will die. If None it won't timeout.""" 27 28 weight = 10 29 """Probability of locust being chosen. The higher the weight, the greater is the chance of it being chosen.""" 30 31 client = NoClientWarningRaiser() 32 _catch_exceptions = True 33 34 def __init__(self): 35 super(Locust, self).__init__() 36 37 def run(self): 38 try: 39 self.task_set(self).run() 40 except StopLocust: 41 pass 42 except (RescheduleTask, RescheduleTaskImmediately) as e: 43 44 class HttpLocust(Locust): 45 """ 46 Represents an HTTP "user" which is to be hatched and attack the system that is to be load tested. 47 48 The behaviour of this user is defined by the task_set attribute, which should point to a 49 :py:class:`TaskSet <locust.core.TaskSet>` class. 50 51 This class creates a *client* attribute on instantiation which is an HTTP client with support 52 for keeping a user session between requests. 53 """ 54 55 client = None 56 """ 57 Instance of HttpSession that is created upon instantiation of Locust. 58 The client support cookies, and therefore keeps the session between HTTP requests. 59 """ 60 def __init__(self): 61 super(HttpLocust, self).__init__() 62 if self.host is None: 63 raise LocustError("You must specify the base host. Either in the host attribute in the Locust class, or on the command line using the --host option.") 64 self.client = HttpSession(base_url=self.host)
在Locust類中,靜態字段client即客戶端的請求方法,這里的client字段沒有綁定客戶端請求方法,因此在使用Locust時,需要先繼承Locust類class HttpLocust(Locust),然后在self.client =HttpSession(base_url=self.host)綁定客戶端請求方法;
對於常見的HTTP(s)協議,Locust已經實現了HttpLocust類,其self.client=HttpSession(base_url=self.host),而HttpSession繼承自requests.Session。因此在測試HTTP(s)的Locust腳本中,可以通過client屬性來使用Python requests庫的所 有方法,調用方式與 reqeusts完全一致。另外,由於requests.Session的使用,client的方法調用之間就自動具有了狀態記憶功能。常見的場景就是,在登錄系統后可以維持登錄狀態的Session,從而后續HTTP請求操作都能帶上登錄狀態;
Locust類中,除了client屬性,還有幾個屬性需要關注:
- task_set ---> 指向一個TaskSet類,TaskSet類定義了用戶的任務信息,該靜態字段為必填;
- max_wait/min_wait ---> 每個用戶執行兩個任務間隔的上下限(毫秒),具體數值在上下限中隨機取值,若不指定則默認間隔時間為1秒;
- host --->被測試系統的host,當在終端中啟動locust時沒有指定--host參數時才會用到;
- weight--->同時運行多個Locust類時,用於控制不同類型的任務執行權重;
Locust流程,測試開始后,每個虛擬用戶(Locust實例)運行邏輯都會遵守如下規律:
- 先執行WebsiteTasks中的on_start(只執行一次),作為初始化;
- 從WebsiteTasks中隨機挑選(如果定義了任務間的權重關系,那么就按照權重關系隨機挑選)一個任務執行;
- 根據Locust類中min_wait和max_wait定義的間隔時間范圍(如果TaskSet類中也定義了min_wait或者max_wait,以TaskSet中的優先),在時間范圍中隨機取一個值,休眠等待;
- 重復2~3步驟,直到測試任務終止;
class TaskSet
TaskSet類實現了虛擬用戶所執行任務的調度算法,包括規划任務執行順序(schedule_task)、挑選下一個任務(execute_next_task)、執行任務(execute_task)、休眠等待(wait)、中斷控制(interrupt)等待。在此基礎上,就可以在TaskSet子類中采用非常簡潔的方式來描述虛擬用戶的業務測試場景,對虛擬用戶的所有行為進行組織和描述,並可以對不同任務的權重進行配置。
@task
通過@task()裝飾的方法為一個事務。方法的參數用於指定該行為的執行權重。參數越大每次被虛擬用戶執行的概率越高。如果不設置默認為1。
TaskSet子類中定義任務信息時,采取兩種方式:@task裝飾器和tasks屬性。
采用@task裝飾器定義任務信息時:
from locust import TaskSet, task class UserBehavior(TaskSet): @task(1) def test_job1(self): self.client.get('/test1') @task(3) def test_job2(self): self.client.get('/test2')
采用tasks屬性定義任務信息時
from locust import TaskSet def test_job1(obj): obj.client.get('/test1') def test_job2(obj): obj.client.get('/test2') class UserBehavior(TaskSet): tasks = {test_job1:1, test_job2:3} # tasks = [(test_job1,1), (test_job1,3)] # 兩種方式等價
上面兩種定義任務信息方式中,均設置了權重屬性,即執行test_job2的頻率是test_job1的兩倍。
若不指定,默認比例為1:1。
高級用法:
關聯
在某些請求中,需要攜帶之前response中提取的參數,常見場景就是session_id。Python中可用通過re正則匹配,對於返回的html頁面,可用采用lxml庫來定位獲取需要的參數;
from locust import HttpLocust, TaskSet, task from lxml import etree class WebsiteTasks(TaskSet): def get_session(self,html): #關聯例子 tages = etree.HTML(html) return tages.xpath("//div[@class='btnbox']/input[@name='session']/@value")[0] def on_start(self): html = self.client.get('/index') session = self.get_session(html.text) payload = { "username": "test_user", "password": "123456", 'session' : session } header = { "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", } self.client.post("/login",data=payload,headers=header) @task(5) def index(self): self.client.get("/") assert response['ErrorCode']==0 #斷言 @task(1) def about(self): self.client.get("/about/") class WebsiteUser(HttpLocust): host = "https://github.com/" task_set = WebsiteTasks min_wait = 5000 max_wait = 15000
參數化
作用:循環取數據,數據可重復使用
例如:模擬3個用戶並發請求網頁,共有100個URL地址,每個虛擬用戶都會依次循環加載100個URL地址
from locust import TaskSet, task, HttpLocust class UserBehavior(TaskSet): def on_start(self): self.index = 0 @task def test_visit(self): url = self.locust.share_data[self.index] print('visit url: %s' % url) self.index = (self.index + 1) % len(self.locust.share_data) self.client.get(url) class WebsiteUser(HttpLocust): host = 'http://debugtalk.com' task_set = UserBehavior share_data = ['url1', 'url2', 'url3', 'url4', 'url5'] min_wait = 1000 max_wait = 3000
保證並發測試數據唯一性,不循環取數據;
所有並發虛擬用戶共享同一份測試數據,並且保證虛擬用戶使用的數據不重復;
例如:模擬3用戶並發注冊賬號,共有9個賬號,要求注冊賬號不重復,注冊完畢后結束測試:
采用隊列
from locust import TaskSet, task, HttpLocust import queue class UserBehavior(TaskSet): @task def test_register(self): try: data = self.locust.user_data_queue.get() except queue.Empty: print('account data run out, test ended.') exit(0) print('register with user: {}, pwd: {}'\ .format(data['username'], data['password'])) payload = { 'username': data['username'], 'password': data['password'] } self.client.post('/register', data=payload) class WebsiteUser(HttpLocust): host = 'http://debugtalk.com' task_set = UserBehavior user_data_queue = queue.Queue() for index in range(100): data = { "username": "test%04d" % index, "password": "pwd%04d" % index, "email": "test%04d@debugtalk.test" % index, "phone": "186%08d" % index, } user_data_queue.put_nowait(data) min_wait = 1000 max_wait = 3000
保證並發測試數據唯一性,循環取數據;
所有並發虛擬用戶共享同一份測試數據,保證並發虛擬用戶使用的數據不重復,並且數據可循環重復使用;
例如:模擬3個用戶並發登錄賬號,總共有9個賬號,要求並發登錄賬號不相同,但數據可循環使用;
from locust import TaskSet, task, HttpLocust import queue class UserBehavior(TaskSet): @task def test_register(self): try: data = self.locust.user_data_queue.get() except queue.Empty: print('account data run out, test ended') exit(0) print('register with user: {0}, pwd: {1}' .format(data['username'], data['password'])) payload = { 'username': data['username'], 'password': data['password'] } self.client.post('/register', data=payload) self.locust.user_data_queue.put_nowait(data) class WebsiteUser(HttpLocust): host = 'http://debugtalk.com' task_set = UserBehavior user_data_queue = queue.Queue() for index in range(100): data = { "username": "test%04d" % index, "password": "pwd%04d" % index, "email": "test%04d@debugtalk.test" % index, "phone": "186%08d" % index, } user_data_queue.put_nowait(data) min_wait = 1000 max_wait = 3000
斷言(即檢查點)
性能測試也需要設置斷言么? 某些情況下是需要,比如你在請求一個頁面時,就可以通過狀態來判斷返回的 HTTP 狀態碼是不是 200。
通過with self.client.get("url地址",catch_response=True) as response的形式;
response.status_code獲取http響應碼進行判斷,失敗后會加到統計錯誤表中;
python自帶的斷言assert失敗后代碼就不會向下走,且失敗后不會被Locust報表統計進去;
默認不寫參數catch_response=False斷言無效,將catch_response=True才生效;
下面例子中:
首先使用python斷言對接口返回值進行判斷(python斷言不通過,代碼就不向下執行,get請求數為0),通過后對該接口的http響應是否為200進行判斷;
@task def all_interface(self): #豆瓣圖書api為例子 with self.client.get("https://api.douban.com/v2/book/1220562",name="/LhcActivity/GetActConfig",catch_response=True) as response: assert response.json()['rating']['max']==10 #python斷言對接口返回值中的max字段進行斷言 if response.status_code ==200: #對http響應碼是否200進行判斷 response.success() else: response.failure("GetActConfig[Failed!]")
五、Locust運行模式
運行Locust
時,通常會使用到兩種運行模式:單進程運行和多進程分布式運行。
單進程運行模式
Locust
所有的虛擬並發用戶均運行在單個Python
進程中,具體從使用形式上,又分為no_web
和web
兩種形式。該種模式由於單進程的原因,並不能完全發揮壓力機所有處理器的能力,因此主要用於調試腳本和小並發壓測的情況。
當並發壓力要求較高時,就需要用到Locust
的多進程分布式運行模式。從字面意思上看,大家可能第一反應就是多台壓力機同時運行,每台壓力機分擔負載一部分的壓力生成。的確,Locust
支持任意多台壓力機(一主多從)的分布式運行模式,但這里說到的多進程分布式運行模式還有另外一種情況,就是在同一台壓力機上開啟多個slave
的情況。這是因為當前階段大多數計算機的CPU都是多處理器(multiple processor cores
),單進程運行模式下只能用到一個處理器的能力,而通過在一台壓力機上運行多個slave
,就能調用多個處理器的能力了。比較好的做法是,如果一台壓力機有N
個處理器內核,那么就在這台壓力機上啟動一個master
,N
個slave
。當然,我們也可以啟動N
的倍數個slave
,但是根據我的試驗數據,效果跟N
個差不多,因此只需要啟動N
個slave
即可。
no_web形式啟動locust:
如果采用no_web
形式,則需使用--no-web
參數,並會用到如下幾個參數。
-c, --clients
:指定並發用戶數;-n, --num-request
:指定總執行測試次數;-r, --hatch-rate
:指定並發加壓速率,默認值位1。
示例:
$ locust -f locustfile.py --host = xxxxx.com --no-web -c 1 -n 2
在此基礎上,當我們想要調試Locust
腳本時,就可以在腳本中需要調試的地方通過print
打印日志,然后將並發數和總執行次數都指定為1
$ locust -f locustfile.py --host = xxxxx.com --no-web -c 1 -n 1
執行測試
通過這種方式,我們就能很方便地對Locust
腳本進行調試了。
Locust
腳本調試通過后,就算是完成了所有准備工作,可以開始進行壓力測試了。
web形式啟動locust:
如果采用web
形式,,則通常情況下無需指定其它額外參數,Locust
默認采用8089
端口啟動web
;如果要使用其它端口,就可以使用如下參數進行指定。
-P, --port
:指定web端口,默認為8089
.- 終端中--->進入到代碼目錄: locust -f locustfile.py --host = xxxxx.com
- -f 指定性能測試腳本文件
- -host 被測試應用的URL地址【如果不填寫,讀取繼承(HttpLocust)類中定義的host】
- 如果
Locust
運行在本機,在瀏覽器中訪問http://localhost:8089
即可進入Locust
的Web管理頁面;如果Locust
運行在其它機器上,那么在瀏覽器中訪問http://locust_machine_ip:8089
即可。
多進程分布式運行
不管是單機多進程
,還是多機負載
模式,運行方式都是一樣的,都是先運行一個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
中,就不需要再指定端口了。masterslave
才能執行測試任務。
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>
master
和slave
都啟動完畢后,就可以在瀏覽器中通過http://locust_machine_ip:8089
進入Locust
的Web管理頁面了。使用方式跟單進程web
形式完全相同,只是此時是通過多進程負載來生成並發壓力,在web
管理界面中也能看到實際的slave
數量。如果slave
與master
不在同一台機器上,還需要通過--master-host
參數再指定master
的IP地址。
運行結果:
Number of users to simulate 設置虛擬用戶數,對應中no_web
模式的-c, --clients
參數;
Hatch rate(users spawned/second)每秒產生(啟動)的虛擬用戶數 , 對應着no_web
模式的-r, --hatch-rate
參數,默認為1。點擊Start swarming 按鈕,開始運行性能測試。
上圖:啟動了一個 master 和兩個 slave,由兩個 slave 來向被測試系統發送請求
性能測試參數
-
Type: 請求的類型,例如GET/POST。
-
Name:請求的路徑。這里為百度首頁,即:https://www.baidu.com/
-
request:當前請求的數量。
-
fails:當前請求失敗的數量。
-
Median:中間值,單位毫秒,一半的服務器響應時間低於該值,而另一半高於該值。
-
Average:平均值,單位毫秒,所有請求的平均響應時間。
-
Min:請求的最小服務器響應時間,單位毫秒。
-
Max:請求的最大服務器響應時間,單位毫秒。
-
Content Size:單個請求的大小,單位字節。
-
reqs/sec:是每秒鍾請求的個數。
相比於LoadRunner
,Locust
的結果展示十分簡單,主要就四個指標:並發數
、RPS
、響應時間
、異常率
。但對於大多數場景來說,這幾個指標已經足夠了。
在上圖中,RPS
和平均響應時間
這兩個指標顯示的值都是根據最近2秒請求響應數據計算得到的統計值,我們也可以理解為瞬時值。
如果想看性能指標數據的走勢,就可以在Charts
欄查看。在這里,可以查看到RPS
和平均響應時間
在整個運行過程中的波動情況。
除了以上數據,Locust
還提供了整個運行過程數據的百分比統計值,例如我們常用的90%響應時間
、響應時間中位值;平均響應時間和錯誤數的統計
,該數據可以通過Download response time distribution CSV和Download request statistics CSV
獲得,數據展示效果如下所示。
-----------------------------------------------------------
注意:
locust雖然使用方便,但是加壓性能和響應時間上面還是有差距的,如果項目有非常大的並發加壓請求,可以選擇wrk
對比方法與結果:
可以准備兩台服務器,服務器A作為施壓方,服務器B作為承壓方
服務器B上簡單的運行一個nginx服務就行了
服務器A上可以安裝一些常用的壓測工具,比如locust、ab、wrk
我當時測下來,施壓能力上 wrk > golang >> ab > locust
因為locust一個進程只使用一核CPU,所以用locust壓測時,必須使用主從分布式(zeromq通訊)模式,並根據服務器CPU核數來起slave節點數
wrk約為55K QPS
golang net/http 約 45K QPS
ab 大約 15K QPS
locust 最差,而且response time明顯比較長
-------------------------------------------------------------------
好文推薦:
1、https://debugtalk.com/post/locustplus-talk-about-performance-test/
這篇博客從性能測試方法、性能瓶頸定位、性能測試工具的基本組成、性能測試工具推薦(比較了loadrunner,jmeter,Locust優缺點)等方面做了深入的介紹,推薦!
蝗蟲比Jmeter好的一點就是高並發,但是相對的不好的地方也有,就是需要另外的工具去監控服務器,而且需要去編寫代碼。