Community程式設計與開發github.com

DataMonarch/locust-load-test

使用 Python、locust 和 uv 對任何專案的 API 或 Web 服務進行負載測試。掃描程式碼庫中的每個端點,將其分類為核心、支援和邊緣功能,並讓使用者決定測試等級和流量情境,最後產出 HTML 報告。

locust-load-test 是什麼?

這是一個專為開發者和 AI 代理設計的負載測試技能,能自動化整個效能測試流程。它會先掃描專案程式碼,找出所有 API 端點(包括 Python、Node.js、Java、Go、Ruby 等常見框架),並根據業務重要性將其分類為核心(core)、支援(support)和邊緣(peripheral)功能。接著,它會引導使用者選擇測試等級(煙霧測試、預期負載、壓力測試)和流量情境(從專案本身的流量配置、限制和逾時中推導),然後自動建構 locust 測試工具、安全執行、收集伺服器端指標和 CPU 分析檔案,最後產出包含容量、服務瓶頸(knee)和失敗模式的 HTML 報告。此技能支援多種部署環境(本機、Kubernetes、Docker),並包含安全執行規則(如停止條件),以防止對共用系統造成意外損害。它適用於任何需要 API 負載測試、壓力測試、浸泡測試、尖峰測試、容量規劃或了解系統能承受多少使用者的場景,但**不**適用於單一函數的微基準測試或前端頁面速度(Lighthouse)稽核。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/DataMonarch/agent-skills/tree/HEAD/skills/locust-load-test

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

使用 locust 和 uv 進行負載測試

這項技能能將專案從「它能承受多少?」轉變為一份團隊可以據以行動的數據報告。請依序執行每個步驟,因為每個步驟都為下一個步驟提供基礎。使用者需要做出兩個決定:測試等級和流量情境,而且只有在看到您在程式碼中發現的資訊後,才能做出決定。

$SKILL 是此技能所在的資料夾,也就是您讀取此 SKILL.md 檔案所在的目錄。請在 shell 中設定一次 (SKILL=/path/to/locust-load-test)。負載測試本身會存在於目標儲存庫的 loadtest/ 目錄中(或使用者選擇的任何位置)。

1 探索   -> loadtest/endpoints.json   每個端點,包含其呼叫者和成本提示
2 分類   -> loadtest/PLAN.md          核心/支援/邊緣表格;向使用者顯示
3 詢問   -> 等級 + 情境 + 環境 + 限制條件
4 建置   -> loadtest/ (一個 uv 專案)   harness.py, payloads/, 執行腳本
5 執行   -> loadtest/results/<run>/   先執行煙霧測試,然後是選定的等級,風險最高的最後執行
6 收集   -> results/<run>/metrics, profiles   伺服器端資訊(當可連接時)
7 報告   -> loadtest/report.html + 以白話文說明的發現

1. 探索端點

uv run $SKILL/scripts/discover_endpoints.py . -o loadtest/endpoints.json --markdown loadtest/endpoints.md

掃描器會讀取程式碼,並且只寫入此檔案。它可以找到跨常見技術堆疊的路由宣告:Python、Node、JVM、Go、Ruby、.NET 和 PHP 框架,以及 OpenAPI 檔案、GraphQL schema、gRPC protos、websockets 和 SSE。它會盡可能解析路由器前綴和掛載點。它還會計算每個端點的客戶端站點呼叫數量(fetch、axios、httpx、requests、生成的客戶端、測試,以及伺服器渲染模板中的連結、表單和 htmx 屬性),以便您了解產品本身的 UI 和服務使用了什麼。每個條目都包含方法、路徑、file:line、處理程式、認證提示、主體提示、串流提示、成本提示、處理程式進行的呼叫,以及誰呼叫了它。

框架自己的路由列表勝過任何靜態掃描,因為框架已經解析了所有前綴、掛載點和生成的路由。當應用程式可以產生一個時,請將其用作事實來源。這指的是來自運行中開發伺服器的 OpenAPI 文件 (/openapi.json)、flask routes、bin/rails routes、php artisan route:list --json,或 Spring 的 /actuator/mappings:

uv run $SKILL/scripts/discover_endpoints.py . --route-dump http://localhost:8000/openapi.json -o loadtest/endpoints.json

