返回首頁高併發

高併發測試指南:JMeter、Locust、k6 工具比較與實作教學|2025

17 min 分鐘閱讀
#高併發測試#壓力測試#JMeter#Locust#k6#wrk#效能測試#CI/CD#容量規劃

高併發測試指南:JMeter、Locust、k6 工具比較與實作

前言:不測試就上線,等於在賭博

「上線前測過了嗎?」 「測了,功能都正常。」 「壓測呢?」 「……」

然後大促當天,系統掛了。

功能測試只能確保「能用」,壓力測試才能確保「撐得住」。高併發系統不做壓測就上線,跟蒙眼開車一樣危險。

本文將帶你從「為什麼要壓測」開始,比較四大壓測工具,教你撰寫壓測腳本、解讀測試指標,最後介紹如何整合 CI/CD 做持續壓測。

如果你還不熟悉高併發的基本概念,建議先閱讀高併發是什麼?完整指南


一、為什麼需要壓力測試

1.1 找出系統瓶頸

壓測能暴露系統的弱點:

  • 資料庫連線數不夠
  • 某個 API 特別慢
  • 記憶體洩漏
  • 網路頻寬瓶頸

這些問題在低流量時不會出現,壓測才能找出來。

1.2 驗證架構設計

你的架構設計能撐多少 QPS?理論計算不準,實測才知道。

  • 讀寫分離有效嗎?
  • 快取命中率夠高嗎?
  • 負載均衡分配均勻嗎?

壓測是架構設計的驗證手段。詳細的架構設計原則,請參考高併發架構設計

1.3 容量規劃依據

大促預估有 100 萬用戶同時上線。需要開多少台機器?

沒有壓測數據,只能靠猜。有了壓測數據,才能精準規劃。

1.4 建立 Baseline

壓測不是一次性的。每次發布新版本,效能可能會變。

定期壓測,建立效能基準線(Baseline)。如果新版本效能下降,馬上能發現。


二、壓測工具比較

市面上壓測工具很多,這裡介紹四個最常用的。

2.1 Apache JMeter

簡介:Java 編寫的老牌壓測工具,功能最全面。

優點

  • GUI 介面,上手容易
  • 支援多種協議(HTTP、JDBC、LDAP、JMS)
  • 插件生態豐富
  • 分散式測試支援

缺點

  • Java 編寫,資源佔用較高
  • GUI 在大型測試時會卡
  • 腳本是 XML,不好維護

適合

  • 需要測試多種協議
  • 團隊不熟悉程式語言
  • 企業級應用

2.2 Locust

簡介:Python 編寫的現代壓測工具。

優點

  • Python 寫腳本,彈性高
  • 輕量,資源佔用少
  • 分散式架構原生支援
  • Web UI 即時監控

缺點

  • 只支援 HTTP
  • Python 寫法有學習曲線
  • 極端效能場景稍弱

適合

  • Python 開發者
  • Web API 測試
  • 需要複雜測試邏輯

2.3 k6

簡介:用 JavaScript 撰寫腳本的現代壓測工具,由 Grafana 維護。

優點

  • Go 編寫,效能極佳
  • JavaScript/TypeScript 寫腳本
  • 開發者體驗好(CLI first)
  • 雲端服務整合(Grafana Cloud)

缺點

  • 只支援 HTTP/WebSocket/gRPC
  • 相對較新,社群較小
  • 進階功能需要付費版

適合

  • 前端/全端開發者
  • DevOps 團隊
  • 需要整合 CI/CD

2.4 wrk

簡介:C 語言編寫的極簡壓測工具。

優點

  • 極輕量,資源佔用最少
  • 單機就能產生極高 QPS
  • Lua 腳本擴展

缺點

  • 功能簡單,只測 HTTP
  • 沒有 GUI
  • 報告功能弱

適合

  • 快速基準測試
  • 對效能要求極高的場景
  • 簡單的 API 測試

工具比較表

