Nginx +Tomcat集群后 session 的處理
1. session儲存大小的由來。
session是由建立前後端連線的執行緒建立的,該執行緒佔據jvm記憶體大小,就是session的儲存大小。
單節點低負荷的情況下,我們通常把一個WEB應用打成WAR包放WEB應用伺服器,如TOMCAT下執行就行了(如圖1)。但隨著使用者量的增加,系統負載日益增長,這時我們通常就會採用多臺WEB應用伺服器組成叢集來分擔負荷(tomcat1, tomcat2上同時部署了應用application1; tomcat3上單獨部署了應用application3),這時某一使用者對同一應用的訪問就有可能分配到從不同的TOMCAT訪問這個應用(如圖2, session1和session2同時訪問application1)。假設我們的WEB訪問請求都是無狀態的,多個後臺應用和一個後臺應用的處理就沒什麼區別了,根據每次請求的引數進行相關邏輯處理就行。但通常我們會將使用者資訊,鑑權的資料等放入session中做使用者鑑權, 使用者狀態資料等基礎框架的處理,這時我們每次分配到WEB伺服器後臺的訪問請求就需要記錄session狀態及資料了,確保每次使用者訪問,後臺從session取出的資料是一致的。
到這裡,我們已經可以清楚的看到,叢集環境下,某一使用者請求訪問APPLICATION1,第一次請求被NGINX轉發到TOMCAT1,產生了SESSION1,這時,APPLICATION1存了某一資料進SESSION1。隨後,該使用者進行第二次請求,這時,NGINX將該請求轉發到TOMCAT2,這時TOMCAT2產生了一個新的SESSION2來訪問APPLICTION1,如果這時APPLICTION1從SESSION中取剛存入的資料,因為SESSION2是TOMCAT2新產生的,並不是剛才存入資料的SESSION1,就會取不到我們想要的資料.
所以,很自然的,我們就想到需要保持session1和session2的一致性。
而保持session1和session2的一致性有兩種很明顯的方法,一種是保持session1和session2中的資料一致,二是讓session1和session2成為一個session,即如果同一使用者訪問applcation1, tomcat1和tomcat2產生的是一個共享的session。下面就介紹下這兩種處理方式.
1. TOMCAT間的 session複製。
顧名思義,就是把一臺TOMCAT上session發生變更的時候, 將變更的資料分發給其他TOMCAT。如圖3
tomcat間是以IP組播發送變更的資料,將資料傳送到叢集組的其他成員。這裡,同一使用者訪問APPLICATION1的session資料互相有了同步,他們的資料是相同的,就用app1sesson表示。
配置方法是配置 conf/server.xml 檔案中的 Manager ,Channel,以及WEB.XML的distributable 屬性。 網上已有很多配置介紹,這裡就不囉嗦了。
2. 採用 memcached session manager 共享session。
這裡, tomcat1和tomcat2產生的session1和session2 在 session mananger 的管理下,都使用的是快取中的共享session,訪問應用時這樣傳到application1應用的session就是圖中的共享session.
這種共享session方案可採用google的memcached session manager, 注意下載時對應TOMCAT版本。 它以memcached作為快取,安裝時所有tomcat節點需要安裝memcached-session-manager。支援sticky session 和 non-sticky session。大概原理是當一個請求結束時,session會被送回Memcached進行備份。當下一次請求開始時,本地Session可用,直接服務,請求結束後,session又被送回Memcached備份。如果下一次請求會被路由到其他Tomcat上。負責處理此此請求的Tomcat並不清楚Session的資訊。此時它會從Memcached查詢該Session,更新該Session並將其儲存在本機內容。此次請求結束,session被修改,送回Memcached備份。如下圖:
配置方法網上也有很多介紹,主要是修改 tomcat下 conf/server.xml, memcachedNodes可指定多個memcached節點, 逗號隔開。
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:localhost:11211" requestUriIgnorePattern=".*\.(png|gif|jpg|css|js){1}quot;" sessionBackupAsync="false" sessionBackupTimeout="1800000" copyCollectionsForSerialization="false" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
如是非粘性,配置 sticky="false":
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:localhost:11211" sticky="false" requestUriIgnorePattern=".*\.(png|gif|jpg|css|js){1}quot;" sessionBackupAsync="false" lockingMode="uriPattern:/path1|/path2" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />