加機器能解決的問題其實不多。真正撐不住流量的系統,通常敗在單點資料庫、同步呼叫鏈太長、以及沒人看得懂正在發生什麼事。這三件事都不是水平擴展能救的。
設計大流量架構的核心,不是「怎麼變快」,而是「哪些請求可以不做、可以晚做、可以只做一次」。想清楚這件事,後面的技術選型才有意義。
快取、佇列、分片:先想清楚要解什麼
快取的重點不是快,是擋。 快取真正的價值在於讓後端資料庫不必承擔每一個讀請求。但快取用錯會製造更大問題:熱點 key 打爆單一節點、快取雪崩讓資料庫瞬間裸奔、更新策略不一致導致資料錯亂。設計時要先回答三個問題:這份資料能容忍多舊?失效時誰負責回填?快取掛了系統還能不能運作?如果第三題答案是「不行」,那你不是在用快取加速,是把快取當成主資料庫,風險完全不同。
訊息佇列的重點是解耦,不是非同步。 假設一個典型電商情境:下單要扣庫存、發通知、寫報表、通知物流。如果全部同步做,任何一個環節慢或掛掉都會拖垮下單 API。把非關鍵路徑丟進佇列,主流程只做「必須成功才算下單」的事,其他交給消費者慢慢處理。但要注意:佇列不是萬能藥,它把即時錯誤變成延遲錯誤,你必須有機制處理重試、死信、以及消費者跟不上生產者的情況。
資料庫分片是最後手段。 分片一旦做下去,跨片 join、分散式交易、schema 變更都會變得複雜好幾倍。在走到分片之前,先確認讀寫分離、索引優化、冷熱資料分離都做過了。真的要分,分片鍵的選擇比什麼都重要——選錯了之後幾乎無法回頭,只能重做遷移。
無狀態與可觀測性:擴展性的兩根支柱
服務無狀態是水平擴展的前提。session、上傳中的檔案、記憶體內的計算狀態,任何綁在特定機器上的東西都會讓你沒辦法自由加減 pod。把狀態外推到 Redis、物件儲存、資料庫,服務本身只做無記憶的處理——這個原則聽起來老生常談,但實務上很多系統會在某個角落偷偷藏狀態,直到某次擴容才爆出來。
CDN 的角色也類似:把靜態資源、甚至部分動態 API 的回應推到邊緣,源站壓力自然下降。現在的 CDN 大多支援邊緣運算,登入驗證、A/B 測試、簡單的個人化都能在邊緣做掉,不必每次回源。
最後是可觀測性。系統一旦分散化,出問題時沒有 log、metrics、trace 這三樣,你只能猜。我們的經驗法則是:在寫下第一行分散式程式碼之前,就要決定好 trace ID 怎麼傳、log 怎麼集中、關鍵指標怎麼打點。事後補這些東西的成本,遠高於一開始就內建。
我們的觀察
大流量架構真正難的地方,不是選對技術,而是承認「這個系統以後會長什麼樣」需要提前想清楚。過度設計會讓小專案動彈不得,設計不足又會在流量來的時候被迫大改。我們在報價時通常會建議客戶:先誠實預估未來一到兩年的流量量級,再決定要不要現在就上分片、佇列、多區部署。架構的價值不在酷炫,而在於三年後回頭看,還撐得住當時的決定。