工具語言腳本GUI分散式資源佔用適合場景
JMeterJavaXML支援企業級、多協議
LocustPythonPythonWeb原生Python 團隊、Web API
k6GoJavaScript付費版DevOps、CI/CD
wrkCLua極低快速基準測試

插圖 1:壓測工具使用場景對比

三、測試指標解讀

跑完壓測,看到一堆數字。這些數字代表什麼?

3.1 吞吐量指標

QPS(Queries Per Second)

每秒查詢數。對於 Web API,這是最常用的吞吐量指標。

  • 100 QPS:小型網站
  • 1,000 QPS:中型網站
  • 10,000+ QPS:大型網站

TPS(Transactions Per Second)

每秒交易數。一筆交易可能包含多個查詢。

例如:一次購買 = 查商品 + 扣庫存 + 建訂單 + 扣款 = 1 TPS,但可能是 4 QPS。

RPS(Requests Per Second)

每秒請求數。通常和 QPS 同義。

3.2 回應時間指標

平均回應時間(Avg)

所有請求回應時間的平均值。看起來直觀,但容易被極端值影響。

P50 / P95 / P99

百分位數(Percentile),更能反映真實體驗。

  • P50:50% 的請求在這個時間內完成(中位數)
  • P95:95% 的請求在這個時間內完成
  • P99:99% 的請求在這個時間內完成

為什麼關注 P99?因為 1% 的慢請求可能影響大量用戶。

舉例

  • 平均回應時間:100ms
  • P50:80ms
  • P95:200ms
  • P99:1000ms

這表示雖然平均看起來還好,但有 1% 的用戶要等 1 秒以上。這 1% 可能就是你的 VIP 客戶。

3.3 錯誤指標

錯誤率(Error Rate)

請求失敗的比例。包括 HTTP 5xx 錯誤、超時、連線失敗。

  • < 0.1%:優秀
  • 0.1% - 1%:可接受
  • 1%:需要關注

超時率(Timeout Rate)

請求超時的比例。通常設定 30 秒或 60 秒超時。

3.4 資源指標

壓測時要同時監控服務端資源:

  • CPU 使用率:超過 80% 要警覺
  • 記憶體使用率:注意有沒有持續上升(洩漏)
  • 網路 I/O:頻寬有沒有打滿
  • 磁碟 I/O:有沒有大量讀寫

這些指標幫你定位瓶頸在哪裡。


四、壓測腳本撰寫教學

光說不練假把式。這裡示範三種工具的實際寫法。

4.1 JMeter 範例

JMeter 主要用 GUI 設計測試計畫,核心元件:

  1. Thread Group:設定並發用戶數
  2. HTTP Request:定義要測試的 API
  3. Listener:收集和顯示結果

<ThreadGroup>
  <numThreads>100</numThreads>
  <rampTime>10</rampTime>
  <duration>60</duration>
</ThreadGroup>

<HTTPSampler>
  <domain>api.example.com</domain>
  <path>/products</path>
  <method>GET</method>
</HTTPSampler>

實際操作流程:

  1. 開啟 JMeter GUI
  2. 新增 Thread Group,設定 100 用戶、10 秒 ramp-up、跑 60 秒
  3. 新增 HTTP Request,填入 API 資訊
  4. 新增 Summary Report 查看結果
  5. 點擊運行

4.2 Locust 範例

Locust 用 Python 寫腳本,彈性很高。

# locustfile.py
from locust import HttpUser, task, between

class WebUser(HttpUser):
    # 每次請求間隔 1-3 秒
    wait_time = between(1, 3)

    @task(3)  # 權重 3,執行頻率較高
    def get_products(self):
        self.client.get("/products")

    @task(1)  # 權重 1
    def get_product_detail(self):
        product_id = 123
        self.client.get(f"/products/{product_id}")

    @task(1)
    def create_order(self):
        self.client.post("/orders", json={
            "product_id": 123,
            "quantity": 1
        })

    def on_start(self):
        # 每個用戶啟動時執行(例如登入)
        self.client.post("/login", json={
            "username": "test",
            "password": "test123"
        })

