Tăng tốc kiểm thử Playwright với Pawdist: Giải pháp phân phối động
Nếu bạn đã sử dụng Playwright một thời gian dài với bộ kiểm thử lớn, có thể bạn đã từng dùng tùy chọn --shard
để phân phối kiểm thử của mình qua nhiều máy hoặc CI runners. Lúc đầu, điều này có vẻ như là giải pháp hoàn hảo. Nhưng khi bộ kiểm thử của bạn phát triển, bạn sẽ nhận thấy một vấn đề khó chịu: một số runners hoàn thành trong thời gian hợp lý, trong khi những cái khác lại mất thời gian đáng kể hơn. Cuối cùng, bạn sẽ phải chờ đợi runner chậm nhất hoàn thành.
Nguyên nhân của vấn đề
Nguyên nhân chính của vấn đề này là cách thức hoạt động của sharding trong Playwright: nó tĩnh. Nó chia các tệp kiểm thử thành các khối đều trước khi các bài kiểm thử bắt đầu và gán mỗi khối cho một máy hoặc CI runner cụ thể. Ví dụ, nếu bạn chia sẻ trên 4 runners, nó sẽ chia bộ kiểm thử của bạn thành 4 nhóm đã được xác định trước.
bash
# Runner 1 chạy phần một của kiểm thử
npx playwright test --shard=1/4
# Runner 2 chạy phần hai
npx playwright test --shard=2/4
# ...và cứ thế
Cách tiếp cận này hoạt động hoàn hảo nếu tất cả các bài kiểm thử của bạn mất đúng thời gian như nhau. Nhưng trong thực tế, điều đó không bao giờ xảy ra. Một số bài kiểm thử ngắn và đơn giản, trong khi những bài khác liên quan đến các quy trình người dùng phức tạp và mất nhiều thời gian hơn. Sự phân chia tĩnh này dẫn đến sự mất cân bằng đáng kể:
- Phân phối tải không đồng đều: Một runner có thể nhận hết các bài kiểm thử "dễ" và hoàn thành sớm, ngồi chờ trong khi các runner khác còn lại phải làm việc vất vả.
- Lãng phí tài nguyên: Trong khi một runner đang chờ, một runner khác lại phải vật lộn với hàng đợi dài các bài kiểm thử "khó".
- Thời gian thực thi lâu hơn: Thời gian chạy tổng thể của bạn bị chi phối bởi shard chậm nhất, không phải là thời gian trung bình.
Ví dụ thực tế
Để làm rõ hơn vấn đề này, hãy cùng xem một ảnh chụp màn hình từ một pipeline GitLab CI thực tế nơi bộ kiểm thử gồm 53 bài được phân phối qua 4 runners.
Như bạn có thể thấy, sự phân phối kiểm thử rất không đồng đều:
- Runner 1 (shard 1/4): 46 giây
- Runner 2 (shard 2/4): 1 phút 45 giây
- Runner 3 (shard 3/4): 41 giây
- Runner 4 (shard 4/4): 1 phút 1 giây
Thời gian thực thi tổng thể cho bộ kiểm thử của chúng tôi được xác định bởi runner chậm nhất, đó là 1 phút và 45 giây. Trong khi đó, Runner 3 đã hoàn thành chỉ trong 41 giây! Điều này có nghĩa là một trong các CI runner của chúng tôi đã ngồi hoàn toàn không làm gì trong hơn một phút, chờ đợi những cái khác bắt kịp. Đây là một ví dụ về việc sharding tĩnh dẫn đến lãng phí tài nguyên CI/CD và chu kỳ phản hồi kéo dài.
Giải pháp: Phân phối kiểm thử động với Pawdist
Tôi xin giới thiệu Pawdist, một bộ phân phối kiểm thử động hiệu suất cao, được phát triển bằng Rust để giải quyết vấn đề này. Thay vì gán trước các bài kiểm thử, Pawdist sử dụng kiến trúc Manager-Worker đã được chứng minh:
- Manager: Quản lý quét tất cả các bài kiểm thử và tạo ra một hàng đợi công việc duy nhất.
- Workers: Kết nối với manager và yêu cầu một bài kiểm thử. Ngay khi một worker hoàn thành một bài kiểm thử, nó sẽ yêu cầu bài kiểm thử tiếp theo từ hàng đợi.
Theo cách này, không có CI runner nào phải ngồi không. Một runner nhanh chóng hoàn thành một bài kiểm thử ngắn có thể ngay lập tức lấy bài tiếp theo có sẵn, giúp làm sạch hàng đợi nhanh hơn. Điều này đảm bảo rằng tài nguyên của bạn được sử dụng hiệu quả hơn cho đến khi bài kiểm thử cuối cùng hoàn thành.
So sánh: Pawdist vs. Playwright Sharding
Để chứng minh tác động thực tế, tôi đã tạo một dự án Playwright mẫu với 100 bài kiểm thử. Tôi cố tình thiết kế nó để phơi bày điểm yếu của sharding tĩnh:
- Tests 1-50: Cố tình lâu, mất từ 15-25 giây mỗi bài.
- Tests 51-100: Cố tình ngắn, mất từ 1-15 giây mỗi bài.
javascript
// Một đoạn mã từ tệp kiểm thử để thể hiện sự mất cân bằng
import { test, expect } from '@playwright/test';
// ...
test('Kiểm thử Phân phối 4', async ({ page }) => {
await page.waitForTimeout(25000); // 25 giây (kiểm thử dài)
expect(true).toBe(true);
});
// ...
test('Kiểm thử Phân phối 77', async ({ page }) => {
await page.waitForTimeout(1000); // 1 giây (kiểm thử ngắn)
expect(true).toBe(true);
});
Tôi đã chạy bộ kiểm thử này bằng ba phương pháp khác nhau, giữ nguyên tổng số song song là 4 cho các phương pháp này.
Chạy 1: Mức cơ bản (Không Sharding)
Trước tiên, tôi đã chạy tất cả 100 bài kiểm thử trên một máy duy nhất với 4 worker song song. Điều này cho chúng ta thời gian tốt nhất có thể.
Toàn bộ bộ kiểm thử hoàn thành trong 6 phút 3 giây.
Chạy 2: Sự mất cân bằng của Sharding tĩnh
Tiếp theo, tôi đã chia các bài kiểm thử qua hai runner (mô phỏng hai máy CI), mỗi máy chạy 2 worker song song.
Vì Playwright chia các bài kiểm thử theo thứ tự, kết quả đã tạo ra sự mất cân bằng nghiêm trọng:
- Shard 1/2 (Tests 1-50): Nhận tất cả các bài kiểm thử dài và mất 8 phút 36 giây.
- Shard 2/2 (Tests 51-100): Nhận tất cả các bài kiểm thử ngắn và hoàn thành chỉ trong 3 phút 32 giây.
Thời gian thực thi tổng thể đã tăng lên 8 phút 36 giây, bị chi phối bởi shard chậm nhất.
Chạy 3: Giải pháp Pawdist (Phân phối động)
Cuối cùng, tôi đã sử dụng Pawdist với hai worker, mỗi cái được đặt thành 2 runner song song.
Nhật ký rõ ràng cho thấy phép màu của phân phối động. Thay vì bị khóa vào một nhóm bài kiểm thử đã được xác định trước, các worker rút từ một hàng đợi chung. Khi một worker hoàn thành một bài kiểm thử (dù ngắn hay dài), nó ngay lập tức yêu cầu bài kiểm thử tiếp theo từ hàng đợi trung tâm. Điều này đảm bảo rằng ngay cả khi một worker bị mắc kẹt với một bài kiểm thử dài, một worker khác có thể hoàn thành nhiều bài kiểm thử ngắn hơn trong thời gian chờ, hiệu quả cân bằng tải theo thời gian thực.
Toàn bộ bộ kiểm thử hoàn thành trong 6 phút 5 giây, gần như khớp với mức lý tưởng và loại bỏ sự mất cân bằng lớn do sharding tĩnh gây ra.
Phương pháp | Thời gian thực thi tổng thể |
---|---|
Mức cơ bản (Không Sharding) | 6m 3s |
Sharding Playwright | 8m 36s |
Pawdist | 6m 5s |
Thước đo hiệu suất đã nói lên tất cả. Pawdist cung cấp khả năng mở rộng của kiểm thử phân tán mà không gặp phải các hình phạt hiệu suất của sharding tĩnh.
Sẵn sàng để tăng tốc kiểm thử của bạn?
Nếu bạn đang tìm cách tối ưu hóa thời gian thực thi bài kiểm thử Playwright của mình và tận dụng tối đa tài nguyên CI, hãy thử Pawdist!
Bằng cách chuyển sang mô hình phân phối động, bạn có thể đạt được:
- Thời gian thực thi tổng thể nhanh hơn: Bộ kiểm thử hoàn thành khi bài kiểm thử cuối cùng hoàn thành, không phải shard chậm nhất.
- Tối ưu hóa sử dụng tài nguyên: Không còn runners CI nào phải ngồi không chờ đợi.
- Cân bằng tải động thực sự: Các bài kiểm thử được gán theo yêu cầu cho hiệu quả tối đa.
Để biết hướng dẫn cài đặt và sử dụng chi tiết, bạn có thể xem README toàn diện của dự án trên GitHub.