Locust學習總結

簡介

Locust是一個使用Python編寫的可擴展、分布式的開源性能測試工具。

優點

  • 相比于Jmeter、LoadRunner這種基于GUI的工具而言,Locust使用Python語言來描述測試場景使模擬用戶行為變得更加靈活和簡潔,除了Http(s)協議之外,Locust可以測試任意協議的系統,只需要實現Python調用對應協議的庫進行請求即可(類似HttpLocust類)。
  • Locust的并發機制采用協程的方式,相比于進程和線程減少了系統級資源調度,因此單機的產生的并發能力相比于LoadRunner、jmeter得到了大幅的提升。

安裝

pip install locust

Locust腳本編寫

import queue
from locust import HttpLocust, TaskSet, task
from locust.clients import HttpSession
from sign import ParserData


class UserBehavior(TaskSet):

    parser_data = ParserData()  # 解析接口傳參類
    _client = 20
    version = 119
    user_info = None

    @staticmethod
    def get_user_info(response):
        r = response.json().get('content')
        return {
            'market_id': r.get('marketId'),
            'token': r.get('token')
        }

    def on_start(self):
        try:
            user, password = self.locust.users.get_nowait()
        except queue.Empty:
            print('test data run out. test ended.')
            exit(0)
        client = HttpSession(base_url='http://login.xxxx.cn')
        data = self.parser_data(loginName=user,
                                password=password,
                                client=self._client,
                                version=self.version)
        response = client.post(url='/login', data=data)
        self.user_info = self.get_user_info(response)
        self.locust.users.put_nowait((user, password))

    @task(2)
    def index(self):
        url = '/index'
        data = self.parser_data(market_id=self.user_info['market_id'],
                                client=self._client,
                                version=self.version,
                                pnum='3')
        headers = {'Authorization': 'Barer:' + self.user_info['token'],
                   'Accept': 'application/vnd.hs-api.v1+json'}
        with self.client.post(url=url, data=data, headers=headers,
                              verify=False, catch_response=True) as response:
            if response.status_code == 200:
                response.success()
            else:
                response.failure('http error.')

    @task(1)
    def shop_car_list(self):
        url = '/shopCar/list'
        data = self.parser_data(market_id=self.user_info['market_id'],
                                ischaidan='1',
                                client=self._client,
                                version=self.version)
        headers = {'Authorization': 'Bearer:' + self.user_info['token'],
                   'Accept': 'application/vnd.hs-api.v1+json'}
        with self.client.post(name='ShopCar', url=url, data=data, headers=headers,
                              verify=False, catch_response=True) as response:
            if response.status_code != 200 or "失敗" in response.text:
                response.failure('response error.')
            else:
                response.success()


class Stay(TaskSet):

    index = 0

    def on_start(self):
        self.index += 1

    @task
    def get_error(self):
        response = self.client.get('/1', name='error', allow_redirects=False,
                                   verify=False, catch_response=True)
        if response.status_code == 200:
            response.success()
        else:
            response.failure('http error.')

    @task
    def logout(self):
        self.interrupt()


class User(TaskSet):

    tasks = {Stay: 1}

    @task(1)
    def user(self):
        self.client.get('/', verify=False)


class WebsiteUser(HttpLocust):
    task_set = UserBehavior
    host = 'https://xxxx.api.xxxx.cn'
    min_wait = 1000
    max_wait = 3000
    users = queue.Queue()
    users.put_nowait(('user1', '1232'))
    users.put_nowait(('user2', '1234'))
    users.put_nowait(('user3', '1321'))
    weight = 3
    stop_timeout = 20


class WebsiteU(HttpLocust):
    task_set = User
    host = 'https://www.baidu.com'
    min_wait = 0
    max_wait = 0
    weight = 1
    stop_timeout = 60

簡單解釋下:

  • UserBehavior和WebsiteUser兩個類實現測試場景使用3個用戶賬號,每個用戶會去先登錄,然后分別去查看首頁和進入購物車頁面
  • 首先導入了需要用到的類,HttpLocust類為Locust子類,模擬客戶端的請求類,Taskset類為任務集類,task為任務裝飾器。