運行指令:

# 啟動 Locust Web UI
locust -f locustfile.py --host=https://api.example.com

# 或直接命令列運行
locust -f locustfile.py --host=https://api.example.com \
    --users 100 --spawn-rate 10 --run-time 60s --headless

想深入了解 Python 處理高併發的方式,請參考Python vs Golang 高併發

4.3 k6 範例

k6 用 JavaScript 寫腳本,對前端開發者友好。

// script.js
import http from 'k6/http';
import { check, sleep } from 'k6';

// 測試設定
export const options = {
  stages: [
    { duration: '10s', target: 50 },   // 10 秒內爬升到 50 用戶
    { duration: '30s', target: 100 },  // 維持 100 用戶 30 秒
    { duration: '10s', target: 0 },    // 10 秒內降到 0
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'],  // 95% 請求要在 500ms 內
    http_req_failed: ['rate<0.01'],    // 錯誤率 < 1%
  },
};

export default function () {
  // 取得商品列表
  const productsRes = http.get('https://api.example.com/products');
  check(productsRes, {
    'products status is 200': (r) => r.status === 200,
  });

  sleep(1);

  // 取得商品詳情
  const detailRes = http.get('https://api.example.com/products/123');
  check(detailRes, {
    'detail status is 200': (r) => r.status === 200,
    'detail has name': (r) => r.json('name') !== undefined,
  });

  sleep(1);

  // 建立訂單
  const orderRes = http.post(
    'https://api.example.com/orders',
    JSON.stringify({ product_id: 123, quantity: 1 }),
    { headers: { 'Content-Type': 'application/json' } }
  );
  check(orderRes, {
    'order created': (r) => r.status === 201,
  });

  sleep(1);
}

運行指令:

k6 run script.js

五、CI/CD 整合持續壓測

壓測不應該是一次性的。整合到 CI/CD,每次發布都自動跑。

5.1 為什麼要持續壓測

  • 新程式碼可能引入效能問題
  • 及早發現,避免上線後才出事
  • 建立效能基準線,追蹤趨勢
  • 防止效能迴歸

5.2 整合方式

GitHub Actions + k6 範例

# .github/workflows/load-test.yml
name: Load Test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  load-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install k6
        run: |
          sudo gpg -k
          sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
          echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
          sudo apt-get update
          sudo apt-get install k6

      - name: Run load test
        run: k6 run --out json=results.json tests/load-test.js

      - name: Check thresholds
        run: |
          if grep -q '"thresholds":{"http_req_duration":\[{"ok":false' results.json; then
            echo "Performance threshold failed!"
            exit 1
          fi

5.3 測試門檻設定

設定明確的門檻,自動判斷通過/失敗:

// k6 thresholds
export const options = {
  thresholds: {
    http_req_duration: ['p(95)<500', 'p(99)<1000'],
    http_req_failed: ['rate<0.01'],
    http_reqs: ['rate>100'],  // 至少 100 QPS
  },
};

插圖 2:CI/CD 壓測流程圖

六、容量規劃方法

壓測數據怎麼用來做容量規劃?

6.1 估算公式

步驟 1:估算預期流量

預期 QPS = 日活用戶 × 人均請求數 ÷ 活躍秒數

例如:

  • 日活用戶:100,000
  • 人均請求數:50 次
  • 活躍時間:8 小時 = 28,800 秒
  • 預期 QPS = 100,000 × 50 ÷ 28,800 ≈ 174

步驟 2:考慮峰值

峰值通常是平均值的 2-5 倍。

峰值 QPS = 預期 QPS × 峰值係數

假設峰值是平均的 3 倍:

  • 峰值 QPS = 174 × 3 ≈ 522

6.2 安全係數

不要把系統跑到極限。預留空間給突發狀況。

目標容量 = 峰值 QPS × 安全係數

安全係數通常取 1.5-2 倍:

  • 目標容量 = 522 × 1.5 ≈ 783 QPS

6.3 擴展計畫

知道目標容量後,用壓測數據反推需要多少資源。

