結論先講
功能測試回答「能不能動」,壓力測試回答「能撐多少人」。 兩個問題的答案都是「Yes」,系統才算準備好上線。大部分團隊只回答了第一個問題,然後在上線當天用真實用戶回答第二個。
一個你可能經歷過的場景
行銷團隊花了三個月準備大促活動。開發團隊準時交付,QA 全部通過,PM 信心滿滿地按下部署按鈕。
活動開始後 15 分鐘:
- API response time 從 200ms 飆到 8 秒
- 資料庫連線池耗盡,新請求全部排隊
- 錯誤率從 0% 跳到 40%
- 客服電話被打爆,社群開始罵
工程團隊緊急加機器、調參數、重啟服務,折騰了兩個小時才穩定。事後覆盤,大家都知道原因:沒做過壓力測試。
這不是假設情境。這是大多數中型團隊遲早會遇到的事。
功能測試和壓力測試的根本差異
| 維度 | 功能測試 | 壓力測試 |
|---|---|---|
| 問的問題 | 這個 API 回傳的結果對不對? | 100 個人同時打這個 API 會怎樣? |
| 測試條件 | 單一請求、理想環境 | 併發請求、資源競爭 |
| 發現的問題 | 邏輯錯誤、驗證遺漏 | 記憶體洩漏、連線池耗盡、CPU 阻塞 |
| 失敗的表現 | 回傳錯誤結果 | 回傳正確結果但要等 10 秒 |
| 什麼時候壞 | 開發階段就能發現 | 上線後流量上來才爆 |
關鍵差異在於:功能測試是在真空中測試邏輯,壓力測試是在資源競爭中測試行為。
一個 API 在單一請求時可以完美運作。但當 500 個請求同時進來,搶同一個資料庫連線池、搶同一顆 CPU 的運算時間、搶同一塊記憶體,行為會完全不同。
壓力下才會出現的問題
這些問題在功能測試中永遠不會被發現:
1. Bcrypt 阻塞 CPU
單一請求:bcrypt.hash() 花 80ms,沒感覺
50 個併發:每個 bcrypt 都在排隊等 CPU,response time 飆到 3 秒
Bcrypt 是 CPU-bound 操作,Node.js 的 single-thread 模型讓它在高併發時特別痛苦。這是我們在 9 框架壓測中發現的共同瓶頸——功能測試不會告訴你這件事。
2. 資料庫連線池耗盡
Pool Max: 20
併發請求: 100
結果: 80 個請求在排隊等連線,timeout 後返回 500
3. 記憶體洩漏在高流量下加速
單一請求:每次請求洩漏 1KB,一天 1000 個請求,漏 1MB,沒人在意
高流量:每秒 100 個請求,一小時漏 360MB,OOM Kill
4. 競態條件(Race Condition)
用戶 A 和用戶 B 同時購買最後一件商品
單一請求測試:A 買成功
併發測試:A 和 B 都買成功,庫存變成 -1
壓力測試的類型
不是所有壓力測試都一樣。根據你想回答的問題,選擇不同的測試類型:
Load Test(負載測試)
在預期的正常流量下,系統表現如何?
- VU(虛擬用戶): 預期流量的 1-2 倍
- 持續時間: 10-30 分鐘
- 用途: 確認日常負載下的 response time 和 error rate
Stress Test(壓力測試)
系統的極限在哪裡?超過極限後會怎樣?
- VU: 逐步增加直到系統崩潰
- 持續時間: 每個階段 5 分鐘
- 用途: 找出系統的 breaking point 和降級行為
Spike Test(尖峰測試)
流量突然暴增 10 倍,系統能撐住嗎?
- VU: 瞬間從正常流量跳到 10 倍
- 持續時間: 尖峰維持 1-5 分鐘
- 用途: 模擬大促開始、新聞曝光等突發流量
Soak Test(耐久測試)
系統跑 24 小時會不會慢慢劣化?
- VU: 正常流量
- 持續時間: 4-24 小時
- 用途: 發現記憶體洩漏、連線洩漏、日誌膨脹
什麼時候該做壓力測試
不是每個專案都需要壓力測試。 判斷標準很簡單:
一定要做
- 面向消費者的 API(電商、社群、金融)
- 有明確的流量高峰(大促、開學季、報稅季)
- SLA 有明確的 response time 承諾
- 微服務架構(一個服務慢會拖垮整條鏈路)
- 付費的基礎設施(你需要知道要買多少資源)
可以不做
- 內部工具、後台管理系統(同時用的人不超過 10 個)
- 一次性的資料處理腳本
- 開發中的原型、MVP
做了但做錯的常見情況
- 只測單一 API: 真實流量是多個 API 同時被打。用戶登入的同時在查商品、加購物車
- 在本地測: 本地跑壓測的結果和生產環境差十萬八千里
- 只看平均值: P99 10 秒但平均 200ms,平均值什麼都看不出來
- 測完不留記錄: 下次上線前又從零開始猜「應該撐得住吧」
壓力測試的投資報酬率
壓力測試不是免費的。它需要:
- 時間: 設計測試場景、寫腳本、跑測試、分析結果
- 基礎設施: 測試環境、壓測工具、監控工具
- 專業知識: 看懂結果並做出正確決策
但比起「上線後才發現撐不住」的成本:
| 成本項目 | 沒做壓測 | 有做壓測 |
|---|---|---|
| 發現問題的時機 | 上線後,用戶在罵 | 上線前,QA 環境 |
| 修復的壓力 | 極高,邊修邊接客服電話 | 低,排進正常開發週期 |
| 信譽損失 | 用戶流失、媒體報導 | 無 |
| 修復成本 | 緊急加機器 + 通宵加班 | 正常工時內調整 |
壓力測試的核心價值不是「讓系統變快」,而是「在上線前就知道極限在哪裡」。 知道極限,你就能做決策:加機器、調架構、或是告訴行銷「最多同時 5000 人」。
為什麼會有這個系列
先講背景。我們原本是單體架構,一個 FastAPI 服務搞定所有事。後來拆成微服務——Auth Service、Post Service、File Service 各自獨立。拆完之後才發現:單體時代「一個服務慢就是慢」,微服務時代「一個服務慢,整條鏈路一起死」。
一個 Auth Service 的 bcrypt 佔滿 CPU,Post Service 和 File Service 的請求全部卡在等 JWT 驗證。用戶看到的不是「登入慢」,是「整個網站都慢」。
這才意識到:微服務不是拆完就沒事,你得知道每個服務的極限在哪。壓力測試從「有空再做」變成「不做不行」。
所以我們蓋了一個壓測平台,拿 9 個後端框架(Express-TS、Express-JS、Django、FastAPI、Go、NestJS、Laravel、Spring Boot、.NET Core)在完全相同的條件下比較。這個系列就是從搭平台到跑數據到做決策的完整紀錄。
這個系列的結構
40 篇文章,分成 10 個 Part。你可以從任何一個 Part 開始讀,但按順序會有完整的敘事線。
Part 1 — 方法論(5 篇):為什麼做、怎麼做、工具怎麼用。不需要任何數據就能讀。
Part 2 — Bcrypt 專題(3 篇):我們最大的發現——9 個框架的共同天花板竟然是同一個東西。
Part 3 — CRUD 壓測(6 篇):第一場實戰。每個框架各一篇,講清楚它為什麼快、為什麼慢。
Part 4 — 混合場景(5 篇):排名大翻盤。讀多寫少的真實場景下,倒數第二名變第一名。
Part 5 — 檔案上傳(4 篇):從 CPU-bound 轉到 I/O-bound,Streaming vs Buffering 的哲學之爭。
Part 6 — ORM、DB 與微服務(5 篇):框架之下的東西。連線池、N+1、以及從單體拆微服務踩的坑。
Part 7 — 規則引擎(3 篇):189 份報告不可能人看。讓機器自動判斷瓶頸。
Part 8 — 架構決策(3 篇):最快的框架不是最適合的框架。怎麼把數據變成真正的選型依據。
Part 9 — WebSocket / SSE(4 篇):持久連線是另一個世界。不看 RPS,看能撐幾萬條連線。
Part 10 — 回顧(2 篇):回到起點。壓測教會我們的事,以及如果重來一次會怎麼設計。
下一篇
壓測平台架構設計 — 用 k6 + InfluxDB + Grafana + 自建規則引擎,搭建一個可重複使用的壓測平台。
本系列文章
完整 68 篇目錄見 系列首頁
→ 下一篇:壓測平台架構設計:從 k6 腳本到全自動分析