iT邦幫忙

2025 iThome 鐵人賽

DAY 3
1

在 Day02 的快速入門中,我們建立了一個基礎的 HttpUser 來對 API 進行測試。然而,要精準模擬真實世界的使用者行為,我們需要更深入地了解 Locust 的核心組件,包含 UserHttpUser 的差異、任務的權重設定 (@task(weight)), 以及使用者等待時間 (wait_time) 的不同策略。

今天,我們將深入探討這些概念,並學習如何同時模擬多種不同的使用者類型。

User vs. HttpUser

在 Locust 中,所有模擬使用者都繼承自 User 類別。User 是最基礎的抽象類別,而 HttpUser 則是它的一個特化版本。

  • User:
    這是最通用的使用者類別,它本身不具備任何特定的網路協定能力。當您需要測試非 HTTP 的系統時,例如 gRPC、WebSocket 或其他自訂 TCP/IP 協定,就應該繼承自 User 類別,並自行實現客戶端邏輯。

    基礎範例 (無任務):

    from locust import User, between
    
    class MyCustomUser(User):
        wait_time = between(1, 5)
    
  • HttpUser:
    這是最常用的使用者類別,專為測試 HTTP/HTTPS 服務(如網站、API)而設計。它繼承自 User,並內建了一個強大的 HTTP 客戶端 self.client (基於 requests)。透過這個客戶端,我們可以輕易地發送 GET, POST, PUT 等請求。

    基礎範例 (無任務):

    from locust import HttpUser, between
    
    class MyWebAppUser(HttpUser):
        wait_time = between(1, 5)
        host = "https://example.com"
    

任務權重 (Weight)

在真實情境中,使用者執行的不同操作頻率可能不同。例如,瀏覽商品的使用者數量遠大於下訂單的使用者。Locust 允許我們使用 @task 裝飾器的參數來設定任務的「權重」,以模擬這種行為。

一個任務的權重越高,它被選中執行的機率就越大。如果所有任務都沒有設定權重,則它們被選中的機率相等。

範例:
假設一個電商網站,使用者有 80% 的時間在瀏覽商品,20% 的時間在查看個人檔案。我們可以這樣設定:

from locust import HttpUser, task, between

class WebsiteUser(HttpUser):
    wait_time = between(1, 5)
    host = "http://localhost:8080"

    @task(4)  # 權重設為 4
    def view_products(self):
        print("I am viewing products.")

    @task(1)  # 權重設為 1
    def view_profile(self):
        print("I am viewing my profile.")

更改範例後記得要重啟終端機的 locust 並重整網頁

在這個例子中,view_products 任務被執行的機率是 view_profile 的 4 倍,這更貼近真實的使用者行為模式。在下面這張圖片可以看到印出 “I am viewing products.” 的機率要比 “I am viewing profile.” 的機率高出不少:

https://ithelp.ithome.com.tw/upload/images/20250820/20144024UdWWN8M8Pc.png

比較表格

特性 User HttpUser
基礎類別 是,所有使用者的基礎 否,繼承自 User
內建客戶端 是 (self.client),用於 HTTP/S
主要用途 測試非 HTTP 協定 (gRPC, WebSocket) 測試網站、API 等 HTTP/S 服務
範例場景 遊戲伺服器、訊息佇列 電商網站、RESTful API

深入 wait_time 屬性

