Skip to main content

K6

在現代網頁與 API 系統開發中,效能測試是確保系統穩定性的關鍵環節。透過系統性的測試,我們能提前發現潛在瓶頸,確保系統在高併發情況下仍能穩定運作。

什麼是壓力測試?

壓力測試(Stress Testing)是一種軟體測試方法,主要目的是評估系統在極端條件下的穩定性與可靠度。這些極端條件包括:

  • 高流量訪問
  • 高併發請求
  • 大量資料處理

透過壓力測試,我們可以:

  • 找出系統的最大承載能力
  • 識別潛在瓶頸點
  • 觀察系統在超出設計負載時的行為表現
  • 確保系統能優雅地處理錯誤情況

常見應用情境

  • 電商網站:促銷活動期間的高流量衝擊
  • 金融系統:結算時段的高併發交易處理
  • API 服務:短時間內大量請求的處理能力

測試類型分類

根據測試目的和強度,可細分為以下幾種類型:

  • Smoke Testing(煙霧測試):驗證系統在低配備、正常負載下的基本運作
  • Load Testing(負載測試):測量系統在一般及尖峰負載下的效能指標
  • Stress Testing(壓力測試):測試系統在高負載或極端條件下的穩定性
  • Spike Testing(尖峰測試):模擬瞬間流量驟升的系統反應
  • Soak Testing(浸泡測試):測試系統長期運作下的穩定性

安裝與環境設置

使用 Docker 執行 K6

推薦使用 Docker 執行 K6,優點包括:

  • 避免複雜的依賴安裝
  • 確保跨平台的一致執行環境
  • 簡化部署流程

前置需求

  • 已安裝 Docker
  • 準備測試腳本(JavaScript)

基礎測試腳本範例

// test.js
import http from "k6/http";
import { check, sleep } from "k6";

export const options = {
vus: 10, // 10 個虛擬使用者
duration: "30s", // 測試持續 30 秒
};

export default function () {
const res = http.get("https://test-api.k6.io");
check(res, {
"status is 200": (r) => r.status === 200,
});
sleep(1); // 每次請求間隔 1 秒
}

執行測試

將上述腳本儲存為 test.js,透過以下指令執行:

docker run --rm -i -v ${PWD}:/scripts -w /scripts grafana/k6 run test.js

指令說明

  • --rm:測試結束後自動移除容器
  • -i:允許 Docker 接受 stdin 輸入
  • -v ${PWD}:/scripts:將當前目錄掛載到容器內的 /scripts 路徑
  • -w /scripts: 指定資料夾為 scripts
  • grafana/k6:使用官方 K6 Docker 映像檔
  • run /scripts/test.js:執行掛載的測試腳本

測試腳本撰寫技巧與實例

K6 使用 JavaScript 撰寫測試腳本,語法直觀且功能強大。以下提供常見情境的實作範例:

1. 基本 GET 請求測試

export default function () {
http.get("https://example.com");
}

2. API 回應內容驗證

const res = http.get("https://example.com/api/user");
check(res, {
"狀態碼為 200": (r) => r.status === 200,
"回應時間 < 1 秒": (r) => r.timings.duration < 1000,
"回傳內容包含 userId": (r) => r.body.includes("userId"),
});

3. 模擬使用者登入(POST 請求)

const payload = JSON.stringify({
username: "admin",
password: "123456",
});

const params = {
headers: { "Content-Type": "application/json" },
};

const res = http.post("https://example.com/api/login", payload, params);
check(res, {
登入成功: (r) => r.status === 200,
});

4. 使用 setup() 函數共享資料

export function setup() {
// 在測試開始前執行,回傳的資料會傳遞給所有虛擬使用者
return { token: "abc123" };
}

export default function (data) {
const res = http.get("https://example.com/api/data", {
headers: { Authorization: `Bearer ${data.token}` },
});

check(res, {
取得資料成功: (r) => r.status === 200,
});
}

5. 解析 HTML 內容

import http from "k6/http";
import { parseHTML } from "k6/html";

export default function () {
const loginPage = http.get("https://example.com/login");
const doc = parseHTML(loginPage.body);
const csrfToken = doc.find('input[name="_token"]').first().attr("value");

// 使用解析出的 CSRF token 進行後續操作
const payload = JSON.stringify({
username: "admin",
password: "123456",
_token: csrfToken,
});

const params = {
headers: { "Content-Type": "application/json" },
};

const res = http.post("https://example.com/login", payload, params);
check(res, {
登入成功: (r) => r.status === 200,
});
}

測試配置選項(options)

options 物件是定義 K6 測試行為的核心配置,包含虛擬使用者數量、測試時間、階段性壓力設定等。

常用配置屬性

