在單臺服務器情況下session處理比較簡單镐确,一旦到了集群環(huán)境中包吝,我們就必須考慮用戶和會話的問題,如果不加處理的話源葫,一旦后端IP輪詢切換诗越,會話cookies找不到session,會話就中斷了息堂。在此情景下嚷狞,通常有以下5種解決方案。
1. 依然使用集群荣堰,但集群的輪詢策略改成hash ip
將每一個用戶和后端服務器綁定床未,這樣用戶的會話就會一直落在同一臺服務器上,這是成本最小的解決方案振坚,只需要修改Nginx服務器的配置即可薇搁。如果是在比較老的架構(gòu)上,推薦這種改造方案渡八。
upstream backend {
ip_hash;
server bk1.abc.com;
server bk2.abc.com;
server bk3.abc.com;
}
這種解決解決方案也存在局限性啃洋,比如某臺服務器掛了切換到另一臺服務器传货,對應的會話也就丟了。還有另外一個問題宏娄,如果前端用了CDN的話问裕,客戶端IP變化的頻率可能是很高的,有可能一個小時或更短時間內(nèi)就變一次孵坚,這在校園網(wǎng)的網(wǎng)絡環(huán)境下很容易產(chǎn)生這種情況僻澎。
2. 使用Session復制方案
顧名思義,Session復制就是讓集群里的每臺服務器都存儲整個集群所有服務器上的全部session十饥。這樣一旦某臺服務器掛了,用戶切換到其他服務器上也能訪問到一樣的session數(shù)據(jù)祖乳。這種解決方案不好的地方在于進行session復制需要額外的網(wǎng)絡開銷和系統(tǒng)資源逗堵,當服務器較多或session中存儲的數(shù)據(jù)量大的時候,這個問題尤為明顯眷昆。
Session復制本身的操作是比較復雜蜒秤,但是對于服務器來說,配置比較簡單亚斋,但性能是個很大的問題作媚。當集群中服務器數(shù)量大于兩臺時就比較吃力了,總之這是一種比較早期時候的解決方案帅刊。
3. Nginx的sticky方案
sticky方案和方案1類似纸泡,但是sticky能把會話死死地粘滯在其中一臺服務器上,算是對方案1的補充赖瞒,可以避免在CDN網(wǎng)絡波動下的IP沖突造成的會話丟失女揭。但是依然無法解決服務器掛掉導致會話丟失的問題。
4. NoSQL的幾種存儲方案
基于Redis等NoSQL的session集中存儲方案栏饮,是目前最流行的解決方案吧兔,早期用MySQL來存儲。引入Redis的方案除了會增加系統(tǒng)復雜度外袍嬉,依然還有以下幾個問題:
- Redis有單點境蔼,要解決單點問題就得使用redis的集群方案,比如Codies
- 用戶量大的情況下伺通,用來連接redis的類庫可能存在瓶頸箍土,比如性能不穩(wěn)定、高并發(fā)容易掛的問題等等罐监。
5. 放棄Session使用Cookie
使用純cookie涮帘,不使用session,天然分布式笑诅。存在問題:
- Cookies需要加解密调缨,性能消耗需要考慮疮鲫。而且儲存空間有限,如果存放了復雜的數(shù)據(jù)弦叶,序列化本身也是一個消耗俊犯。
- 對于瀏覽器而言,每次請求都會帶上Cookies伤哺,包括js/css等靜態(tài)資源燕侠,浪費帶寬,可以考慮為靜態(tài)資源單獨部署一個子域名立莉。
需要注意的是绢彤,如果應用需要做“禁止同時登錄”的需求時,用Cookie的話解決起來會麻煩很多蜓耻。
另外可以把cookie換成token等方式驗證用戶茫舶,每次請求帶上token作為會話憑據(jù)。