wait_time 用於模擬使用者在執行下一個任務前的「思考時間」,這對於建立更真實的負載模式至關重要。Locust 提供了三種主要的等待策略:

  1. between(min, max):
    這是最常用的策略。它會讓模擬使用者在每次任務執行後,隨機等待 minmax 秒之間的一個時間。這能很好地模擬真實使用者行為的隨機性。

    • 範例: 使用者在瀏覽完一個頁面後,可能會花 1 到 5 秒的時間閱讀,然後才點擊下一個連結。
    from locust import HttpUser, task, between
    
    class WebsiteUser(HttpUser):
        wait_time = between(1, 5)
        host = "http://localhost:8080"
    
        @task(4)  # 權重設為 4
        def test_hello_world_endpoint(self):
            self.client.get("/hello-world")
    
  2. constant(wait_seconds):
    此策略讓模擬使用者在每次任務後,都等待一個固定的秒數。這在需要精確控制請求間隔的場景中很有用,但較不符合真實使用者的隨機行為。

    • 範例: 一個自動化腳本或機器人可能每 3 秒鐘就固定查詢一次系統狀態。
    from locust import HttpUser, task, constant
    
    class WebsiteUser(HttpUser):
        wait_time = constant(5)
        host = "http://localhost:8080"
    
        @task(4)  # 權重設為 4
        def test_hello_world_endpoint(self):
            self.client.get("/hello-world")
    
  3. constant_pacing(wait_seconds):
    這是一個更進階的策略,它能確保一個任務的執行週期(包含任務執行時間與等待時間)總和為一個固定的秒數。如果任務執行時間超過了設定的秒數,則等待時間為 0。這對於達成特定的吞吐量 (RPS, Requests Per Second) 非常有用。

    • 範例: 您需要確保每個使用者平均每 5 秒鐘就完成一次「下訂單」的流程,無論該流程中的 API 請求快或慢。
    from locust import HttpUser, task, constant_pacing
    
    class WebsiteUser(HttpUser):
        wait_time = constant_pacing(5)
        host = "http://localhost:8080"
    
        @task(4)  # 權重設為 4
        def test_hello_world_endpoint(self):
            self.client.get("/hello-world")
    

    可以看到在下圖中 “Total Requests per Second” 的地方,除了一開始剛進行測試之外,後續的平均請求次數就逐漸趨於穩定。

    https://ithelp.ithome.com.tw/upload/images/20250820/20144024WBrlwXLYPN.png

模擬多種使用者類型

在真實世界中,一個系統通常會有多種類型的使用者,例如:匿名訪客、普通會員、後台管理員。他們的行為模式和權限都不同。Locust 允許我們在同一個測試腳本中定義多個 User 類別來模擬這種複雜情境。

Locust 本身沒有 MultipleUserMultipleHttpUser 這樣的類別。要實現多使用者模擬,您只需要在 locustfile 中定義多個繼承自 UserHttpUser 的類別即可。

執行範例:
假設我們要同時模擬兩種使用者:一種是頻繁瀏覽網站的普通用戶 (WebAppUser),另一種是偶爾呼叫特定 API 的數據分析師 (DataAnalystUser)。

from locust import HttpUser, task, between

# 第一種使用者:網站訪客
class WebAppUser(HttpUser):
    wait_time = between(1, 3)
    host = "http://localhost:8080"

    # 權重為 2,表示這類使用者行為較頻繁
    weight = 2

    @task
    def homepage(self):
        print("WebAppUser: Visiting homepage")
        # self.client.get("/")

    @task
    def about_page(self):
        print("WebAppUser: Visiting about page")
        # self.client.get("/about")

# 第二種使用者:數據分析師
class DataAnalystUser(HttpUser):
    wait_time = between(5, 10)
    host = "http://localhost:8080"

    # 權重為 1,表示這類使用者較少
    weight = 1

    @task
    def get_analytics_data(self):
        print("DataAnalystUser: Fetching analytics data")
        # self.client.get("/api/v1/analytics")

當您使用 locust -f demo.py 啟動這個腳本時,Locust 的 Web UI 會讓您分別設定要模擬的 WebAppUserDataAnalystUser 的數量。Locust 會根據您設定的比例以及類別中定義的 weight 屬性來產生負載。

由於我們這裡這定了兩個 User,重啟 locust 後記得使用者的數量要至少設定兩個,才可以看得出效果!

https://ithelp.ithome.com.tw/upload/images/20250820/20144024mvM6G29JMF.png

按下 START 開始執行後,應該可以在終端機上看到如下圖中的效果,WebAppUserDataAnalystUser 交替著出現:

https://ithelp.ithome.com.tw/upload/images/20250820/20144024cM1mbIPfP2.png

透過這些進階功能,您可以更靈活、更真實地模擬複雜的使用者場景,從而更準確地評估您的系統效能。


今天我們深入了解了如何定義與客製化使用者行為。明天,我們將轉換視角,探討 Locust 的運作流程以及更多元的執行方法,敬請期待!


上一篇
Day02 - Locust & FastAPI 快速入門
下一篇
Day04 - Locust 的運作流程及執行方法
系列文
Vibe Coding 後的挑戰:Locust x Loki 負載及監控13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言