然後,在信任輸出之前,務必批判性地閱讀它:

  • unmatched_client_calls 要不是掃描遺漏的路由,就是對其他服務的呼叫。
  • prefix_resolved: false 和 notes 標記了猜測。shared_handler: true 表示一個函數服務於多種方法,而掃描無法分辨其成本提示屬於哪個方法;請閱讀該處理程式。
  • existing_load_tests 列出了儲存庫中已有的 locustfiles 或 k6 腳本。請重複使用它們的 payload。
  • 對照原始程式碼抽查五個條目。

當清單看起來很薄弱、某個技術堆疊未被涵蓋,或者您需要某個框架的路由轉儲命令時,請閱讀 references/discovery.md。

2. 分類:核心、支援、邊緣

根據判斷對端點進行分類。不要根據關鍵字分類:相同的 /search 在商店中是核心功能,但在管理控制檯中則是支援功能。

層級它是什麼典型範例
核心使用者來此的目的,通常是繁重工作的所在地:計算、模型呼叫、資料處理、主要寫入路徑商店的結帳流程;文件服務中的轉換或提取功能;聊天 API 中的完成功能
支援使核心功能可用的功能登入、工作階段、設定、使用者自身資料的清單和搜尋、為核心功能提供資料的上傳功能、管理 CRUD
邊緣產品並非為此而存在健康檢查、指標、文件、靜態檔案、除錯路由、來自非所屬服務的 Webhook

需要權衡的證據:

  • README 和文件指出該產品的用途;
  • UI 呼叫最多的內容 (client_calls) 以及測試演練的內容 (test_calls);
  • 處理程式的成本:追蹤 calls 進入服務層,因為 cost_hints 只能看到處理程式主體。模型呼叫、資料庫寫入、外部呼叫、CPU 工作(密碼雜湊、壓縮、圖片:cpu)、檔案處理和佇列發布是使端點昂貴的原因;
  • 命名方式;
  • 如果可以查看,團隊自己的監控或日誌顯示最繁忙的內容。

撰寫 loadtest/PLAN.md,其中包含此表格,每個您打算進行負載測試的端點一行,以及一個簡短的、您排除的端點及其原因的列表:

| 端點 | 層級 | 原因 | 成本提示 | payload 來源 |
|---|---|---|---|---|
| POST /api/orders/{id}/checkout | 核心 | 購買路徑;UI 從 3 個地方呼叫 | 資料庫寫入,付款 API 呼叫 | tests/fixtures/order.json |

在提問之前向使用者顯示此表格,並邀請他們更正。錯誤的層級會使後續的每個數字都回答錯誤的問題,而使用者比任何掃描都更了解自己的產品。

3. 詢問使用者

使用 AskUserQuestion 工具。如果該工具不可用,請將相同的問題作為純編號列表提出,並等待回答。僅在使用者看到計劃表之後才提問。

  • Q1 核心等級。 第 1、2 或 3 級。
  • Q2 支援等級。 第 1、2 或 3 級,或者不測試支援功能。
  • Q3 使用者負載情境。 從此專案推導出的二到四個選項(見下文),並將您推薦的選項標記為「(推薦)」,並用一句話說明它為何合適。
  • Q4 目標環境。 要對哪個部署環境進行負載測試(staging、本機堆疊、負載測試副本)。除非使用者明確同意,否則切勿對生產系統進行負載測試。負載會擴散到共用的資料庫、租戶和帳單上。
層級執行方式回答的問題成本
1 煙霧/基準測試低穩定負載(一到幾個使用者)持續幾分鐘每個路徑是否都能運作,在無競爭情況下的延遲是多少?幾分鐘;風險極低
2 預期負載逐步增加到預期的峰值,保持該負載,然後在該水平進行短時間浸泡測試在業務最繁忙時是否能滿足延遲目標,以及有多少緩衝空間?大約一小時;目標環境以其真實峰值運行
3 壓力/容量測試逐步增加到觸發停止規則(瓶頸和崩潰點),外加一次尖峰測試它在哪裡崩潰、如何崩潰,以及它能否恢復?一到兩小時;目標環境將會飽和並可能崩潰,因此需要一個時間窗口和有人在旁監控