Taskset

  • UserBehavior為Taskset子類,該類主要用來定義每個虛擬用戶的操作行為

  • Taskset子類中可以定義一個on_start方法在正式開始測試前只執行一次,相當與初始化操作(這里說的只執行一次是每個虛擬用戶都會去執行一次),比如獲取登錄token等操作。

  • teskset類中的每個任務都需要用@task(weight=1)裝飾器去裝飾為一個任務,weight為執行的權重,如果不裝飾,locust不會認為這是一個任務,UserBehavior類中@task(1)、@task(2)裝飾器表示3個用戶里面有2個用戶去模擬執行index方法,有1個用戶去執行shop_car_list方法

  • taskset類中self.client屬性請求操作時傳入catch_response參數,設置為True,可以標記響應結果為成功或失敗,即使響應是成功的,也可以標記為失敗,默認為Fasle

  • taskset類中self.client屬性請求操作時有一個name參數,當設置了name的值時,最后的請求結果展示中name字段會顯示這里定義的name值,相當與給這個方法起了一個別名.

  • taskset類中interrupt(reschedule=True)方法在頂層的taskset類(即被指定到Locust子類中的taskset)中不可用,reschedule為True時,從被嵌套的任務中出來立即執行新的任務,如果為False從被嵌套的任務中出來會等待min_time-max_time之間的隨機時間,然后再執行新的任務,這個方法主要用來跳出嵌套的任務集

HttpLocust

  • WebsiteUser為HttpLocust子類,該類是用來模擬用戶的類,定義了一些用戶信息,及請求方式

  • HttpLocust子類中task_set屬性用來指定模擬用戶執行的操作,即Taskset子類

  • HttpLocust子類中的host屬性為被測試系統的host,當命令行中沒有指定--host參數時,此屬性會生效

  • HttpLocust子類中的min_wait、max_weight為最大等待時間和最小等待時間,每個請求會從這兩個時間間隔中隨機取一個時間等待,相當用戶實際操作系統時每個動作的思考時間。若測試單個接口則對應的值都設置為0即可。如果Taskset類中定義了min_wait、max_weight則會覆蓋Locust子類中定義的值。單位ms,默認值1000ms

  • HttpLocust子類中的stop_timeout屬性為執行測試的時間,單位為s

  • HttpLocust子類中的weight為該類執行的權重,當有多個子類時生效,如WebsiteUser、WebsiteU兩個HttpLocust子類中weight值分別為3和1.

  • Locust默認單機單進程運行,此模式下并不能充分利用單機的多處理器,可使用分布式運行,即開啟一個master,n個slave(n為處理器個數),master負責啟動Locust的web服務和任務分發,不會產生壓力,slave主要負責產生壓力

運行模式:

no-web模式

no_web模式指在命令行中直接運行

locust -f load_test.py -c 1 -r 1 -n 1
  • -f 指定要運行的Locust性能測試文件
  • -c 指定模擬的并發用戶數
  • -r 指定每秒的啟動用戶數
  • -n 指定運行次數
  • -t 指定運行的時間,例如300s,1m,1h
    寫完腳本調試時可在該模式下運行

單機單進程運行

locust -f load_test.py

分布式運行

分布式運行,有單機多進程運行和多機多進程運行兩種

locust -f load_test.py --master       master模式下啟動locust
locust -f load_test.py --slave         啟動一個locust slave節點,單機多進程模式
locust -f load_test.py --slave --master-host=192.168.105.11    啟動一個locust slave節點,多機模式下 
no_web模式下運行
image.png
web模式
image.png
  • Number of users to simulate:需要模擬的虛擬用戶個數
  • Hatch rate (users spawned/second):啟動虛擬用戶的速率,每秒產生出多少個用戶數


    QQ圖片20171109190334.png
  • 顯示并發數、響應時間、異常率、每秒請求數等
  • reqs/sec(每秒請求數)為根據最近2s請求數據計算得到的數據,即瞬時值


    QQ圖片20171109190430.png
  • 顯示rps、響應時間、并發數在整個測試運行中的走勢圖


    QQ圖片20171109190455.png
  • 顯示測試過程中出現的所有失敗的請求

Exceptions顯示測試過程中出現的異常
Download Date提供測試結果csv文件的下載

測試數據:

  • locust子類中設置的數據是全局的,為list時,使用自增方式取數據,并發運行時會出現取到的數據重復的情況,如果對數據唯一性有要求,使用python的queue隊列的數據結構即可
  • taskset子類中設置的數據是局部的,即每一個虛擬用戶都會有一個屬于自己的這個變量

queue數據結構

隊列形式

q=queue.Queue(maxsize=3)       先進先出隊列
q.put(1)      向隊列中存數據
q.get()        向隊列中取數據
q.put_nowait()       相當于q.put(1, block=False),當q隊列滿了之后put會觸發queue.Full異常
q.get_nowait()       相當與q.get(block=False),當q隊列為空之后get會觸發queue.Empty異常
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容