負載測試與容量規劃簡介
預測未來是不可能的,但為其做好準備是必須的。容量規劃 (Capacity Planning) 是估計系統為滿足未來需求所需的資源(CPU、記憶體、儲存、網路)的過程。負載測試 (Load Testing) 則是透過模擬真實世界的流量對系統進行實際驗證,以確認這些估計是否準確。
對於 Professional Cloud Architect 來說,這是為了確保行銷活動(如超級盃廣告)不會導致客戶看到「404 找不到網站」的錯誤。
白話文解釋負載測試與容量規劃
比喻 1 — 餐廳的週五晚上
容量規劃就像餐廳老闆在繁忙的週五晚上之前,決定要擺放多少張桌子以及僱用多少名廚師。負載測試則像是僱用 100 名學生同時出現並點複雜的餐點,以觀察廚房是否能應對高峰,或者服務生是否開始掉盤子(系統崩潰)。
比喻 2 — 橋樑的載重限制
橋樑有「最大容量」。工程師透過將重型卡車駛上橋樑並測量其彎曲程度來進行負載測試。如果橋樑在達到目標重量(預期的峰值負載)之前就開始出現裂縫,你若不加固橋樑(垂直調整規模 Vertical Scaling),就得再建第二座橋(水平調整規模 Horizontal Scaling)。
比喻 3 — 水管系統
負載測試就像同時打開家裡所有的水龍頭,觀察水壓是否下降。如果水壓太低,說明你的「容量」不足。在雲端環境中,這可能意味著你的資料庫連接池太小或網路頻寬已飽和。
Google Cloud 對你可以使用的資源數量施加的硬性限制(例如:某個區域中的 CPU 數量)。管理配額是容量規劃的關鍵部分。
負載測試生命週期
- 定義目標: 目標是什麼?(例如:「10,000 個並行使用者,回應時間 <1s」)。
- 選擇工具:
- Locust: 基於 Python,易於編寫腳本,非常適合在 GKE 上進行分散式測試。
- JMeter: 基於 Java,功能極其豐富,是業界標準。
- 建立場景: 不要只是 ping 首頁。模擬真實的使用者旅程(登入 -> 搜尋 -> 加入購物車 -> 結帳)。
- 執行與監控: 在 Cloud Monitoring 中觀察 CPU、記憶體和資料庫延遲等指標。
- 分析與優化: 尋找瓶頸。是程式碼的問題嗎?資料庫?還是網路?
容量規劃最佳實踐
- 監控歷史趨勢: 使用 Cloud Monitoring 觀察過去 6 個月的流量成長情況,以預測未來的 6 個月。
- 為高峰做規劃: 不要只為「平均」的一天做規劃;要為「最高峰」的一天做規劃(例如:黑色星期五)。
- 主動管理配額: 在重大活動開始前數週檢查你的 GCP 配額。儘早申請增加配額,因為某些請求需要 Google 人員的手動審核。
- 驗證自動調整規模 (Auto-scaling): 在負載測試期間,確保你的受管理執行個體群組 (MIG) 和 GKE 叢集確實按照預期擴展。
架構師洞察: 在 PCA 考試中,如果一家公司正計畫「大規模全球發布」並希望確保成功,最佳答案通常涉及進行分散式負載測試並檢查所有目標區域的資源配額。 ::
在 GCE 與 GKE 上部署負載產生器 — k6、Locust、JMeter
負載產生器執行平台的選擇,會同時影響測試的真實度與成本。把產生器跑在 Google Cloud 內部(與待測系統同區域或跨區域)可以飽和 VPC 頻寬而不會被 ISP 節流;IAM 也讓 worker 能直接連到內部 Load Balancer。
工具比較
- k6(Go): 適合想用 JavaScript 撰寫測試腳本、有原生 Prometheus 輸出、且只想要單一靜態執行檔的工程師。要當成 Cloud Run Job 或 GKE
Job跑固定平行 pod 數量都很簡單。預設輸出 JSON / OpenTelemetry,透過 OTLP collector 可以乾淨地串流進 Cloud Monitoring。 - Locust(Python): 一級支援分散式模式,包含一個 master pod 與 N 個 worker pod — Google 參考架構
cloud.google.com/architecture/distributed-load-testing-using-gke就是把這個模型部署在 GKE Autopilot 上。 - JMeter(Java): 三者中最重,但協定廣度無人能敵(JMS、針對 Cloud SQL 的 JDBC、外掛 gRPC)。當你需要 50k 以上並行執行緒時,把 JMeter slave 部署到
c3-standard規格的 Managed Instance Group。
GKE 上的分散式模式
┌────────────────┐
│ Locust master │ (1 pod, web UI on :8089)
└────────┬───────┘
│ gRPC
┌────────────┼────────────┐
▼ ▼ ▼
Worker pod Worker pod Worker pod ... N 個 worker 分散於各節點
│ │ │
└────────────┴────────────┘
│ HTTPS
▼
待測系統(HTTPS LB → Cloud Run / GKE)
每個 worker pod 規格刻意調小(例如 500m CPU / 512Mi 記憶體),讓 Cluster Autoscaler 能把 worker 緊密打包。用 topologyKey: kubernetes.io/hostname 把 worker 分散到不同節點,避免單一節點變成瓶頸。多區域測試時,每個區域部署一個 Locust master,並在 Cloud Monitoring 用 target_pool 標籤把指標彙整起來。
把負載產生器跑在和待測系統不同的 VPC 專案裡。這樣可以保證 egress NAT 耗盡、配額耗盡或產生器端 CPU 飽和,都不會被誤判成應用程式故障。透過 Shared VPC 或 Private Service Connect 連線。
容量基準、headroom 與延遲百分位數
基準不是單一數字,而是在目前生產流量水位下擷取的穩態剖面。沒有基準,headroom 數學就只是猜測。
基準量測檢查清單
- 用 Cloud Monitoring MQL 從過去 7 天挑一段具代表性的 30 分鐘區間(例如
fetch k8s_container | metric 'kubernetes.io/container/cpu/core_usage_time')。 - 從 Cloud Load Balancer 的
https/total_latencies指標記錄 p50、p95、p99 延遲。 - 同一時間記錄 CPU 使用率、記憶體 working set、網路 egress、資料庫 active connection 數。
- 計算每個 pod / 每個 vCPU 的每秒請求數 — 這就是你的工作單位成本。
Headroom 數學
目標尖峰 P rps,基準是 p99 ≤ SLO 時每 vCPU 能扛 B rps:
所需 vCPU 數 = (P / B) × HeadroomFactor
HeadroomFactor: 1.3 適用於可預測工作負載(批次、內部 API)
1.5 適用於消費型尖峰流量
2.0 適用於黑色星期五等級的大型發布
Headroom 不是浪費,而是吸收「autoscaler 收到訊號」到「pod 就緒」這段時間差的緩衝。
為什麼 p99 比平均值重要
100 ms 的平均值可能藏著一個由 GC pause 或冷連線造成的 4 秒 p99。PCA 考題裡寫「系統平均達到 SLO」的選項通常是錯的 — 正確答案會把容量綁到百分位數 SLO(例如「在 5× 尖峰下 p99 < 300 ms」)。在 Cloud Monitoring 上設定 SLO burn-rate 警示,要綁到 Service 物件,而不是原始指標。
Little's Law 容量推算公式: 並行數 = 吞吐量 × 延遲。1,000 rps、p50 延遲 200 ms 時,預期會有約 200 個 in-flight 請求。Cloud Run 的 max-instances × concurrency 或 GKE pod replica 數要照這個算式來抓。
Cloud Monitoring 觀測性佈線與 autoscaling 反應曲線
沒有觀測性的負載測試,等同對自己做阻斷服務攻擊。在打第一個合成請求之前,先把下列項目接上:
必備儀表板
- 黃金訊號區塊: 請求速率、p50/p99 延遲、錯誤率、飽和度(CPU、記憶體、連線數)— 每項一張圖,時間軸對齊測試起點。
- Autoscaler 區塊: GKE 看
kubernetes.io/autoscaler/desired_replicas與current_replicas;MIG 看compute.googleapis.com/instance_group_manager/desired_size;Cloud Run 看run.googleapis.com/container/instance_count。 - 相依服務區塊: Cloud SQL 的
database/cpu/utilization、Spanner 的instance/cpu/utilization_by_priority、Memorystore 的redis.googleapis.com/stats/cpu_usage_time。
解讀 autoscaling 反應曲線
把 replica 數隨時間變化的曲線與請求速率疊圖。健康的曲線會出現:
- 延遲期(0-60 秒): Replica 平穩,流量上升中。延遲暫時上升。
- 擴張期(60-180 秒): Replica 線性上升;新 pod 進入
Ready狀態並開始吸收負載。p99 應該在 2-3 分鐘內回落。 - 穩態高原: Replica 穩定在
target_cpu_utilization(HPA 預設 60-70 %)。 - 縮減期: 流量停止後,GKE HPA 會等 5 分鐘(
--horizontal-pod-autoscaler-downscale-stabilization)才移除 pod,以避免抖動。
請用斜坡式 ramp,不要用 step 函數。k6 的 stages 區塊(例如 5 分鐘內 0→500 rps,維持 10 分鐘,再 5 分鐘 500→2,000)可以揭露 autoscaler 的反應時間。1 秒內從 0 → 2,000 rps 的階梯函數只能證明「冷系統會壞」 — 這你早就知道了。
常見瓶頸特徵
- Replica 平穩但延遲上升: 撞到配額,或 HPA 指標選錯了(真正瓶頸是 RPS 但你用 CPU 在縮放)。
- Replica 每 5 分鐘震盪一次: Downscale stabilization 太積極 — 把
--horizontal-pod-autoscaler-downscale-stabilization調大。 - 延遲 p99 以固定間隔跳動: Cloud SQL 連線風暴或 JVM GC — 改用 Cloud SQL connector 加連線池,或加掛 PgBouncer sidecar。
資料庫負載測試模式 — Spanner 與 BigQuery
無狀態層會線性擴展。有狀態層不會 — 而且通常是負載測試中第一個倒下的元件。
Cloud Spanner — 節點規模與 hotspot
Spanner 是按節點(或 100/1000 PU 分數單位)供應。每個節點在 p99 ≤ 10 ms 下大致可以撐起 10,000 QPS 的 point read 或 2,000 QPS 的 write。負載測試策略:
- 跑一個混合讀寫工作負載,目標 CPU 65 %;這是 Google 建議的穩態水位。Spanner 會自動 split,但 split 穩定下來需要幾分鐘。
- 測試期間開 Key Visualizer 找 hotspot。明顯的垂直亮帶 = 單調遞增主鍵(timestamp、sequence)= 改寫成 hash prefix 或 UUIDv4。
- 驗證 client 端 session pool size = 100 × 節點數。Pool 太小會表現成 client-side queueing,而不是 Spanner CPU 飆高。
不要用單一主鍵範圍(例如所有寫入都打到 user_id = 1)來壓測 Spanner。Spanner 的分散式架構會懲罰 hotspot — 整個 split 會被序列化執行:你會看到 instance 層 CPU 才 5 %,但某個 split 是 100 %。儀表板看起來健康,應用程式卻 timeout。永遠要把 key space 隨機化。
BigQuery — slot 與並行數
BigQuery 的容量來自 slot。兩種購買模式在負載下的行為差異極大:
| 模式 | 負載下行為 | 何時要壓測 |
|---|---|---|
| On-demand | 每專案最多 2,000 slot,共享池,slot 可得性無 SLA | 對延遲容忍度高的尖峰分析查詢 |
| Editions(Standard/Enterprise/Plus) | 保留 slot,可選 autoscaler 到 max_slots |
生產儀表板、排程 ETL |
針對一個要服務 1,000 名並行分析師的發布儀表板,用相同的 query mix 跑 1×、2×、5× 預期並行數,並觀察 bigquery.googleapis.com/slots/total_allocated_for_reservation 與 query/execution_times。如果查詢排隊超出延遲預算,就買有 autoscaler 的專屬 reservation,或把結果預先物化到 BigQuery BI Engine。
運算層 autoscaler 規模設定 — GKE HPA、Cluster Autoscaler、Cloud Run concurrency
Autoscaler 的好壞,取決於你怎麼設定。三個旋鈕最關鍵。
GKE — HPA 加 Cluster Autoscaler
Horizontal Pod Autoscaler 縮放pod;Cluster Autoscaler 縮放節點。兩者必須一起調:
# HPA 同時用 CPU 與自訂指標縮放 pod
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
minReplicas: 3
maxReplicas: 200
metrics:
- type: Resource
resource: { name: cpu, target: { type: Utilization, averageUtilization: 60 } }
- type: Pods
pods: { metric: { name: http_requests_per_second }, target: { type: AverageValue, averageValue: "100" } }
Cluster Autoscaler 設定 --scale-down-unneeded-time=10m,並啟用 node auto-provisioning,這樣 autoscaler 可以在測試中即時建立合適機型的新 node pool。GKE Autopilot 會自動處理,但 pod 層級的 resource requests 必須準確,否則 Autopilot 會超量供應,帳單暴增。
Cloud Run — concurrency 調校
Cloud Run 是按 active container instance 縮放,不是按 CPU。決策變數是 --concurrency(每個 instance 同時處理的請求數,預設 80,上限 1000):
- CPU bound 的 JSON API:
--concurrency=20到40— 並行請求太多會互相搶 CPU。 - I/O bound 的 proxy 或 LLM 前端:
--concurrency=200到500— 大多數執行緒都在等後端。 - 對 cold start 敏感的:設
--min-instances=N,讓 N 覆蓋基準流量,第一位使用者就不用付 cold start 代價。
負載測試會浮現最佳值:在固定 RPS 下,把 p99 延遲對 --concurrency 作圖,挑出能讓 p99 守住 SLO 的最高 concurrency。這常常能讓 Cloud Run 帳單減半。
Cloud Run 的 max-instances 上限是硬性配額,不是建議值。如果負載測試尖峰打到 800 個 instance 而你 max-instances=500,Cloud Run 會直接回 HTTP 429,不會自動提升上限。永遠把 max-instances 設為預期尖峰的 2 倍,並在發布前數週申請配額提升。
FAQ — 負載測試與容量規劃
Q1. 我應該針對生產環境進行負載測試嗎?
理想情況下,不應該。你應該使用一個具備相同配置和資料規模的類生產預備環境 (Staging environment)。如果你必須在生產環境中進行測試,請在非尖峰時段進行,並制定嚴格的「停止」協議。
Q2. 「負載測試」與「壓力測試 (Stress Testing)」有什麼區別?
負載測試檢查系統是否能處理預期的高峰。壓力測試則是將系統推向極限直到崩潰,以找出絕對限制並觀察其故障方式(例如:是直接當機還是只是變慢?)。
Q3. 在負載測試期間如何處理資料庫瓶頸?
如果資料庫是瓶頸,請考慮針對讀取密集型工作負載使用唯讀副本 (Read Replicas)、升級到更大的執行個體(垂直調整規模),或切換到可全球擴展的資料庫(如 Cloud Spanner)。
Q4. 我可以使用 Google Cloud 來產生測試負載嗎?
可以。常見的模式是在 GKE 上部署 Locust 工作節點叢集。這讓你能夠從 Google 網路內部(或從多個區域)產生大量流量來測試你的應用程式。
Q5. 在容量規劃背景下的「預熱 (Warm-up)」是什麼?
某些服務(如 Cloud Functions 或 Cloud Run)可能會遇到「冷啟動 (Cold Starts)」。此外,資料庫快取在達到峰值效能之前也需要用資料進行「預熱」。確保你的負載測試包含預熱階段,以獲得真實的結果。