性能測試工具Locust的使用

1、寫在前面html

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

官方使用文檔:https://docs.locust.io/en/latest/python

大併發量測試時,建議在linux系統下進行。linux

 

2、Locust安裝nginx

1.一、   --->  pip3 install locust 
git

1.2 、 經過GitHub上克隆項目安裝(Python3推薦):https://github.com/locustio/locust  ,而後執行     ...\locust> python setup.py install
github

 二、安裝 pyzmqgolang

 If you intend to run Locust distributed across multiple processes/machines, we recommend you to also install pyzmq.web

 若是打算運行Locust 分佈在多個進程/機器,須要安裝pyzmq.算法

 經過pip命令安裝。 />  pip install pyzmq

三、安裝成功,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 工具的版本.

 

四、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時就會快上許多。

 

3、編寫接口壓測腳本文件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類:  用於定義測試業務。

二、建立index()、about()、demo()方法分別表示一個行爲,訪問http://example.com。用@task() 裝飾該方法爲一個任務。一、2表示一個Locust實例被挑選執行的權重,數值越大,執行頻率越高。在當前ScriptTasks()行爲下的三個方法得執行比例爲2:1:1

3、WebsiteUser()類: 用於定義模擬用戶。

4、task_set :  指向一個定義了的用戶行爲類。

5、host:   指定被測試應用的URL的地址

6、min_wait :   用戶執行任務之間等待時間的下界,單位:毫秒。

七、max_wait :   用戶執行任務之間等待時間的上界,單位:毫秒。

腳本使用場景解讀

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

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

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

 

4、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!]")

 

5、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明顯比較長

-------------------------------------------------------------------

好文推薦:

一、https://debugtalk.com/post/locustplus-talk-about-performance-test/

這篇博客從性能測試方法、性能瓶頸定位、性能測試工具的基本組成、性能測試工具推薦(比較了loadrunner,jmeter,Locust優缺點)等方面作了深刻的介紹,推薦!

蝗蟲比Jmeter好的一點就是高併發,可是相對的很差的地方也有,就是須要另外的工具去監控服務器,並且須要去編寫代碼。

相關文章
相關標籤/搜索