屬性名稱資料型別說明
vus整數同時執行的虛擬使用者數量(固定負載模式)
duration字串測試總持續時間(如 "30s""1m""2h"
iterations整數總執行次數(設定後會覆蓋 durationvus
stages陣列多階段壓力測試配置
thresholds物件SLA 門檻條件設定(反應時間、錯誤率等)

階段性壓力測試範例

export const options = {
stages: [
{ duration: "30s", target: 10 }, // 30秒內緩慢增加至 10 個虛擬使用者
{ duration: "1m", target: 10 }, // 維持 10 個使用者 1 分鐘
{ duration: "30s", target: 0 }, // 30秒內減少至 0
],
};

設定 SLA 門檻範例

export const options = {
thresholds: {
http_req_duration: ["p(95)<500"], // 95% 的請求須在 500ms 內完成
http_req_failed: ["rate<0.01"], // 錯誤率須低於 1%
},
};

測試報告解讀

K6 測試完成後會產生詳細的效能指標報告,以下是主要指標的說明:

核心指標說明

指標名稱說明
vus虛擬使用者數量(Virtual Users)
iterations總執行次數
http_req_durationHTTP 請求耗時統計(平均值、最大值、百分位數)
http_req_failedHTTP 請求失敗比例
checks驗證條件通過率
iteration_duration單次完整 iteration 的執行時間
vus_max測試期間的最大虛擬使用者數

範例報告解讀

checks.....................: 100.00% ✓ 300  ✗ 0
http_req_duration..........: avg=180ms min=100ms max=350ms p(90)=300ms p(95)=320ms
http_req_failed............: 0.00% ✓ 0 ✗ 300
iterations.................: 2609 22.56/s
vus.......................: 2 min=1 max=100
vus_max...................: 100 min=100 max=100

重點觀察項目

  • 成功率checkshttp_req_failed 顯示請求成功率
  • 效能表現http_req_duration 的各項統計值
  • SLA 達成:是否符合預設的效能需求

更多指標詳情可參考:K6 官方指標文檔

如何從 K6 報告推估系統承載能力

雖然 K6 報告不會直接顯示「可承載 X 人同時在線」,但我們可以透過以下方法進行推估:

1. 分析虛擬使用者數量(vus)

vus 代表同時在線的模擬使用者數。若設定 vus: 100 且測試順利通過,表示系統至少可承受 100 人同時在線。

2. 評估回應時間表現

觀察 http_req_duration 的統計數據:

  • avg:平均回應時間
  • p(95):95% 請求的回應時間
  • max:最大回應時間

效能判斷標準

  • p(95) < 500ms:效能良好
  • p(95) < 1000ms:效能尚可
  • p(95) > 2000ms:可能存在效能瓶頸

3. 檢查錯誤率

http_req_failed 為 0% 表示所有請求都成功處理,系統運作穩定。

4. 計算 QPS(每秒查詢數)

QPS = iterations ÷ duration(秒)

根據 QPS 推算承載人數:

假設每位使用者每 2 秒發送 1 次請求
可承載人數 = QPS × 2

實際計算範例

假設測試結果如下:

vus: 100
duration: 60s
iterations: 10000
http_req_failed: 0.00%
http_req_duration (p95): 350ms

計算過程

  • QPS = 10000 ÷ 60 ≈ 167
  • 可承載人數 ≈ 167 × 2 = 約 334 人

結論:系統可以在 1 分鐘內穩定承載約 334 人同時操作,每人每 2 秒發送 1 次請求,且回應時間良好。

最佳實踐建議

測試策略規劃

  1. 由小到大:從小規模測試開始,逐步增加負載
  2. 多場景測試:涵蓋不同的使用者行為模式
  3. 定期執行:將效能測試整合至 CI/CD 流程

腳本撰寫技巧

  1. 適當的等待時間:使用 sleep() 模擬真實使用者行為
  2. 詳細的驗證條件:透過 check() 確保回應正確性
  3. 資料驅動測試:使用外部檔案提供測試資料

結果分析重點

  1. 關注趨勢變化:比較不同版本的效能表現
  2. 識別瓶頸點:分析回應時間分布找出問題
  3. 設定合理 SLA:根據業務需求制定效能標準

結語

K6 是一套現代化、開發者友善的效能測試工具。它具備以下優勢:

  • 簡單易用:搭配 Docker 可快速上手
  • 功能強大:支援複雜的測試邏輯與驗證
  • 程式化測試:使用熟悉的 JavaScript 語法
  • 豐富報告:提供詳細的效能指標分析
  • CI/CD 整合:容易整合至開發流程

無論是進行 API 單點測試,還是模擬複雜的高併發場景,K6 都能提供準確的數據指標,協助開發團隊做出更好的系統優化決策。

透過系統性的效能測試,我們不僅能確保產品品質,更能在系統上線前就發現並解決潛在問題,為使用者提供更穩定、更快速的服務體驗。

參考資料