文章目錄
Session是啥?
Session 是另一種記錄客戶狀態的機制,不同的是 Cookie 保存在客戶端瀏覽器中,而 Session 保存在服務器上。客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上。這就是 Session。客戶端瀏覽器再次訪問時只需要從該 Session 中查找該客戶的狀態就可以了。
用瀏覽器打開一個網頁,用到的是HTTP協議,學過計算機的應該都知道這個協議,它是無狀態的,什麼是無狀態呢?就是說這一次請求和上一次請求是沒有任何關係的,互不認識的,沒有關聯的。但是這種無狀態的的好處是快速。
1. Session共享
正常情況下,HTTPSession是通過Servlet容器創建並進行管理的,創建成功之後都是保存在內存中。如果對項目進行橫向擴展搭建集羣,此時可以利用一些硬件和軟件工具來做負載均衡,此時,來自同一用戶的HTTP請求就有可能被分發到不同的實例上去,如何保證各個實例之間的Session的同步就成爲一個問題。
實現Session共享的方式主要有以下兩種:
- Session複製共享
- 基於緩存數據庫的session共享(基於
memcache/redis
緩存的session共享)
1.1 session複製共享:session replication
如tomcat自帶session共享,主要是指集羣環境下,多臺應用服務器之間同步session,使session保持一致,對外透明。 如果其中一臺服務器發生故障,根據負載均衡的原理,調度器會遍歷尋找可用節點,分發請求,由於session已同步,故能保證用戶的session信息不會丟失,會話複製。
此方案的不足之處:
- 必須在同一種中間件之間完成(如:tomcat-tomcat之間);
- Session複製帶來的性能損失會快速增加.特別是當session中保存了較大的對象,而且對象變化較快時, 性能下降更加顯著,會消耗系統性能。這種特性使得web應用的水平擴展受到了限制;
- Session內容通過廣播同步給成員,會造成網絡流量瓶頸,即便是內網瓶頸。
1.2 基於緩存數據庫的session共享(基於memcache/redis
緩存的session共享)
使用緩存數據庫存取session信息,應用服務器接受新請求將session信息保存在緩存數據庫中,當應用服務器發生故障時,調度器會遍歷尋找可用節點,分發請求,當應用服務器發現session不在本機內存時,則去緩存數據庫中查找,如果找到則複製到本機,這樣實現session共享和高可用。
2. 多個Tomcat之間實現Session複製共享
<Engine defaultHost="localhost" name="Catalina">
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
這個就是tomcat自帶的集羣配置了,但是還需要修改應用的web.xml文件,加入標籤 <distributable/>
,如下所示:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<distributable/>
</web-app>
注:直接加在</web-app>
之前就可以了這個是加入tomcat的session 複製的,做tomcat集羣必須需要這一步,否則用戶的session 就無法正常使用。
3. Redis實現Session共享
3.1 spring-session + Redis實現Session共享
- 添加依賴
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
- 在
web.xml
中添加session過濾器
<!--session過濾器 放在過濾器頭-->
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.2 Spring Boot + Redis實現Session共享
SpringBoot提供了自動化的Session共享配置,它結合Redis可以非常方便的解決Session共享問題。使用Redis解決Session共享問題的原理很簡單,就是把原本存儲在不同服務器上的Session拿出來放在一個獨立的服務器上。步驟如下:
- 除了Redis的依賴之外,還要提供
spring-session-data-redis
依賴,Spring Session可以做到透明的替換掉應用的Session容器。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
- 編寫實現方法