從專案關於其流量的說明中推導出 Q3 的選項:README 和文件(誰使用它、席位數、租戶)、配置(速率限制、工作者和副本數量、自動擴展器邊界、佇列大小、連線池)、cron 和批次作業,以及呼叫者自己的逾時和重試設定。常見的形狀有:上班時間的逐步增加、早晨的尖峰、穩定的浸泡測試、來自其他服務的整合突發、批次匯入,以及混合的互動式加背景流量。每個選項都應說明其數字:使用者數、生成速率、思考時間、持續時間和請求混合。當專案對其流量隻字未提時,請說明這一點,指出每個數字所依據的假設,並在 Q3 中詢問預期的峰值。 在提問之前閱讀 references/tiers-and-scenarios.md。它展示了如何將配置轉換為這些數字。

在得到答案後,以純文字確定兩件事:

  • 憑證。 它們來自一個檔案或環境變數,由測試工具讀取。切勿將它們貼到聊天中。
  • 限制條件。 列出您發現的並詢問其餘的:速率限制、許可證或啟用窗口、重新啟動的成本、共用租戶,以及每個請求的成本(模型 token、付費 API)。在許可證窗口內重新啟動可能會將服務鎖定一天,而幾個平行的繁重作業加上一個巨大的輸入可能會使目標環境癱瘓。在負載測試之前,而不是之後詢問。
  • 資料狀態。 列表和搜尋在實際使用中容納了多少行資料、資料是否可以在測試運行之間重置,以及測試使用者可以編輯或刪除哪些使用者的行。空的表格會使列表頁面變得免費,而測試運行添加的行會使後續的每個步驟讀取比以前更多的資料。

4. 建置測試工具

mkdir -p loadtest && cd loadtest
cp $SKILL/templates/pyproject.toml . && uv sync   # 專屬的 .venv 和 uv.lock;locust 版本鎖定,Python 3.11+
cp $SKILL/templates/{harness.py,run_local.sh,run_plan.sh,collect.sh,seed.py,loadtest.env.example} .
cp $SKILL/templates/run_docker.sh .      # 當生成器在目標環境的 Docker 網路上運行時
cp -r $SKILL/templates/{run_k8s.sh,k8s} .  # 當它在目標叢集內運行時
git -C .. status --short                 # 只允許出現 loadtest/

請勿在此運行 uv init。在一個本身就是 uv 專案的儲存庫中,它會將 loadtest 添加到應用程式的 [tool.uv.workspace],將 locust 安裝到應用程式的 .venv 中,並寫入應用程式層級的 uv.lock。如果發生這種情況,請復原:在應用程式中執行 git checkout -- pyproject.toml,刪除新的 uv.lock,然後在那裡運行 uv sync。然後填入範本:

  • REQUESTS. 根據 PLAN.md 填入 harness.py 中的表格:層級、名稱、權重、混合、主體和預期狀態。從專案的測試、fixtures 和 schemas 中獲取 payload,並將它們放入 loadtest/payloads/。切勿使用生產資料。伺服器渲染的應用程式會為其登入頁面和錯誤頁面都回答 200,因此請檢查僅在正確頁面上才有的內容:expect_text,以及在重定向是正確答案時檢查 expect_location。被重定向但未說明的行將會失敗。
  • REQ_TIMEOUT. 將其設定為真實呼叫者的逾時時間:閘道器、前端的 abort、客戶端 SDK 或代理的讀取逾時。測試工具將每個請求都保持到此逾時,作為完整答案的截止時間,因此較晚的答案會以「超過截止時間」失敗,而不是被計入成功(而產品早就將其報告為失敗)。
  • MIX. 為每個具有不同成本的流量混合提供自己的標籤,並將每個混合作為自己的情境運行(短聊天大小的輸入、文件大小的輸入、一個成本更高的選項)。它們的容量可能相差數倍,而混合運行會隱藏昂貴的那個。
  • Auth. 設定 AUTH,使每個模擬使用者登入一次,而不是每個請求都登入一次。帶有 session cookie 的表單登入也需要 LOGIN_EXPECT_LOCATION 或 LOGIN_EXPECT_TEXT,因為錯誤的密碼也會回答 200(請參閱 loadtest.env.example)。登入會進入 login 階段,並排除在步驟編號和停止規則之外:每個登入都會在添加其使用者的步驟開始時到達,而緩慢的密碼雜湊處理會以穩定負載從不支付的成本結束運行。要對登入本身進行負載測試,請將其設為一行。
  • 資料. 為應用程式填入 seed.py 並運行 python3 seed.py up --users N --rows M:通過應用程式的 API,每個測試帳戶都會獲得自己的行,SEED_MANIFEST 會將其分配給其使用者;行鍵 capture 和 consume 追蹤使用者建立和刪除的內容。將建立與刪除配對,或在運行之間重新播種。
  • 流程. 多步驟流程(上傳然後輪詢、建立然後讀取)是使用者類別上的一個方法;範本中有一個範例。

