[Testing] 壓力測試 load testing - locust

    簡單紀錄一個壓力測試工具 - Locust,Locust 是一個開源的壓力測試工具,用於模擬大規模並發用戶請求來測試 Web 應用和 API 的性能。它使用 Python 腳本定義測試行為,支持分佈式測試,並提供簡潔的 Web 界面來監控測試結果,適合進行靈活且可擴展的性能測試。

Locust 特點:
1. 使用簡單:基於 Python 腳本,靈活且易於編寫自定義測試場景。
2. 實時監控:提供友好的 Web UI,實時查看測試結果和性能數據。
3. 可擴展性強:支持分佈式測試,能夠模擬大量並發用戶。

情境:
1 . 目的為搶票。
2 . 組合兩個API測試,一個是取票(book_event),一個是取得當前票數名額資料(search_event)。
3 . 提供一組使用者資料,做為壓力測試資料。
4 . 每次隨機取一個使用者發起請求。


提前補充:
1. Locust有很多進階的應用,目前只記錄最基本的功能。

Step1: 先安裝locust

pip install locust


Step2: 建立程式碼(新增一個 
locustfile.py)

import json 
import random
from locust import HttpUser, task, between

# 載入 JSON 文件中的數據
with open('users.json') as f:
    users_data = json.load(f)

# BookingUser(HttpUser) 表示一個用戶類別,繼承自 HttpUser
class BookingUser(HttpUser):
    # 設置 Host 為本地的 API 地址
    host = "http://test"

    # 等待時間,模擬真實用戶的行為
    # between(0.5, 1) 表示每次任務之間的等待時間在 0.5 到 1 秒之間
    wait_time = between(0.5, 1)

    # 使用 JSON 數據進行活動預約
    # @task是一個裝飾器,只要有加上@task的函數即註冊為任務,Locust就會執行這個函數,會在用戶模擬時執行
    # @task(1) 表示這個函數的權重為 1,當有多個函數時,Locust會根據權重來決定執行的順序。 @task(1) > @task(2)...
    @task(1)
    def book_event(self):
        # 從 users_data 中隨機選擇一個用戶
        user_data = random.choice(users_data)

        # 手動設置 Cookies
        headers = {}

        # 發送活動預約請求到指定的 URL
        response = self.client.post("/SignUpBykey", json={
            "user_id": user_data["user_id"],
            "uid": user_data["uid"]
        },headers=headers,verify=False)

        # 打印結果
        if response.status_code == 200:
            print(f"User {user_data['user_id']} successfully booked with UID {user_data['uid']}")
        else:
            print(f"Failed to book with UID {user_data['uid']} for user {user_data['user_id']}")

    @task(2)
    def search_event(self):
        # 從 users_data 中隨機選擇一個用戶
        user_data = random.choice(users_data)

        # 手動設置 Cookies
        headers = {}

        response = self.client.post("/GetAppointmentInfo", json={
            "user_id": user_data["user_id"],
        },headers=headers,verify=False)

        # 打印結果
        if response.status_code == 200:
            print(f"User {user_data['user_id']} successfully booked with UID {user_data['uid']}")
        else:
            print(f"Failed to book with UID {user_data['uid']} for user {user_data['user_id']}")   

    # 每次用戶實例化時載入 JSON 數據
    def on_start(self):
        self.user_data = users_data.copy()


Step3: 準備好測試資料 users.json
user.json 放入跟 locustfile.py 同層即可。


Step4: 啟動及參數介紹

locust -f locustfile.py
預設WebUI網址為:  http://0.0.0.0:8089

● 介面參數介紹:
Number of  users: 總共有100個人請求。
Spawn rate: 大約30秒後,將達到每秒100人同時請求。



Step5: 分析數據

● 欄位分析:
 1. Name:這一列顯示的是測試的請求路徑。

 2. # Requests:這是總請求數量。
 你總共發送了 3,078 次請求到這個 API。

 3. # Fails:這是失敗的請求數量。
 你有 0 次失敗,這意味著所有請求都成功完成,這是非常好的結果。

 4. Median (ms):這是響應時間的中位數,以毫秒(ms)為單位。
 中位數響應時間為 75 ms,即 0.075 秒。這意味著一半的請求在 0.075 秒內完成。

 5. 90%ile (ms):這是響應時間的第 90 百分位值(90% 的請求在該時間內完成)。
 第 90 百分位的響應時間是 230 ms,即 0.23 秒。這意味著 90% 的請求在 0.23 秒內完成。

 6. 99%ile (ms):這是響應時間的第 99 百分位值(99% 的請求在該時間內完成)。
 第 99 百分位的響應時間是 520 ms,即 0.52 秒。這意味著 99% 的請求在 0.52 秒內完成。

 7. Average (ms):這是響應時間的平均值。
 平均響應時間為 113 ms,即約 0.113 秒。這表示所有請求的平均完成時間。

 8. Min (ms):這是最短的響應時間。
 最短響應時間是 44 ms,這意味著最快的請求在 44 毫秒內完成。

 9. Max (ms):這是最長的響應時間。
 最長響應時間是 3,074 ms,即約 3 秒。這意味著有一些請求花費了較長時間才完成。

 10. Average size (bytes):這是每個響應的平均大小,以字節(bytes)為單位。
 每個響應的平均大小為 18,716 bytes。

 11. Current RPS (Requests per Second):這是當前每秒的請求數。
 當前每秒的請求數是 116.6,這意味著你的系統每秒處理大約 116.6 個請求。

 12. Current Failures/s:這是當前每秒的失敗數量。
 每秒失敗請求數為 0,這意味著在測試期間沒有發生失敗請求。


● 性能分析:
1. 每秒請求數 (RPS):116.6 次每秒的請求量算是中等水平。這樣的數值取決於你的服務器配置和應用程序的複雜性。如果你的服務器在每秒 116.6 個請求的負載下仍然能保持穩定且無失敗,那麼它在這一負載下的表現是非常好的。
2. 響應時間:中位數響應時間為 75 ms,平均響應時間也是 75 ms 左右。這可能表明你的系統在負載較大的情況下仍可保持較短的延遲。
3. 成功率:這次測試沒有任何失敗請求,這意味著你的系統在處理這個負載時非常穩定,沒有崩潰或出錯。

● 結論:
1. 請求成功率:100% 成功率是非常好的,系統在這個負載下運行穩定。
2. 響應時間:響應時間短,75 ms的響應時間就服務而言可以接受。
3. 簡單看 => RPS愈高,Average愈小 Failures愈少,這樣的整體服務就愈好

留言

這個網誌中的熱門文章

[C#] 無法載入檔案或組件 或其相依性的其中之一。 找到的組件資訊清單定義與組件參考不符。 (發生例外狀況於 HRESULT: 0x80131040)

[Cloud CICD] 後端篇 - .Net8 WebApi, Github Action, Azure App Service

[Cloud CICD] 前端篇 - Vue3, Github Action, Azure Static Web App