LB 是水平擴展的前提
水平擴展是靠加開實例來分攤流量,但加實例本身不會自動讓服務擴得動,它要兩個前提同時成立:流量分得進新實例、以及任何實例都能接任何請求。負載平衡解第一個——它是那個把流量分到多個實例的元件,沒有它,新開的實例是一台沒有流量進得去的孤島。無狀態解第二個——實例之間不能有「只有我這台知道」的狀態,否則流量分過去也服務不了。這一章講負載平衡怎麼滿足第一個前提、以及第二個前提為什麼把設計推向無狀態,把「怎麼做到無狀態」交棒給水平擴展模組。
LB 讓新實例能接到流量
一個新開的實例要能接流量,得先讓負載平衡認得它。流程是實例啟動、註冊進後端群組、健康檢查通過、開始被分流。這條路徑上任何一環沒接好,實例就擴而不用——機器開了、資源在燒,但流量進不去。
擴容時最常見的訊號是「新實例遲遲不接流量」。根因通常在註冊與健康檢查的時序:實例註冊進服務發現有延遲、健康檢查要連續通過幾次才開始分流、傳播到所有轉發層又要一段時間,這些疊起來就是新實例從啟動到真正分到流量的空窗。這段空窗在 健康檢查路由設計 有完整的傳播延遲鏈;對擴展來說,關鍵是加實例到它真正幫上忙之間有延遲,容量規劃不能假設按下擴容就立刻有容量。
無狀態讓任何實例能接任何請求
第二個前提是任何實例都能接任何請求。這在實例本地保存了請求相關狀態時會破功——會話資料存在某台實例的記憶體裡,那個會話的後續請求就只能回到那台,負載平衡沒辦法自由地把它分給別台。要維持這種綁定,就得靠 會話黏著,而黏著的代價是負載不均、以及那台實例掛掉時會話狀態一起消失。
把狀態從實例本地移出去,這兩個代價就消失。會話資料放進外部的共享儲存(例如集中的 session store),每個實例都是無狀態的——它不保存任何「只有我這台知道」的狀態,需要時每次從共享儲存讀。這樣負載平衡可以把任何請求分給任何實例,加開的實例立刻是完全對等的容量,掛掉一台也不會帶走誰的會話。無狀態是讓水平擴展真正線性的關鍵:實例對等,加 N 台就多 N 台的容量。
外置狀態不是沒有代價——它把「本地記憶體讀取」換成「網路讀共享儲存」,多一次網路往返、也讓共享儲存成為新的關鍵依賴。共享儲存怎麼選、會話怎麼處理、哪些狀態能外置哪些不能,是 水平擴展模組 的主題,這裡只確立「無狀態是水平擴展的前提」這條方向。
擴縮時,網路規則要跟著成員身分走
實例會隨擴縮不斷增減、換 IP,網路的存取規則不能綁在具體 IP 上,否則每擴一台就要改一次規則。可靠的做法是讓規則跟著成員身分走:後端的防火牆規則寫成「只接受來自負載平衡那一群的流量」,而不是「只接受這幾個 IP」。這樣從 2 台擴到 20 台,成員換了一輪 IP,規則一個字都不用改。這套 group 對 group 的引用是 infra 網路地基 的設計,對水平擴展的意義是它讓擴縮不牽動網路規則。
跨可用區分流是容錯的地基
負載平衡把流量分到多個實例時,這些實例最好分散在不同的可用區(AZ),這樣單一 AZ 故障時,其他區的實例還能承接。基礎設施層負責把跨 AZ 的網路地圖鋪對稱——每種角色在至少兩個可用區各有落點;負載平衡層負責把入口流量實際分派到跨可用區的後端。infra 的網路地基明確把「入口流量怎麼分到跨可用區的後端」這件事交給負載平衡處理,兩層在這裡接棒。跨 AZ、跨區域的容錯設計本身是高可用的範圍,會在 模組六 展開,這裡的重點是負載平衡的分流能力是那層容錯的地基。
下一步路由
#devops #load-balancing #horizontal-scaling #stateless #session