Bạn muốn biết API của mình hoạt động như thế nào ở chính xác 500 yêu cầu mỗi giây, chứ không phải "nhanh nhất có thể với N luồng hoạt động hết công suất." Hầu hết các công cụ kiểm thử tải đều cố định số lượng kết nối đồng thời và để tốc độ yêu cầu dao động. Vegeta làm điều ngược lại: bạn đặt tốc độ, và nó sẽ gửi đúng số lượng yêu cầu mỗi giây đó bất kể máy chủ phản hồi như thế nào. Sự khác biệt đó rất quan trọng khi bạn quan tâm đến các con số mà phiếu trả lời sử dụng, thông lượng ở một mức tải mục tiêu và độ trễ mà bạn thực sự cam kết trong một SLO.
Vegeta là gì
Vegeta là một công cụ kiểm thử tải HTTP dòng lệnh được viết bằng Go. Nó cũng có thể được sử dụng như một thư viện Go, nhưng hướng dẫn này sẽ tập trung vào giao diện dòng lệnh (CLI). Ý tưởng cốt lõi là duy trì tốc độ yêu cầu không đổi. Bạn yêu cầu Vegeta "gửi 100 yêu cầu mỗi giây trong 30 giây", và nó sẽ duy trì tốc độ đó bằng cách thêm worker khi cần. Nếu máy chủ chậm lại, Vegeta vẫn tiếp tục đưa ra các yêu cầu mới đúng theo lịch trình thay vì chờ các yêu cầu cũ hoàn thành.
Thiết kế đó mang lại cho bạn một bài kiểm thử tải theo mô hình mở. Lưu lượng truy cập thực tế đến theo thời gian riêng của nó; người dùng không dừng lại và chờ đợi điểm cuối chậm của bạn trước khi người dùng tiếp theo xuất hiện. Một công cụ dựa trên tốc độ sẽ phù hợp với hành vi đó.
Tải dựa trên tốc độ so với tải dựa trên số lượng kết nối đồng thời
Đây là điểm mà mọi người thường bối rối.
Một công cụ dựa trên số lượng kết nối đồng thời (một nhóm luồng hoặc người dùng ảo cố định, mỗi luồng/người dùng lặp lại yêu cầu-phản hồi) sử dụng mô hình đóng. Khi máy chủ chậm lại, vòng lặp bị đình trệ, do đó tốc độ yêu cầu thực tế giảm xuống. Bạn yêu cầu tạo tải, nhưng công cụ lại âm thầm giảm tải. Điều đó che giấu sự tắc nghẽn mà bạn có thể thấy trong môi trường sản xuất.
Một công cụ dựa trên tốc độ như Vegeta sử dụng mô hình mở. Bạn cố định tốc độ đến của yêu cầu. Nếu máy chủ không thể theo kịp, các yêu cầu sẽ xếp hàng, độ trễ tăng lên và báo cáo sẽ cho thấy điều đó. Bạn sẽ có một cái nhìn trung thực về những gì xảy ra khi nhu cầu vượt quá khả năng.
Không có mô hình nào là sai cả. Sử dụng mô hình đồng thời khi bạn muốn biết "tôi có thể phục vụ bao nhiêu người dùng cùng lúc." Sử dụng mô hình tốc độ khi bạn muốn biết "điều gì sẽ xảy ra ở 2.000 yêu cầu mỗi giây." Vegeta thuộc loại thứ hai. Để có cái nhìn tổng quan hơn về không gian công cụ, hãy xem các công cụ kiểm thử tải API hàng đầu.
Cài đặt Vegeta
Hãy chọn phương pháp phù hợp với thiết lập của bạn.
Homebrew trên macOS:
brew update && brew install vegeta
Các trình quản lý gói khác:
# MacPorts
port install vegeta
# Arch Linux
pacman -S vegeta
# FreeBSD
pkg install vegeta
Từ mã nguồn với Go đã cài đặt:
git clone https://github.com/tsenart/vegeta
cd vegeta
make vegeta
Bạn cũng có thể tải xuống tệp nhị phân đã biên dịch sẵn từ trang phát hành trên GitHub. Xác nhận cài đặt:
vegeta --help
Luồng xử lý cốt lõi
Vegeta được xây dựng xung quanh các đường ống Unix (Unix pipes). Một mục tiêu (target) được đưa vào, một cuộc tấn công (attack) được chạy và một báo cáo (report) được tạo ra. Lần chạy hữu ích nhỏ nhất là một dòng lệnh:
echo "GET http://localhost:8080/" | vegeta attack -duration=5s -rate=100 | vegeta report
Đọc từ trái sang phải:
echoghi một mục tiêu (phương thức và URL) vào đầu ra chuẩn.vegeta attackđọc mục tiêu đó từ đầu vào chuẩn và bắn 100 yêu cầu mỗi giây trong 5 giây. Tổng cộng là 500 yêu cầu.vegeta reportđọc luồng kết quả nhị phân và in ra bản tóm tắt.
Cờ -rate nhận số yêu cầu trên mỗi đơn vị thời gian. -rate=100 và -rate=100/1s có nghĩa giống nhau. -rate=50/500ms có nghĩa là 50 yêu cầu mỗi 500 mili giây. Đặt -rate=0 sẽ loại bỏ giới hạn và gửi yêu cầu nhanh nhất có thể, đây là một bài kiểm thử hoàn toàn khác.
Một báo cáo văn bản trông như thế này:
Requests [total, rate, throughput] 500, 100.20, 100.18
Duration [total, attack, wait] 4.991s, 4.990s, 1.2ms
Latencies [min, mean, 50, 90, 95, 99, max] 412us, 1.3ms, 1.1ms, 1.9ms, 2.4ms, 5.1ms, 12ms
Bytes In [total, mean] 128500, 257.00
Bytes Out [total, mean] 0, 0.00
Success [ratio] 100.00%
Status Codes [code:count] 200:500
Error Set:
Đọc dòng độ trễ trước. Cột 50 là trung vị (median). Cột 99 là phần đuôi: 1 phần trăm yêu cầu chậm hơn con số đó. Phần đuôi là nơi người dùng cảm thấy khó chịu, vì vậy một giá trị trung bình khỏe mạnh nhưng percentile thứ 99 xấu xí vẫn là một vấn đề. Tiếp theo, kiểm tra Success [ratio] và Status Codes. Tỷ lệ thành công 100 phần trăm với tất cả các mã 200 có nghĩa là máy chủ đã chịu được tải. Bất kỳ mã 5xx nào hoặc Error Set không trống có nghĩa là nó bắt đầu gặp sự cố.
Lưu kết quả, sau đó báo cáo theo nhiều cách
Đưa trực tiếp vào report là tốt cho việc xem nhanh. Đối với bất cứ thứ gì bạn sẽ xem lại, hãy lưu kết quả thô vào một tệp trước, sau đó tạo mọi báo cáo bạn muốn từ tệp đó.
echo "GET http://localhost:8080/" | \
vegeta attack -duration=10s -rate=200 -output=results.bin
Bây giờ lần chạy đã được ghi lại trong results.bin. Tạo một báo cáo văn bản:
vegeta report results.bin
Tạo JSON có cấu trúc cho bảng điều khiển hoặc để so sánh giữa các lần chạy:
vegeta report -type=json results.bin > metrics.json
Tạo biểu đồ tần suất độ trễ với các khoảng bạn chọn:
vegeta report -type='hist[0,2ms,5ms,10ms,25ms,100ms]' results.bin
Biểu đồ tần suất đếm số lượng yêu cầu rơi vào mỗi dải độ trễ. Đây là một cách nhanh chóng để xem liệu độ trễ có được phân nhóm chặt chẽ hay trải rộng trên một phạm vi rộng.
Định dạng tệp mục tiêu
Các API thực tế cần nhiều hơn một yêu cầu GET. Di chuyển các mục tiêu của bạn vào một tệp và chuyển nó bằng cách sử dụng -targets. Định dạng HTTP mặc định là dựa trên dòng và dễ đọc.
Tạo tệp targets.txt:
GET http://localhost:8080/api/users
POST http://localhost:8080/api/users
Content-Type: application/json
@./payload.json
GET http://localhost:8080/api/users/42
Một vài quy tắc để điều này hoạt động:
- Dòng đầu tiên của mỗi mục tiêu là
PHƯƠNG_THỨC URL. - Các dòng tiêu đề theo ngay dưới dòng phương thức, mỗi dòng một
Khóa: Giá trị. - Một dòng bắt đầu bằng
@chỉ định một tệp có nội dung trở thành phần thân yêu cầu. - Một dòng trống phân tách mục tiêu này với mục tiêu tiếp theo.
- Các dòng bắt đầu bằng
#là các bình luận.
Đặt phần thân JSON của bạn vào tệp payload.json:
{ "name": "Ada", "role": "engineer" }
Chạy cuộc tấn công với tệp:
vegeta attack -targets=targets.txt -rate=50 -duration=30s | vegeta report
Vegeta lặp lại các mục tiêu theo thứ tự và tiếp tục lặp cho đến khi thời gian kết thúc. Bạn cũng có thể thêm các tiêu đề toàn cục trên dòng lệnh bằng -header, điều này rất tiện lợi cho việc xác thực:
vegeta attack -targets=targets.txt -rate=50 -duration=30s \
-header="Authorization: Bearer $TOKEN" | vegeta report
Đối với các lần chạy có lập trình hoặc khối lượng lớn, Vegeta cũng đọc định dạng mục tiêu JSON. Mỗi dòng là một đối tượng JSON, và bạn chọn nó bằng -format=json:
{"method": "GET", "url": "http://localhost:8080/api/users"}
{"method": "POST", "url": "http://localhost:8080/api/users", "header": {"Content-Type": ["application/json"]}, "body": "eyJuYW1lIjoiQWRhIn0="}
Trường body được mã hóa base64. Định dạng này truyền tải tốt, vì vậy bạn có thể tạo mục tiêu một cách linh hoạt và đưa chúng trực tiếp vào bằng -lazy để tiết kiệm bộ nhớ.
Biểu đồ và đồ thị tần suất
Một con số duy nhất có thể che giấu các xu hướng. Nếu độ trễ giảm dần giữa chừng một lần chạy, bạn sẽ muốn xem đường cong. Lệnh plot của Vegeta biến một luồng kết quả thành một trang HTML tương tác:
vegeta attack -targets=targets.txt -rate=100 -duration=60s | \
vegeta plot > plot.html
Mở plot.html trong trình duyệt. Bạn sẽ nhận được biểu đồ chuỗi thời gian về độ trễ trong suốt quá trình chạy, vì vậy một sự tăng chậm hoặc một đỉnh đột biến giữa thử nghiệm sẽ rất rõ ràng. Bạn có thể vẽ biểu đồ nhiều lần chạy cùng nhau để so sánh các mức tải:
vegeta attack -rate=50 -duration=30s -targets=targets.txt -output=50qps.bin
vegeta attack -rate=100 -duration=30s -targets=targets.txt -output=100qps.bin
vegeta plot 50qps.bin 100qps.bin > compare.html
Đối với các môi trường không có giao diện đồ họa, hãy bỏ qua biểu đồ và xuất biểu đồ tần suất hoặc tệp CSV thô bằng encode:
vegeta encode -to=csv results.bin > results.csv
Khi nào nên sử dụng Vegeta
Hãy tìm đến Vegeta khi câu hỏi là về tốc độ và dung lượng:
- Bạn cần thông lượng và độ trễ ở một mục tiêu số yêu cầu mỗi giây cụ thể.
- Bạn muốn tìm ra tốc độ mà độ trễ hoặc tỷ lệ lỗi bắt đầu tăng lên.
- Bạn đang so sánh hai bản dựng hoặc hai cấu hình cơ sở hạ tầng dưới cùng một mức tải có thể lặp lại.
- Bạn muốn một công cụ có thể lập kịch bản, dễ dàng tích hợp vào luồng dòng lệnh và tác vụ CI mà không cần giao diện đồ họa.
Đây là một công cụ chuyên biệt. Nó gửi các yêu cầu HTTP theo một tốc độ và đo lường cách máy chủ phản hồi. Nó không tạo kịch bản cho các hành trình người dùng nhiều bước với logic phân nhánh, và nó cũng không xác thực nội dung phản hồi ngoài các mã trạng thái. Sự tập trung đó là một tính năng; nó giữ cho công cụ nhỏ gọn và kết quả rõ ràng.
Nếu bạn đang cân nhắc nó so với các công cụ khác, các so sánh trong kiểm thử tải k6 và kiểm thử tải JMeter đề cập đến các lựa chọn thay thế mô hình đồng thời. Đối với các khái niệm và số liệu cơ bản, hướng dẫn kiểm thử hiệu năng API là một tài liệu tham khảo tốt.
Kiểm thử chức năng phù hợp ở đâu
Kiểm thử tải trả lời câu hỏi “nó có đủ nhanh không.” Nó không trả lời câu hỏi “nó có đúng không.” Một lần chạy Vegeta có thể báo cáo 100 phần trăm mã 200 trong khi điểm cuối trả về sai người dùng, một mức giá cũ hoặc một trường JSON không đúng định dạng. Mỗi phản hồi đó đều là một phản hồi 200 nhanh chóng, thành công đối với một công cụ kiểm thử tải.
Tính đúng đắn cần một kiểm tra khác: các xác nhận trên nội dung phản hồi, lược đồ và các quy tắc nghiệp vụ. Đó là kiểm thử chức năng, và nó nên được thực hiện trước và song song với các lần chạy tải của bạn. Mô hình lành mạnh là xác thực rằng API hoạt động đúng, sau đó đo lường hiệu suất của nó dưới tải.
Đây là nơi Apidog bổ trợ cho một công cụ như Vegeta hơn là cạnh tranh với nó. Trong Apidog, bạn xây dựng các kịch bản kiểm thử với các xác nhận trực quan về trạng thái, tiêu đề và các trường JSON, chuỗi các yêu cầu và điều khiển chúng từ các tệp dữ liệu. Bạn xác nhận API trả về dữ liệu chính xác. Vegeta sau đó xác nhận rằng nó vẫn nhanh khi đường dẫn chính xác đó được truy cập hàng trăm lần mỗi giây. Hai công cụ, hai câu hỏi.
Apidog cũng cung cấp một CLI không đầu (headless CLI) để các kịch bản chức năng đó chạy trong cùng một pipeline CI với bước tải của bạn. Cài đặt nó bằng Node:
npm install -g apidog-cli
Sau đó chạy một kịch bản hoặc bộ đã lưu theo ID, với các trình báo cáo cho pipeline của bạn:
apidog run --access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioOrSuiteId> \
-e <environmentId> \
-r cli,html,junit
Cờ -t nhận ID kịch bản, thư mục hoặc bộ, -e nhận ID môi trường và -r chọn một hoặc nhiều trình báo cáo (cli, html, json, junit). Đầu ra junit phù hợp với hầu hết các bảng điều khiển CI. Xem hướng dẫn dòng lệnh Apidog CLI để biết cách chạy từng bước, và hướng dẫn pipeline CI/CD để có quy trình làm việc sao chép-dán. Chạy kiểm thử chức năng trước, sau đó để Vegeta đo lường các điểm cuối đã vượt qua.
Câu hỏi thường gặp
Vegeta có hỗ trợ các yêu cầu POST với phần thân không?
Có. Trong tệp mục tiêu HTTP, đặt phương thức và URL ở dòng đầu tiên, thêm tiêu đề Content-Type, và tham chiếu tệp nội dung với @./payload.json. Trong định dạng JSON, đặt trường method, url và trường body được mã hóa base64.
-rate=0 có tác dụng gì?
Nó loại bỏ giới hạn tốc độ và gửi yêu cầu nhanh nhất có thể theo khả năng của các worker và kết nối. Đó là một bài kiểm thử thông lượng tối đa, khác với một bài kiểm thử tốc độ không đổi có kiểm soát. Để đo lường khả năng lặp lại, hãy đặt một tốc độ rõ ràng.
Làm cách nào để đọc các phân vị độ trễ?
Dòng độ trễ của báo cáo hiển thị min, mean, và các phân vị thứ 50, 90, 95, 99 và max. Hãy tập trung vào thứ 95 và 99. Chúng mô tả phần đuôi chậm mà người dùng thực tế gặp phải, điều mà giá trị trung bình (mean) một mình có thể che giấu.
Vegeta có thể kiểm tra xem API của tôi có trả về dữ liệu chính xác không?
Không. Nó đo lường thông lượng, độ trễ và mã trạng thái. Nó không xác nhận nội dung hoặc lược đồ phản hồi. Hãy kết hợp nó với một công cụ kiểm thử chức năng để đảm bảo tính đúng đắn, sau đó sử dụng Vegeta cho tốc độ và độ trễ.
Làm cách nào để chạy Vegeta trong CI?
Nó là một tệp nhị phân duy nhất đọc từ stdin và ghi kết quả, vì vậy nó có thể được tích hợp vào bất kỳ bước shell nào. Lưu kết quả bằng -output, sau đó tạo báo cáo văn bản hoặc JSON làm artifact của bản dựng. Thêm một cổng chức năng, chẳng hạn như Apidog CLI, trước bước tải để bạn chỉ đo lường các điểm cuối đã vượt qua các xác nhận của chúng.