假設壓測結果:

  • 單台 4C8G 機器能扛 200 QPS
  • 目標容量 783 QPS
  • 需要機器數 = 783 ÷ 200 ≈ 4 台

考慮高可用(N+1 冗餘),至少需要 5 台。


不確定系統能撐多少流量?預約壓測諮詢,讓專家幫你規劃容量。


七、常見問題排查

壓測時遇到問題怎麼辦?

7.1 壓測端瓶頸

症狀:壓測機 CPU 飆高,但服務端還很閒。

原因:壓測工具本身成為瓶頸。JMeter 資源佔用高,單機產生的 QPS 有限。

解法

  • 換輕量工具(k6、wrk)
  • 分散式壓測(多台壓測機)
  • 關閉不必要的監控插件

7.2 網路瓶頸

症狀:網路流量打滿,但 CPU/記憶體都還好。

原因:頻寬不夠,或網路設備成為瓶頸。

解法

  • 檢查壓測機和服務端之間的頻寬
  • 壓測機放到同一個內網
  • 使用雲端壓測服務

7.3 應用瓶頸

症狀:應用 CPU 飆高,回應變慢。

原因:程式碼效能問題、資源競爭、執行緒耗盡。

排查方向

  • Profiling 找出熱點函數
  • 檢查是否有鎖競爭
  • 檢查執行緒池/連線池設定

7.4 資源洩漏

症狀:跑一段時間後效能驟降,記憶體持續上升。

原因:記憶體洩漏、連線洩漏、檔案描述符洩漏。

排查方向

  • 用 APM 工具追蹤記憶體使用
  • 檢查連線有沒有正確關閉
  • 看系統的 open file 數量

常見問題 FAQ

Q1: 壓測應該在生產環境還是測試環境做?

測試環境做初步驗證,生產環境做最終確認。但生產環境壓測要小心,建議在低峰時段、有降級方案的情況下進行。

Q2: 壓測要跑多久?

至少 5-10 分鐘。太短會錯過記憶體洩漏等問題。穩定性測試可以跑幾小時甚至一天。

Q3: 怎麼模擬真實用戶行為?

不是所有用戶都在同一秒發請求。用 ramp-up 模擬用戶逐漸加入,用 think time 模擬用戶思考時間,用不同權重模擬不同行為比例。

Q4: 分散式壓測怎麼做?

JMeter 有 remote testing,Locust 原生支援分散式,k6 付費版有 Cloud 功能。或者手動在多台機器跑,最後合併結果。

Q5: 壓測結果不穩定怎麼辦?

多跑幾次取平均。排除環境干擾(其他程式、網路波動)。確保每次測試的起始狀態一致(重啟服務、清空快取)。


結論:壓測是高併發系統的必修課

沒有經過壓測的系統,就像沒有經過考驗的士兵。

本文重點回顧

  1. 壓測能找出瓶頸、驗證架構、規劃容量
  2. JMeter 功能全、Locust Python 友好、k6 現代化、wrk 極簡
  3. 關注 P99 回應時間,而不只是平均值
  4. 錯誤率和資源指標同樣重要
  5. 整合 CI/CD 做持續壓測
  6. 容量規劃要考慮峰值和安全係數

延伸閱讀:


架構設計需要第二意見?

好的壓測能預防災難。如果你正在:

  • 準備大促,擔心系統撐不住
  • 想知道系統的效能極限在哪
  • 需要規劃容量和預算

預約架構諮詢,讓我們一起檢視你的系統效能。

所有諮詢內容完全保密,沒有銷售壓力。


參考資料

  1. Apache JMeter 官方文檔(2024)
  2. Locust 官方文檔(2024)
  3. k6 官方文檔(2024)
  4. Google,《Site Reliability Engineering》(2016)
  5. AWS,《Performance Testing Best Practices》(2024)

需要專業的雲端建議?

無論您正在評估雲平台、優化現有架構,或尋找節費方案,我們都能提供協助

預約免費諮詢

相關文章