Nginx 反向代理多台後端應用伺服器時,預設輪詢調度導致同一用戶請求分散到不同後端,造成 Session 不一致(登入失效、購物車丟失等)。
| 方案 | 原理 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|
| 應用層共享 | Session 存 Redis/Memcached/DB | 高可用、跨機房、無單點 | 延遲較高、架構複雜 | 嚴格一致性要求、請求量中等 |
| Cookie 改造 | 將 Session ID 存 Client Cookie | 無伺服器狀態、擴展性最強 | 安全風險、大小限制、改造成本高 | 新系統設計、無狀態微服務 |
| ip_hash | 客戶端 IP 雜湊固定後端 | 配置簡單、無額外元件 | IP 不均勻、NAT/代理失效、後端掛掉 Session 丟失 | 簡單集群、無前置代理 |
| upstream_hash | 自定義鍵(Header/Cookie/IP)雜湊 | 靈活支援 X-Forwarded-For、Cookie、JSESSIONID | 需編譯第三方模組、後端異常仍丟失 Session | 有前置代理、需 Cookie 親和性 |
upstream backend {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
ip_hash;
}
需編譯第三方模組 ngx_http_upstream_consistent_hash 或 nginx-upstream-hash。
upstream backend {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
hash $http_x_forwarded_for consistent;
}
upstream backend {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
hash $cookie_JSESSIONID consistent;
}
關鍵參數 consistent: 使用一致性雜湊演算法,節點增減時僅影響極少數鍵的映射,大幅減少 Session 遷移。
; php.ini 或 php-fpm pool 配置
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=password&database=0"
; 或多節點
session.save_path = "tcp://redis1:6379?weight=1, tcp://redis2:6379?weight=1"
# application.yml
spring:
session:
store-type: redis
redis:
host: localhost
port: 6379
依賴 spring-session-data-redis,自動將 Session 同步至 Redis。
# settings.py
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
}
}
若暫時無法改造應用層,可結合:
upstream 設定 health_check 快速踢除故障節點DeltaManager、PHP session.save_handler=memcached)X-Forwarded-For 供 upstream_hash 使用Session 共享無銀彈,根據業務容忍度、架構複雜度與團隊能力選擇最合適的組合策略。