Web 應用幾乎都需維護會話狀態 (購物車、登入狀態、多步驟表單)。儲存位置選擇影響擴展性與效能:
public interface HttpSession {
Object getAttribute(String name);
void setAttribute(String name, Object value);
void removeAttribute(String name);
void invalidate();
void setMaxInactiveInterval(int seconds);
// ...
}
本質是跨 Servlet 共享的 Map,生命週期由容器管理。
| 策略 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| JDBC 持久化 | 叢集全掛仍可恢復 | DB 交易昂貴、資料層擴展難 | 高可用性優先、叢集較小 |
| 檔案系統共享 | 成本低於 DB | 持久化保證較弱 | 成本敏感、可容忍極小遺失 |
| 記憶體全量複寫 | 負載平衡最簡單 (Round-robin) | 記憶體與網路頻寬隨節點數平方增長 | 小型叢集 (≤4 節點) |
| 記憶體 Buddy 複寫 | 擴展性較好、僅備份 1-2 份 | 故障轉移需定位備份節點,LB 較複雜 | 中大型叢集、主流應用伺服器預設 |
開發者必須預期:故障轉移後 Session 可能回滾到數個請求前的狀態,程式碼需防禦性檢查屬性是否存在。
setAttribute():容器靠此偵測變更。直接修改取回的 List/Map 不會觸發複寫。List cart = (List) session.getAttribute("cart"); cart.add(item); session.setAttribute("cart", cart); // 必須重設invalidate():登出、結帳完成即銷毀,釋放記憶體、減少複寫負擔。removeAttribute(),避免垃圾資料隨 Session 複寫。<web-app ...>
<distributable/> <!-- 必須標記啟用複寫 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
確保所有放入 Session 的物件實作 java.io.Serializable。
HttpSession 複寫是叢集高可用的基石,但策略選擇與程式碼撰寫習慣直接決定擴展上限。架構師應在設計早期評估叢集規模、容錯需求、效能預算,選定複寫模式並制定編碼規範;上線前務必進行負載測試驗證伸縮性。