在構建時閱讀 references/harness.md。它涵蓋了每個欄位、形狀、認證模式、串流、非 HTTP 協定和三種部署方式。

5. 安全地執行

  1. 先執行煙霧測試。 運行 RUN_NAME=smoke SHAPE=smoke ./run_local.sh:每個使用者類別一個使用者,按表格順序發送每一行(將建立 id 的行放在使用它的行之前),然後空閒。日誌結尾會顯示 NOTE smoke: every row was sent,或者列出未發送的行。檢查零失敗、合理的延遲和正確的主體。這證明了連線正常,在產生任何負載成本之前。
  2. 檢查機器是否空閒。 在執行測量容量的運行之前,在生成器和目標環境的主機上運行 uptime 和 vmstat 1 5。同一核心上的其他作業會使每個數字都成為爭用的度量。測試工具在每次運行之前會將自身主機的取樣記錄到 run.json (host_check 和一個註解);當目標主機是另一台機器時,將其數字放入 NOTES。報告會在一個運行期間其主機或生成器 CPU 在其步驟中達到 90% 時加上橫幅,並對其瓶頸值提出警告。如果機器正忙,請等待、固定到空閒核心 (taskset),或移動,並說明是哪種情況。
  3. 然後執行選定的層級,從最安全開始。 先執行預期負載,然後是浸泡測試,然後是壓力測試,最後是尖峰測試。風險較高的輸入(最大的 payload、成本更高的選項)最後執行,這樣即使它們對目標造成損害,之前的測試結果也不會遺失。run_plan.sh 按順序運行列表,並且僅在目標的健康檢查通過時才開始每個運行。
  4. 當網路路徑很重要時,將生成器放在真實呼叫者旁邊:同一個叢集、VNet 或 compose 網路 (run_k8s.sh, run_docker.sh)。筆記型電腦上的運行測量的是網際網路和服務本身。每個運行都會記錄 GENERATOR,生成器自身的 CPU 會寫入 metrics/client.csv;當 CPU 超過約 90% 時,數字描述的是生成器。
  5. 遵守停止規則。 當失敗比率超過 STOP_FAIL_RATIO、當 p95 超過 STOP_P95_MS、當過去 20 秒內超過一半的請求失敗,或者當大多數登入失敗時,測試工具會結束運行。許多服務會對請求進行排隊而不是丟棄負載:零錯誤,而延遲只會增長。因此,請將 p95 上限設定為呼叫者的逾時時間或 SLO。不要為了「看看會怎樣」而強行越過停止規則。
  6. 在運行之間監控健康狀態,並讓佇列排空 (run_plan.sh 中的 COOLDOWN)。
  7. 清理您建立的所有內容: ./run_k8s.sh down (pod、ConfigMaps、Secret)、已停止的容器、測試使用者和測試資料。為使用者列出任何無法移除的內容,例如軟刪除的行或稽核條目。

在執行煙霧測試之外的第一次運行之前,以及在對共用系統進行任何運行之前,請閱讀 references/safety.md。

6. 收集伺服器端資訊

客戶端數字說明發生了什麼。伺服器端數字說明為什麼。在 locust 之前啟動收集器,在 locust 之後停止它們,並寫入同一個運行目錄:

uv run $SKILL/scripts/collect_metrics.py run_id

如果目標伺服器可透過 SSH 或 Kubernetes API 訪問,此腳本會收集:

  • top 和 vmstat 的快照;
  • 每個端點的 Nginx/HAProxy 指標(如果存在);
  • 應用程式日誌的最後 N 行;
  • 資料庫連線池狀態。

否則,它會提示使用者手動收集這些資料並將其放入 results/<run>/。

7. 報告

uv run $SKILL/scripts/generate_report.py loadtest/results/<run> -o loadtest/report.html

報告包含:

  • 執行摘要(測試了什麼、發現了什麼);
  • 容量估計(瓶頸點、崩潰點、恢復能力);
  • 每個端點的延遲分佈圖;
  • 伺服器端資源使用情況(CPU、記憶體、I/O);
  • 失敗模式分析;
  • 可操作的建議。

用白話文解釋結果,專注於團隊可以用來改善效能和容量的具體行動。

相關技能