如果您已經在大型測試套件中使用過 Playwright 一段時間,那麼您可能已經使用過--shard
選項將測試並行化到多台機器或 CI 執行器上。乍一看,這似乎是完美的解決方案。但隨著測試套件的成長,您開始注意到一個令人沮喪的問題:有些測試執行器在合理的時間內完成,而其他測試執行器可能需要更長的時間。最終,您只能等待最慢的執行器完成。
造成這種情況的主要原因在於 Playwright 的分片機制:它是靜態的。它會在測試開始前將測試檔案分割成均勻的區塊,並將每個區塊分配給特定的機器或 CI 執行器。例如,如果您在 4 個執行器上進行分片,它會將您的測試分成 4 個預定的群組。
# Runner 1 runs the first quarter of tests
npx playwright test --shard=1/4
# Runner 2 runs the second quarter
npx playwright test --shard=2/4
# ...and so on
如果所有測試耗時完全相同,這種方法會非常有效。但在現實世界中,這種情況永遠不會發生。有些測試簡短簡單,而有些測試則涉及複雜的使用者流程,耗時更長。這種靜態劃分會導致嚴重的不平衡:
負荷分佈不均勻:一名跑步者可能通過了所有「簡單」的測試,並提前完成,無所事事。
浪費資源:當一名跑步者閒著的時候,另一名跑步者卻在為一長串「艱難」的測試而苦苦掙扎。
更長的執行時間:您的總測試執行時間由最慢的分片決定,而不是平均值。
為了讓這個問題更加具體,讓我們來看看真實的 GitLab CI 管道的螢幕截圖,其中 53 個測試套件分佈在 4 個執行器上。
如您所見,測試分佈遠非平衡:
跑者 1(片段 1/4): 46 秒
跑者 2(碎片 2/4): 1 分 45 秒
跑者 3(片段 3/4): 41 秒
跑者 4(碎片 4/4): 1 分 1 秒
我們測試套件的總執行時間由最慢的執行器決定,耗時1 分 45 秒。同時,執行器 3 僅用了41 秒就完成了!這意味著我們的一個 CI 執行器完全閒置了一分鐘多,等待其他執行器趕上來。這是一個靜態分片導致 CI/CD 資源浪費和反饋週期延長的例子。
我想介紹一下Pawdist ,這是一款基於 Rust 的高效能動態測試分發器,由我開發,旨在解決此問題。 Pawdist 不使用預先分配測試,而是使用成熟的Manager-Worker架構:
管理器:它會掃描您的所有測試並建立一個單獨的工作佇列。
工作器:它們連接到管理器並請求測試。一旦工作器完成測試,它就會從佇列中請求下一個測試。
這樣,CI 執行器就不會閒著。快速完成短測試的執行器可以立即取得下一個可用測試,從而更快地清空佇列。這可以確保您的資源得到更有效率的利用,直到最後一個測試完成。
為了示範實際影響,我建立了一個包含 100 個測試的範例 Playwright 專案。我特意設計它來暴露靜態分片的弱點:
測試 1-50:故意設得比較長,每次耗時 15-25 秒。
測試 51-100:故意縮短,每次耗時 1-15 秒。
// A snippet from the test file to show the imbalance
import { test, expect } from '@playwright/test';
// ...
test('Distribution Test 4', async ({ page }) => {
await page.waitForTimeout(25000); // 25 seconds (long test)
expect(true).toBe(true);
});
// ...
test('Distribution Test 77', async ({ page }) => {
await page.waitForTimeout(1000); // 1 second (short test)
expect(true).toBe(true);
});
我使用三種不同的方法執行了這個測試套件,並將這些方法的總平行數保持在 4。
首先,我在一台機器上用 4 個並行工作器執行了全部 100 個測試。這給了我們最佳場景下的時間。
整個測試套件在 6 分 3 秒內完成。
接下來,我將測試分成兩個執行器(模擬兩台 CI 機器),每個執行器執行 2 個並行工作器。
由於 Playwright 按順序拆分測試,結果造成了嚴重的不平衡:
碎片 1/2(測試 1-50):收到所有長測試,耗時8 分 36 秒。
Shard 2/2(測試 51-100):完成了所有簡短的測試,僅用了3 分 32 秒就完成了。
由於最慢的分片,總執行時間膨脹至 8 分 36 秒。
最後,我使用 Pawdist 和兩個工人,每個工人設定為 2 個並行執行者。
日誌清晰地展現了動態分配的魔力。工作器不再局限於一組預先定義的測試,而是從一個共享的佇列中拉取資料。當一個工作器完成一個測試(無論長短)後,它會立即從中央佇列請求下一個測試。這確保了即使一個工作器忙於一個長測試,另一個工作器也能同時完成幾個短測試,從而有效地即時平衡負載。
整個測試套件在6 分 5 秒內完成,幾乎與理想基線相匹配,並消除了靜態分片造成的巨大不平衡。
|方法|總執行時間|
|------------------------|--------------------------------|
| 基線(無分片)| 6 分 3 秒 |
| 劇作家 Sharding | 8 分 36 秒 |
| Pawdist | 6分5秒 |
基準測試結果不言而喻。 Pawdist 提供了分散式測試的可擴充性,而沒有靜態分片的效能損失。
如果您希望優化 Playwright 測試執行時間並充分利用 CI 資源,請嘗試 Pawdist!
透過切換到動態分發模型,您可以實現:
更快的整體執行:當最後一個測試完成時,您的套件就會完成,而不是最慢的碎片。
最佳資源利用:不再有空閒的 CI 執行者等待其他人趕上。
真正的動態負載平衡:按需分配測試以實現最高效率。
有關詳細的安裝和使用說明,您可以查看GitHub上該專案的綜合 README。
原文出處:https://dev.to/muhendiskedibey/is-playwrights-sharding-slowing-you-down-meet-pawdist-iap