性能測試工具Locust


一、寫在前面

官網: https://www.locust.io/

官方使用文檔: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的測試腳本中,所有業務測試場景都是在LocustTaskSet兩個類的繼承子類中進行描的。

那如何理解LocustTaskSet這兩個類呢?簡單地說,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

偽代碼中測試場景如何表達?

代碼主要包含兩個類:

  1. WebsiteUser繼承(HttpLocust,而HttpLocust繼承自Locust)
  2. 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實例)運行邏輯都會遵守如下規律:

  1. 先執行WebsiteTasks中的on_start(只執行一次),作為初始化;
  2. 從WebsiteTasks中隨機挑選(如果定義了任務間的權重關系,那么就按照權重關系隨機挑選)一個任務執行;
  3. 根據Locust類中min_wait和max_wait定義的間隔時間范圍(如果TaskSet類中也定義了min_wait或者max_wait,以TaskSet中的優先),在時間范圍中隨機取一個值,休眠等待;
  4. 重復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_webweb兩種形式。該種模式由於單進程的原因,並不能完全發揮壓力機所有處理器的能力,因此主要用於調試腳本和小並發壓測的情況。

當並發壓力要求較高時,就需要用到Locust的多進程分布式運行模式。從字面意思上看,大家可能第一反應就是多台壓力機同時運行,每台壓力機分擔負載一部分的壓力生成。的確,Locust支持任意多台壓力機(一主多從)的分布式運行模式,但這里說到的多進程分布式運行模式還有另外一種情況,就是在同一台壓力機上開啟多個slave的情況。這是因為當前階段大多數計算機的CPU都是多處理器(multiple processor cores),單進程運行模式下只能用到一個處理器的能力,而通過在一台壓力機上運行多個slave,就能調用多個處理器的能力了。比較好的做法是,如果一台壓力機有N個處理器內核,那么就在這台壓力機上啟動一個masterNslave。當然,我們也可以啟動N的倍數個slave,但是根據我的試驗數據,效果跟N個差不多,因此只需要啟動Nslave即可。 

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中,就不需要再指定端口了。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地址。

運行結果:

 

 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:是每秒鍾請求的個數。

 相比於LoadRunnerLocust的結果展示十分簡單,主要就四個指標:並發數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好的一點就是高並發,但是相對的不好的地方也有,就是需要另外的工具去監控服務器,而且需要去編寫代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2024 CODEPRJ.COM