結論先講

功能測試回答「能不能動」,壓力測試回答「能撐多少人」。 兩個問題的答案都是「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 腳本到全自動分析