Nginx 反向代理場景下,Session 保持(Sticky Session)是有狀態應用叢集化的關鍵課題。本文深度解析 ip_hash 與 sticky cookie 兩大主流方案的原理、配置、優缺點對比與生產環境選型建議,並延伸介紹 Session 複製、集中式儲存等現代化替代方案。
預設輪詢演算法會將同一用戶的請求分發到不同後端節點,導致 Session 資料不一致:用戶在節點 A 登入,下一個請求分發到節點 B → Session 丟失 → 重複登入。Session 保持確保同一用戶請求始終路由到同一後端節點。
Nginx 根據客戶端 IP 地址計算雜湊值,將同一 IP 的請求固定路由到同一後端伺服器(除非該節點標記 down)。
upstream backend {
ip_hash; # 啟用 IP 雜湊
server 192.168.1.10:8080 weight=3;
server 192.168.1.11:8080 weight=2;
server 192.168.1.12:8080 down; # 標記離線,不參與分發
server 192.168.1.13:8080 backup; # 備用節點
}
| 優點 | 缺點 |
|---|---|
| 配置極簡,無需額外模組 | 同一 NAT/代理下所有用戶共用一 IP → 流量高度傾斜,負載極度不均 |
| 無狀態、無 Cookie 依賴、相容性最好 | 後端節點故障時,該 IP 所有用戶 Session 丟失,無法平滑遷移 |
| 效能極高,無額外開銷 | 不支援 IPv6 雜湊(舊版本)、不支援權重動態調整 |
| 配置極簡,零維護成本 | 無法應對 CDN/前置代理場景(真實 IP 被隱藏) |
Nginx Plus 商業版功能(開源版需第三方模組 nginx-sticky-module-ng)。Nginx 向客戶端發送含路由資訊的 Cookie,後續請求攜帶 Cookie 精準路由到原節點。基於 Cookie 而非 IP,解決 NAT/代理場景問題。
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
sticky cookie srv_id expires=1h domain=.example.com path=/ httponly secure;
# 參數說明:
# srv_id Cookie 名稱
# expires=1h Cookie 過期時間(1小時)
# domain=.example.com Cookie 域(支援子域)
# path=/ Cookie 路徑
# httponly 防 XSS
# secure 僅 HTTPS 傳輸
}
# 下載模組
cd /usr/local/src
git clone https://github.com/bitgo/nginx-sticky-module-ng.git
# 重新編譯 Nginx
cd /usr/local/src/nginx-1.24.0
./configure --add-module=../nginx-sticky-module-ng \
--with-http_ssl_module --with-http_v2_module ...(其他參數)
make && make install
| 優點 | 缺點 |
|---|---|
| 基於 Cookie,完美解決 NAT/代理/多用戶共享 IP 問題 | 需第三方模組(開源版)或 Nginx Plus 商業授權 |
| 支援 Cookie 過期、域、路徑、HttpOnly、Secure 完整屬性 | 客戶端禁用 Cookie 時失效(可配合 ip_hash 降級) |
| 節點故障時可配合備用節點平滑切換 | 需重新編譯 Nginx 或購買 Plus 授權,維護成本較高 |
| 負載分佈均勻,不受 NAT 影響 | Cookie 可被竄改/竊取,需配合 Secure/HttpOnly/SameSite |
| 維度 | ip_hash | sticky cookie |
|---|---|---|
| 實現層級 | 核心模組(內建) | 第三方模組 / Nginx Plus |
| 路由依據 | 客戶端 IP 雜湊 | Cookie 值(路由標識) |
| NAT/代理支援 | 不支援(嚴重傾斜) | 完美支援 |
| 負載均勻度 | 極差(同 IP 全走一節點) | 優秀(按用戶分佈) |
| 節點故障行為 | 該 IP 所有用戶 Session 丟失 | 可配合 backup 節點平滑切換 |
| 部署複雜度 | 零配置、零依賴 | 需編譯模組/購買 Plus |
| Cookie 依賴 | 無 | 強依賴(客戶端禁用則失效) |
upstream backend {
# 主策略:sticky cookie(主要流量)
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080 backup;
sticky cookie srv_id expires=2h domain=.example.com path=/ httponly secure;
# 降級:客戶端禁用 Cookie 時回退 ip_hash
# 需配合 map 指令實現條件判斷
# 見下方進階配置
}
# 定義變數:檢查 Cookie 是否存在
map $cookie_srv_id $sticky_fallback {
default "ip_hash";
"" "ip_hash"; # 無 Cookie 時降級
}
upstream backend {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
# 動態選擇策略(需 Nginx Plus 或特定模組支援)
# 開源版可用 split_clients 或 lua 模組實現類似邏輯
}
與其在代理層強行綁定,不如從根源解決:後端 Session 共享,實現真正的無狀態水平擴展。
| 方案 | 原理 | 優點 | 缺點 |
|---|---|---|---|
| Redis 集中式 Session | Session 資料存 Redis Cluster,所有節點讀寫同一份 | 完全無狀態、彈性擴縮容、Session 永不丟失、支援跨機房 | 網路延遲、Redis 單點(需 Cluster/哨兵)、序列化開銷 |
| Session 複製 | 節點間同步 Session(Tomcat DeltaManager、RedisSessionManager) | 本地讀取快、無中心節點 | 網路風暴風險、大集群同步延遲、一致性難保證 |
| JWT 無狀態 Token | Session 資料編碼在 Token 中,客戶端攜帶 | 完全無狀態、無伺服器儲存、天然水平擴展 | Token 體積大、無法主動撤銷、敏感資料不宜存放 |
| 資料庫共享 | Session 存資料庫(Redis/MySQL/PostgreSQL) | 持久化、可查詢、支援複雜查詢 | 延遲較高、連接池壓力 |
階段 1(單體/雙節點):
ip_hash → 簡單、零成本、快速上線
階段 2(叢集化、有前置代理):
sticky cookie (Nginx Plus / nginx-sticky-module-ng)
+ ip_hash 降級
+ 後端引入 Redis Session 共享(漸進式遷移)
階段 3(微服務/雲原生):
完全無狀態化
- Session → Redis Cluster / JWT
- 代理層純粹負責路由、SSL 終結、限流、熔斷
- 服務發現 + 健康檢查 + 灰度發布
階段 4(服務網格):
Istio/Linkerd 接管流量管理
Sidecar 代理處理 mTLS、流量分割、可觀測性
應用層完全無感知網路拓撲
| 場景 | 推薦方案 | 關鍵理由 |
|---|---|---|
| 內部測試/低併發/無代理 | ip_hash | 零成本、零配置、即用即走 |
| 生產環境、有 CDN/WAF、NAT 環境 | sticky cookie + ip_hash 降級 | 解決 NAT 傾斜、支援平滑故障轉移 |
| 追求架構純淨、彈性擴縮容 | 後端 Redis Session 共享 | 根治有狀態痛點,實現真正無狀態擴展 |
| 微服務/雲原生 | JWT + Redis Session / 服務網格 | 完全無狀態、雲原生就緒 |
Nginx Session 保持是從「代理層綁定」向「後端共享」演進的過渡方案。ip_hash 適合簡單場景,sticky cookie 解決 NAT 問題,但終極解法是後端 Session 共享(Redis/JWT)實現真正無狀態。建議根據業務階段、團隊能力、基礎設施成熟度選型,並規劃演進路徑。生產環境建議:短期用 sticky cookie 過渡,長期演進至 Redis Session 共享或 JWT 無狀態架構,配合 Nginx 限流、熔斷、健康檢查,構建高可用、彈性擴展的現代化應用交付架構。