一、應(yīng)用架構(gòu)變遷下的Session管理
Session一詞直譯為“會話”,意指有始有終的一系列動作/消息。Session是Web應(yīng)用蓬勃發(fā)展的產(chǎn)物之一,在Web應(yīng)用中隱含有“面向連接”和“狀態(tài)保持”兩個含義,同時(shí)也指代了Web服務(wù)器與客戶端之間進(jìn)行狀態(tài)保持的解決方案。
在Web應(yīng)用誕生之初,應(yīng)用服務(wù)器與瀏覽器之間僅僅只是基于HTTP協(xié)議進(jìn)行通信。而HTTP協(xié)議是無狀態(tài)的,也就是說每一個請求之間都是相互獨(dú)立的,互不關(guān)聯(lián)。但是隨著應(yīng)用業(yè)務(wù)復(fù)雜化,服務(wù)器需要按照用戶的一系列業(yè)務(wù)操作向用戶提供某些特定的、按需的內(nèi)容。這時(shí)候就需要通過保存用戶狀態(tài),將用戶的請求關(guān)聯(lián)起來。Session管理正是這一問題的解決方案。
早期的Web應(yīng)用基本都采用的是單體架構(gòu),也就是把一個使用了分層架構(gòu)的Web應(yīng)用部署在單節(jié)點(diǎn)Web服務(wù)器上的架構(gòu)類型。在這種架構(gòu)中,雖然采用了分層架構(gòu),將整個應(yīng)用分為了表現(xiàn)層、業(yè)務(wù)邏輯層和數(shù)據(jù)訪問層,每一層各司其職,讓W(xué)eb應(yīng)用的各個方面都有所改善。但這樣的分層只是停留于邏輯上。由于將所有代碼部署在單個服務(wù)器節(jié)點(diǎn)上,隨著應(yīng)用不斷迭代開發(fā),單體應(yīng)用將會發(fā)展成巨石型應(yīng)用,臃腫不堪,難以維護(hù)。
在這樣的單體架構(gòu)中,由于所有的用戶請求都是由這個唯一的服務(wù)器進(jìn)行響應(yīng)處理,所以只要把保存了用戶信息和狀態(tài)的Session對象,存放在應(yīng)用服務(wù)器內(nèi)存里,就能輕松地達(dá)到保持用戶狀態(tài)的目的。
隨著Web應(yīng)用的發(fā)展,用戶訪問量和業(yè)務(wù)復(fù)雜度與日俱增,應(yīng)用的性能和代碼的維護(hù)難度成為應(yīng)用的瓶頸,為了突破瓶頸,開發(fā)者開始嘗試在應(yīng)用架構(gòu)中引入負(fù)載均衡器,繼而演化出了集群和分布式兩種架構(gòu)類型。
集群和分布式架構(gòu)中,后端包含了多個服務(wù)器節(jié)點(diǎn)。當(dāng)用戶進(jìn)行登錄時(shí),登錄請求是由其中一個服務(wù)器節(jié)點(diǎn)進(jìn)行響應(yīng),而后續(xù)的用戶請求將可能被負(fù)載均衡器分發(fā)到其他服務(wù)器節(jié)點(diǎn),這時(shí)候就可能因?yàn)檫@個服務(wù)器節(jié)點(diǎn)上沒有用戶Session,導(dǎo)致服務(wù)器判定用戶是未登錄狀態(tài),讓用戶重新登錄。
所以,在集群和分布式架構(gòu)中,必須保證用戶進(jìn)行登陸后,架構(gòu)中的所有服務(wù)器節(jié)點(diǎn)都能共享Session數(shù)據(jù)。常用的Session管理方案有如下3種:
1、將Session對象保存在Cookie,然后存放在瀏覽器端。每次瀏覽器向服務(wù)器發(fā)送請求的時(shí)候,都會把整個Session對象放在請求里一起發(fā)送到服務(wù)器,以此來實(shí)現(xiàn)Session共享。這樣的方案實(shí)現(xiàn)起來特別方便,但是由于Cookie的存儲容量比較小,所以這個方案只適用于Session數(shù)據(jù)量小的場景。
2、Session復(fù)制。部分應(yīng)用服務(wù)器能夠支持Session復(fù)制功能,例如Tomcat。用戶可以通過修改配置文件,讓應(yīng)用服務(wù)器進(jìn)行Session復(fù)制,保持每一個服務(wù)節(jié)點(diǎn)的Session數(shù)據(jù)達(dá)到一致。但是這個方案的實(shí)現(xiàn)依賴于應(yīng)用服務(wù)器。當(dāng)應(yīng)用被大量用戶訪問時(shí),每個服務(wù)器都需要有一部分內(nèi)存用來存放Session,同時(shí)因?yàn)榇罅縎ession通過網(wǎng)路傳輸進(jìn)行復(fù)制,將會占用網(wǎng)絡(luò)資源,還可能因?yàn)榫W(wǎng)絡(luò)延遲導(dǎo)致程序異常。
3、Session粘滯。利用負(fù)載均衡器的分發(fā)能力,將同一瀏覽器上同一用戶的請求,都定向發(fā)送到固定服務(wù)器上,讓這個服務(wù)器處理該用戶的所有請求,這樣只要這個服務(wù)器上保存了用戶Session,就能保證用戶的狀態(tài)一致性。但是這個方案依賴于負(fù)載均衡器,而且只適用于橫向擴(kuò)展的集群場景,不能滿足分布式場景。
二、微服務(wù)架構(gòu)下的Session管理
微服務(wù)架構(gòu)是將一個應(yīng)用拆分成一套小而相互關(guān)聯(lián)的微服務(wù),微服務(wù)之間通過暴露出來的API被其他微服務(wù)或系統(tǒng)所調(diào)用。在運(yùn)行時(shí) ,每個微服務(wù)實(shí)例通常是一個云虛擬機(jī)或者一個Docker。眾多微服務(wù)綜合起來,構(gòu)成了一個完整的微服務(wù)架構(gòu)應(yīng)用。
微服務(wù)架構(gòu)中的微服務(wù)一般可以分為兩類:無狀態(tài)服務(wù)和有狀態(tài)服務(wù)。無狀態(tài)服務(wù)比如應(yīng)用服務(wù)器提供的公共服務(wù),通常不保存數(shù)據(jù),方便進(jìn)行橫向擴(kuò)展。有狀態(tài)服務(wù)則需要進(jìn)行數(shù)據(jù)存儲,例如數(shù)據(jù)庫服務(wù)和緩存服務(wù)。在Web應(yīng)用中,Session用來存儲用戶狀態(tài)信息,所以Session管理也是有狀態(tài)服務(wù)的一種。
微服務(wù)架構(gòu)可以近似地看做是一個大型的分布式架構(gòu)系統(tǒng),但是與分布式架構(gòu)相比,微服務(wù)架構(gòu)讓應(yīng)用模塊的劃分更為精細(xì),每個微應(yīng)用大小合適,方便進(jìn)行維護(hù)和管理。通過使用devops平臺,可以讓微服務(wù)模塊的開發(fā)部署變得很敏捷。
當(dāng)應(yīng)用由十幾個甚至數(shù)十個部署在不同節(jié)點(diǎn)上的微服務(wù)組成時(shí),如果還是沿用分布式架構(gòu)中的Session管理方案,將會讓Session管理的復(fù)雜度直線上升,同時(shí)很難保證整個架構(gòu)中Session數(shù)據(jù)的一致性。
因此,在微服務(wù)架構(gòu)下的Session管理,我們應(yīng)該另辟蹊徑,不再將Session對象保存在服務(wù)器的內(nèi)存里,而是在應(yīng)用架構(gòu)中引入獨(dú)立的中間存儲介質(zhì),將整個應(yīng)用架構(gòu)中的Session對象進(jìn)行統(tǒng)一管理。
個人認(rèn)為,一個好的Session集中管理方案,應(yīng)該具備以下4個特點(diǎn):
中間存儲介質(zhì)的讀寫速度要快。因?yàn)槭褂昧薙ession集中管理后,將會在Session的讀寫操作中引入網(wǎng)絡(luò)傳輸,與保存在服務(wù)器本地內(nèi)存相比,讀寫速率會有所下降,所以必須保證中間存儲介質(zhì)的讀寫速度。中間存儲介質(zhì)要高可用。整個應(yīng)用架構(gòu)中的Session對象都將被保存在中間存儲介質(zhì)中,如果不能保證存儲介質(zhì)的高可用,整個應(yīng)用都將變得不穩(wěn)定。Session管理方案要保證對用戶的透明性,切換成集中管理后 ,對用戶的使用應(yīng)該是不會與影響的,用戶使用的時(shí)候?qū)Ψ桨父淖儫o感知。管理方案不該和某一應(yīng)用服務(wù)器耦合,應(yīng)該適用于所有常規(guī)應(yīng)用服務(wù)器。1234567
從上述特點(diǎn)可以看出,Session集中管理的技術(shù)選型,應(yīng)該從Session存儲介質(zhì)和管理方案實(shí)現(xiàn)兩方面進(jìn)行考慮。
三、Session管理實(shí)踐分享
因?yàn)镾ession存儲介質(zhì)需要有較高的讀寫性能,所以應(yīng)該選擇緩存服務(wù)器作為存儲介質(zhì)。我們在進(jìn)行微服務(wù)Session管理實(shí)踐的時(shí)候,對目前業(yè)內(nèi)常用的兩種緩存服務(wù)器,Redis和Memcache,進(jìn)行了對比,準(zhǔn)備在兩者之中選一個合適的緩存服務(wù)器來進(jìn)行Session存儲。
從表中的數(shù)據(jù)可能看出,雖然Redis的讀寫性能稍弱于Memcache,但是Redis支持的數(shù)據(jù)類型較多,而且支持?jǐn)?shù)據(jù)的持久化。
此外,Memcache使用Slab Allocation機(jī)制進(jìn)行內(nèi)存管理,通過將內(nèi)存分隔成特定長度塊來解決內(nèi)存碎片問題。同時(shí)Memcache采用最近最少使用(LRU)算法對slab進(jìn)行內(nèi)存回收。這就意味著,如果所有Session對象的大小大致相同,將會被Memcache存放在大小合適的slab中進(jìn)行存儲,一但這些slab被存滿,再有新的數(shù)據(jù)進(jìn)來,里面的存放的時(shí)間相對較早的Session對象就會被清除,導(dǎo)致用戶變成未登錄狀態(tài)。
對比之后發(fā)現(xiàn)Redis更加適合用于Session存儲。而且Redis3.0之后,提供了良好的主從復(fù)制和集群能力,能夠很好地保證Session存儲的高可用。Redis還提供了數(shù)據(jù)失效和訂閱通知的能力,能為Session共享提供良好的支撐。
在Session集中管理方案的實(shí)現(xiàn)上,目前常用的方案有兩種,一種是Memcache-Tomcat-Session,另一種是Spring Session。
Memcache-Tomcat-Session是一個基于Memcache和Tomcat實(shí)現(xiàn)Session集中管理的開源方案,通過修改Tomcat的server.xml文件,使用擴(kuò)展的SessionManager替換Tomcat原有的Session管理器來實(shí)現(xiàn)集中管理。這個方案實(shí)現(xiàn)起來比較簡單,但是與Tomcat耦合,不適用于其他應(yīng)用服務(wù)器。
Spring Session是Spring提供的一套Session管理方案,通過一個SessionFilter將所有訪問應(yīng)用的請求都攔截下來,然后使用Request包裝類接管Session管理。SpringSession不與應(yīng)用服務(wù)器耦合,能適用于常規(guī)服務(wù)器。同時(shí)還提供了在瀏覽器下對同一應(yīng)用存儲多個Session等功能。
SpringSession優(yōu)點(diǎn)頗多,所以開始的時(shí)候我們曾嘗試將SpringSession集成到公司產(chǎn)品中來,進(jìn)行Session集中管理,但在集成過程中考慮到以下幾點(diǎn),最終放棄了集成。
所以最終我們決定使用Redis作為Session的存儲介質(zhì),然后參考SpringSession的實(shí)現(xiàn)理念,自己設(shè)計(jì)開發(fā)一套輕量級的Session集中管理實(shí)現(xiàn)。
同樣使用SessionFilter進(jìn)行用戶請求攔截,然后通過Request包裝類接管應(yīng)用服務(wù)器的Session管理。在Request包裝類中重寫getSession方法。讓用戶在進(jìn)行Session讀寫的時(shí)候去Redis中進(jìn)行操作,而且使用Session的方法與過去一樣,使得管理方案對用戶透明。
在Session共享模塊與Redis之間,基于jedis開發(fā)了一個分布式緩存SDK,用于進(jìn)行通信,同時(shí)SDK可以提供擴(kuò)展性,后續(xù)如果需要支持其他的緩存服務(wù)器,只要對SDK進(jìn)行擴(kuò)展開發(fā)即可。
然后為了保證Session集中管理方案的高可用,將會搭建Redis集群來存儲Session對象。
這是一個推薦客戶搭建的最小Redis集群,集群中共有4個Redis節(jié)點(diǎn),兩主兩從。兩個Master節(jié)點(diǎn)用來對Session數(shù)據(jù)進(jìn)行分片存儲,而Slaver節(jié)點(diǎn)用來對Matser進(jìn)行數(shù)據(jù)備份和讀寫分離。
總結(jié)
https://blog.csdn.net/xudawenfighting/article/details/80127473
聯(lián)系客服