Locust效能測試工具核心技術@task和@events

自動化程式碼美學發表於2021-06-02

Tasks和Events是Locust效能測試工具的核心技術,有了它們,Locust才能稱得上是一個效能工具。

Tasks

從上篇文章知道,locustfile裡面必須要有一個類,繼承User類,當效能測試開始後,會產生一個User類例項,這就是常說的模擬使用者。這些使用者會選擇task執行,休眠一會,再選擇新的task,不斷迭代。

task是Python中的可呼叫物件,它是一項任務,對於Web系統來說,可以是登入、查詢、下訂單、支付等等。

@task裝飾器

@task是定義task最簡單直接的方式,比如:

from locust import User, task, constant

class MyUser(User):
    wait_time = constant(1)

    @task
    def my_task(self):
        print("User instance (%r) executing my_task" % self)

@task有一個可選引數,用來設定task的選擇權重,比如:

from locust import User, task, between

class MyUser(User):
    wait_time = between(5, 15)

    @task(3)
    def task1(self):
        pass

    @task(6)
    def task2(self):
        pass

task2比task1被選擇的可能性大兩倍。

tasks屬性

除了@task裝飾器,還可以設定User類的tasks屬性來定義任務,比如:

from locust import User, constant

def my_task(user):
    pass

class MyUser(User):
    tasks = [my_task]
    wait_time = constant(1)

注意,my_task()函式有一個引數,它是User類的例項。

tasks可以是一個列表:

tasks = [my_task1, my_task2, my_task3]

Locust會使用Python中的random.choice()從裡面隨機選取。

tasks也可以是一個字典:

{my_task: 3, another_task: 1}

後面的int型鍵值代表的是被選擇權重,這個字典等價於列表:

[my_task, my_task, my_task, another_task]

@tag裝飾器

@tag用來打標記,在執行時選擇哪些task執行,哪些task不執行。比如:

class MyUser(User):
    wait_time = constant(1)

    @tag('tag1')
    @task
    def task1(self):
        pass

    @tag('tag1', 'tag2')
    @task
    def task2(self):
        pass

    @tag('tag3')
    @task
    def task3(self):
        pass

    @task
    def task4(self):
        pass
  • 如果使用--tags tag1,那麼只有task1和task2會被選擇。
  • 如果使用--tags tag2 tag3,那麼只有task2和task3會被選擇。
  • 如果使用--exclude-tags tag3,那麼只有task1、task2和task4會被選擇。

注意,exclude的優先順序更高,如果某個tag既包括又排除,那麼會被排除。

Events

@task定義了效能測試的執行動作,@events作為補充,定義了測試開始前和測試結束後的處理。

注意,每個模擬使用者開始和結束的處理是使用的User類的on_start()和on_stop()方法。

test_start和test_stop

測試開始前和測試結束後觸發。示例:

from locust import events

@events.test_start.add_listener
def on_test_start(environment, **kwargs):
    print("A new test is starting")

@events.test_stop.add_listener
def on_test_stop(environment, **kwargs):
    print("A new test is ending")

分散式執行時,它們只會在master節點生效。

init

init和test_start不同,它會在每個Locust程式開始時觸發,分散式執行時,每個節點(worker程式)都會生效。

from locust import events
from locust.runners import MasterRunner

@events.init.add_listener
def on_locust_init(environment, **kwargs):
    if isinstance(environment.runner, MasterRunner):
        print("I'm on master node")
    else:
        print("I'm on a worker or standalone node")

Events是一項hook技術,在學習Locust高階用法時再做進一步介紹。

Locust專案結構

官方建議如下:

common/

__init__.py

auth.py

config.py

locustfile.py或者locustfiles/

api.py

website.py

requirements.txt

FastHttpUser

從上篇文章可以知道,HttpUser類比User類更常用,它的client屬性是HttpSession類(requests.Session子類)的一個例項,可以使用requests發HTTP請求:

# 使用HttpUser
from locust import HttpUser,task,constant


class MyUser(User):
    wait_time = constant(1)
    
    @task
    def my_task1(self):
        with self.client.get("https://www.baidu.com/", catch_response=True) as res:
            if res.status_code == 200:
                print("成功")
            else:
                print("失敗")

但是requests效能是不太好的,如果要產生更高的壓力,建議使用FastHttpUser,效能可以提升5到6倍

# 使用FastHttpUser
from locust import task, constant
from locust.contrib.fasthttp import FastHttpUser


class MyUser(FastHttpUser):
    wait_time = constant(1)

    @task
    def my_task(self):
        with self.client.get("https://www.baidu.com/", catch_response=True) as response:
            if response.status_code == 200:
                print("成功")
            else:
                print("失敗")

由於它們的API不一樣,都有各自的適用場景,所以FastHttpUser不能完全替代HttpUser。

小結

本文嚴格來說是上篇文章《locustfile中的User類和HttpUser類》的下篇,介紹了核心技術Tasks和Events,並給出了官方推薦的專案結構,最後介紹了比HttpUser效能更好的FastHttpUser,如果想要更多的併發,可以考慮使用後者。經過這兩篇文章的學習,已經可以開始動手實踐使用Locust進行效能測試了。如果使用locust命令啟動後,無法開啟網頁,可以試試加上引數:locust --web-host="127.0.0.1"

參考資料:

https://zhuanlan.zhihu.com/p/118470760

https://docs.locust.io/en/stable/writing-a-locustfile.html#tasks

https://www.axihe.com/tools/locust/increase-performance.html

https://blog.csdn.net/u012002125/article/details/113363768

相關文章