「負載均衡不只是把流量分散到多台伺服器。 真正的挑戰在於:如何在機器故障時自動切換、 如何讓有狀態的請求(Session)還是落在同一台、 如何在不停機的情況下滾動升級。」
— 分散式系統工程師必修課
為什麼需要負載均衡?
單台伺服器有三個根本限制:CPU 上限、記憶體上限、網路頻寬上限。 垂直擴展(Scale Up,換更大的機器)可以緩解,但有天花板,且貴。 水平擴展(Scale Out,加更多機器)是解法,但前提是需要有人分配流量——這就是負載均衡器的工作。
提升吞吐量
10 台各能處理 1K QPS 的伺服器,加上 LB 後理論可達 10K QPS。水平擴展的基礎。
高可用性
一台機器掛掉,LB 自動把流量切到其他健康的機器。對用戶透明,感知不到故障。
零停機部署
滾動升級時,LB 先把流量從目標機器移走,升級完再加回來,用戶不中斷。
有 / 無 負載均衡的架構對比
❌ 無 LB(單點)
過載 / 單點故障
✅ 有 LB(水平擴展)
33K
33K
34K
負載均衡演算法
LB 怎麼決定把請求送到哪台?不同演算法有不同的適用場景:
Round Robin(輪詢)
依序輪流分配,A→B→C→A→B→C...。假設所有伺服器性能相同。
✅ 適合
服務無狀態、所有機器規格一致、請求處理時間相近
⚠️ 弱點
忽略機器當前負載,可能把請求分到已過載的機器
Weighted Round Robin(加權輪詢)
高規格機器分到更多請求。A(weight=3):B(weight=1) → A 分到 75% 流量。
✅ 適合
機器規格不同(混合機型)、不同機器承載能力差異大
⚠️ 弱點
靜態設定,不能即時反映機器運行狀態
Least Connections(最少連線)
把新請求分給當前「活躍連線數最少」的機器。動態感知負載,更智慧。
✅ 適合
請求處理時間差異大(例如 API 有快有慢)、長連線場景
⚠️ 弱點
需要追蹤每台機器的活躍連線數,LB 本身有額外開銷
IP Hash(IP 雜湊)
根據客戶端 IP 的 hash 值決定送哪台伺服器。同一個 IP 永遠到同一台機器。
✅ 適合
有狀態的服務(Session 存在機器本地、不共享)、需要保持 Sticky Session
⚠️ 弱點
機器增減時 hash 對應改變,造成 Session 遺失;IP NAT 後可能負載不均
從哪個演算法開始?
• 預設選 Round Robin:Nginx 和 AWS ALB 的預設值,無狀態服務 + 同規格機器的首選,夠用就不要過度設計。
• 請求處理時間差異大(有快有慢)→ 改用 Least Connections:避免慢請求堆積到同一台機器。
• 機器規格不同 → 用 Weighted Round Robin:依硬體能力分配比例流量,通常設定在 Nginx upstream 的 weight 參數。
• 不要用 IP Hash 解決 Session 問題:機器增減時 hash 對應改變,Session 仍會遺失,這是治標不治本的方案。
L4 vs L7 負載均衡
「L4」和「L7」指的是 OSI 模型的第 4 層(傳輸層)和第 7 層(應用層)。 兩者的核心差異是:LB 看得到多少請求內容,決定路由的資訊豐富程度。
| 比較項目 | L4(傳輸層) | L7(應用層) |
|---|---|---|
| 路由依據 | IP + Port | HTTP Header / URL / Cookie / Body |
| 看得到的資訊 | TCP/UDP 封包 | HTTP Method、Path、Host、User-Agent |
| TLS 解密 | 不解密,直接轉發 | 在 LB 終止 TLS,再轉給後端(TLS Termination) |
| 效能 | 極高(不解析封包內容) | 稍低(需解析 HTTP 請求) |
| 智慧路由 | 無法做內容路由 | 可按 /api/* → API 服務、/static/* → CDN |
| 代表產品 | AWS NLB、HAProxy (TCP) | Nginx、AWS ALB、Traefik、Envoy |
| 使用場景 | TCP 長連線、遊戲伺服器、DB Proxy | Web API、微服務、A/B Testing |
L4 + L7 通常是疊起來用的
這不是二選一的問題。生產環境常見的組合是:DNS 層(Route 53)→ L4 LB(AWS NLB,處理 TCP 連線)→ L7 LB(Nginx / ALB,做 HTTP 路由與 TLS Termination)→ Application Servers。 L4 在外層承受大量 TCP 連線的建立與分發,L7 在內層做更智慧的 HTTP 內容路由。 面試時說「L7 ALB 前面還有一層 L4 NLB 做 DDoS 防護」能讓回答更完整。
L7 路由能力示例:Nginx 設定
健康檢查(Health Check)
負載均衡器必須知道哪些後端機器是健康的,才能正確路由。 健康檢查分兩種:
被動健康檢查(Passive)
LB 觀察正常請求的回應。連續 N 次失敗(超時 / 5xx)就標記為不健康。
✅ 不需要額外流量
✅ 反映真實用戶請求的健康狀況
⚠️ 已有真實請求失敗才會偵測到
主動健康檢查(Active)
LB 定時發送探測請求(例如 GET /health 每 5 秒),在真實流量受影響前就偵測到故障。
✅ 提前偵測,不影響真實用戶
✅ 可檢查 DB 連線、依賴服務等深層狀態
⚠️ 需要後端實作 /health 端點
建議的健康檢查參數
5 秒
探測間隔
太頻繁會增加後端負載
連續 2 次
失敗閾值
才下線,避免偶發超時誤判
< 100ms
回應期限
/health 本身要夠快
健康檢查的常見陷阱
• 只檢查 HTTP 200:服務可能在線但 DB 斷線,用戶請求還是全部失敗。
• 健康檢查頻率太低:30 秒一次,故障後等 30 秒才切換,期間所有請求都失敗。
• 健康檢查本身造成負載:10 台機器、1 秒一次的深層檢查,等於額外 10 QPS 的 DB 查詢。
Sticky Session 問題與解法
如果應用有狀態(Session 存在機器記憶體),負載均衡後同一個用戶的請求可能落在不同機器上, 導致「明明登入了,下一個請求卻要重新登入」。
方案一:IP Hash(Sticky Session)
同 IP 永遠到同台機器,狀態不丟失。但機器故障 Session 仍消失,且 IP NAT 後負載不均。
⚠️ 治標不治本方案二:集中式 Session Store
把 Session 存到 Redis(而非本地記憶體)。任何機器都能讀取 Session,LB 可自由分配請求。
✅ 推薦做法方案三:JWT(無狀態 Token)
用 JWT 取代 Session,Token 本身包含狀態。LB 無需關心,服務也無需共享 Session Store。
✅ 現代 API 首選⚠️ JWT(方案三)的隱藏限制:無法即時撤銷
JWT 讓 LB 不需要關心 Session,看起來很美好——但代價是: 使用者登出時,你只能清除前端的 Token,伺服器無法讓已簽發的 JWT 立即失效。 如果 Access Token 存活期設 1 小時,被盜的 Token 在 1 小時內仍然有效。 解法:Access Token 設短存活期(15 分鐘)+ Refresh Token 搭配 Redis 黑名單, 登出時把 Refresh Token 加進黑名單,讓惡意方無法換取新 Token。
生產環境的多層負載均衡
大型系統通常不只一層 LB,而是多層組合:
面試時的說法
「在 DNS 層做 Geo-routing 把流量分到最近的 Region, 每個 Region 內用 L7 LB(AWS ALB)把流量分到多台 API 服務, 健康檢查設 5 秒一次,連續 3 次失敗則下線。 Session 用 Redis Cluster 集中存放,讓 LB 可以自由分配請求而不需要 Sticky Session。」
重點整理
Round Robin 是基礎
無狀態服務的預設選擇。加權版(Weighted)應對機器規格不均;Least Connections 應對請求耗時不均。
L7 才能做智慧路由
L4 只看 IP:Port,L7 能看 HTTP Header、URL、Cookie,可做 A/B Testing、藍綠部署、微服務路由。
主動健康檢查是關鍵
每 5 秒探測,連續 2 次失敗就下線。/health 端點要檢查真實依賴(DB、Redis),不能只回 200。
Session 問題用 Redis 解
不要用 Sticky Session(IP Hash)打補丁,把 Session 搬到 Redis,讓服務真正無狀態才是正解。