問題

我在自己的壓測平台上壓 12 個後端框架,breaking point 定義成「某一級的 Err% 超過 50%」。結果 laravel、spring-boot、rails 在 1000 VU 時都是「未達 breaking point」,看起來比 go、nestjs 還能撐。

可是同一級它們的平均回應時間約 30 秒,Check% 掉到 51%。

我一開始懷疑是「請求逾時了,卻沒被算成失敗」。回頭查平台存下來的原始指標,答案剛好相反:請求真的成功了,只是排了很久。

實測數字

以下是 2026-10 在我自己的壓測平台重測的結果。情境是 user-crud,VU 依序 10 → 50 → 100 → 500 → 1000,每級 30 秒,每個框架的容器限制 2 CPU/2 GB。

1000 VU 那一級:

  • laravel:註冊 2xx 999/1000,http_req_duration 最大 50.6 秒,整級完成 1194 個請求,Err 0.1%
  • spring-boot:註冊 2xx 999/999,最大 59.6 秒,整級 1025 個請求,Err 0.0%
  • rails:註冊 2xx 515/515,最大 59.9 秒,整級 517 個請求,Err 0.0%
  • go(對照):請求中位數 30189 ms、最大 33460 ms,Err 76.6%,被判定為 breaking point

判斷方式:用已存的資料,不用重跑

  1. 看那一級的 2xx 成功數:三家的註冊幾乎全過。
  2. 看最大延遲:50~60 秒,沒碰到 k6 單一請求的預設逾時。k6 的 timeout 參數預設是 60 秒(k6 文件:Params),rails 最慢的 59.9 秒剛好沒撞到。所以 Err 0% 是真的,不是逾時被漏算。
  3. 看整級請求數:30 秒只完成 517~1194 個請求,等於每個 VU 大約只做完一次註冊。換算 RPS 只有 8.6~19.8——吞吐量已經崩了。
  4. Check% 51% 是哪一項沒過:是「回應 < 2s」那項延遲檢查,不是錯誤。

為什麼會這樣:撐不住有兩種長相

類型撐不住時錯誤率只看錯誤率的判定
回錯型(go 等)碰到單一請求處理上限(我的實作預設 30 秒),回 504高有 breaking point
排隊型(laravel、spring-boot、rails)請求在佇列裡等,慢,但最後成功≈ 0「撐得住」

go 那組數字的中位數剛好卡在 30 秒附近,對得上「處理上限 30 秒、逾時回 504」的設計。

只看錯誤率,快速回錯的框架反而被判得比較差。可是回錯其實是比較健康的行為:用戶端能早點知道失敗,可以重試或降級;排隊型讓使用者乾等 50 秒,最後才拿到一個早就沒意義的成功。

排隊這件事在 PHP 這邊有很具體的機制:PHP-FPM 的 pm.max_children 限制同時處理的請求數,超過的就排隊等 process 空出來(細節見第 14 篇 Laravel CRUD)。

還沒查證的部分

laravel 和 spring-boot 的實作裡都有請求逾時的中介層,卻還是拖到 50~60 秒才回。我的推測是:中介層的計時從「開始處理」才起算,沒有包含請求在 nginx/php-fpm 或 Tomcat 佇列裡等待的時間。rails 那邊我只找到逾時的錯誤碼,沒找到對應的中介層,可能根本沒實作。(推測/未查證:以上三點都還沒有實際驗證)

如果推測成立,代表「同一條逾時規則」落地到不同框架後,高負載下的行為會完全不同——值得逐家驗一次「佇列等待時間有沒有算進逾時」。

解法:排名改看最高 RPS

排名不看 breaking point,改看「最高 RPS(在幾 VU 達到)」與「固定 VU 下的延遲」。 breaking point 保留,但標明「只看錯誤率」。

最高 RPS 對兩型都公平:不管是回錯還是排隊,吞吐量都會在飽和點附近封頂。

我沒選「錯誤率或 P95 超過門檻就算崩」這種新定義。原因是大部分框架在 100 VU 時 P95 就已經 3~11 秒,結果會對門檻非常敏感,而且門檻本身又得另外訂、另外吵。

這也牽動到舊結論

系列早期那份 CRUD 排名就是只看錯誤率得出的,「Go 最穩定」這類說法也是同一個盲點。第 9 篇 CRUD 總覽已經加了 2026-10 的更正說明:排名會改用「最高成功 RPS」與「固定 VU 下的延遲」重跑校正,重跑完之前那張表請當參考。這篇是那則更正背後的原因,不代表舊排名已經重跑。

第 5 篇 Grafana 儀表板的「0% Error ≠ 沒問題」一節講的是同一件事的看圖版:Error 0% 要配 RPS 一起看,RPS 很低就是堵塞的假象。

怎麼預防再次發生

  • 壓測報告的排名欄位用「最高 RPS(在幾 VU)」,breaking point 只當註記。
  • 看到「錯誤率 0%,但平均延遲接近逾時值」就是排隊型的訊號,不要寫成「最穩定」。
  • 同類「只看錯誤率」得出的舊結論,都要回頭檢查一次。
  • 判讀批次壓測結果時,不只錯誤率會騙人,退出碼也會:見批次驅動的退出碼會說謊。
  • 回錯型 vs 排隊型
  • 最高成功 RPS
  • k6 預設逾時 60 秒