spring boot 及 redis 實現分佈式session 實踐筆記

(0)背景

Spring-Session實現Session共享入門教程

  1. Spring-Session使用的場景?

HttpSession是經過Servlet容器進行建立和管理的,在單機環境中。經過Http請求建立的Session信息是存儲在Web服務器內存中,如Tomcat/Jetty。css

假如當用戶經過瀏覽器訪問應用服務器,session信息中保存了用戶的登陸信息,而且session信息沒有過時失,效那麼用戶就一直處於登陸狀態,能夠作一些登陸狀態的業務操做!
單機sessionhtml

可是如今不少的服務器都採用分佈式集羣的方式進行部署,一個Web應用,可能部署在幾臺不一樣的服務器上,經過LVS或者Nginx等進行負載均衡(通常使用Nginx+Tomcat實現負載均衡)。此時來自同一用戶的Http請求將有可能被分發到不一樣的web站點中去(如:第一次分配到A站點,第二次可能分配到B站點)。那麼問題就來了,如何保證不一樣的web站點可以共享同一份session數據呢?java

假如用戶在發起第一次請求時候訪問了A站點,並在A站點的session中保存了登陸信息,當用戶第二次發起請求,經過負載均衡請求分配到B站點了,那麼此時B站點可否獲取用戶保存的登陸的信息呢?答案是不能的,由於上面說明,Session是存儲在對應Web服務器的內存的,不能進行共享,此時Spring-session就出現了,來幫咱們解決這個session共享的問題!web

集羣session

  1. 如何進行Session共享呢?

簡單點說就是請求http請求通過Filter職責鏈根據配置信息過濾器將建立session的權利由tomcat交給了Spring-session中的SessionRepository,經過Spring-session建立會話,並保存到對應的地方。redis

session共享

實際上實現Session共享的方案不少,其中一種經常使用的就是使用Tomcat、Jetty等服務器提供的Session共享功能,將Session的內容統一存儲在一個數據庫(如MySQL)或緩存(如Redis,Mongo)中,spring

一句話總結——
DelegatingFilterProxy引導每一個請求到名爲springSessionRepositoryFilter過濾器
RedisHttpSessionConfiguration建立名爲springSessionRepositoryFilter 的Spring Bean,繼承自Filter
springSessionRepositoryFilter替換容器默認的HttpSession支持爲Spring Session
Spring Session將Session路由至redis


(一)spring boot 實現Redis實現分佈式session功能的共享


spring boot 集成 redis-session:

實踐測試:
有一個業務:
步驟一:獲取驗證碼,服務端保存驗證碼在session上
步驟二:點擊驗證,服務端拿取session上的驗證碼與用戶輸入的做比較


首先在沒有redis的狀況下,步驟一指向服務器1,步驟二指向服務器2,原理上應該沒法驗證,由於session分佈在兩臺服務器上,
實踐結果與原理相同

而後在redis狀況下,步驟一指向服務器1,步驟二指向服務器2,步驟1、二仍然應該連貫順利進行,實踐結果與原理相同

再,在redis狀況下,步驟一指向服務器1,步驟二指向服務器2,步驟一進行後,刪掉redis清空,步驟二應該沒法驗證,實踐結果與原理相同

@Configuration
@EnableRedisHttpSession
public class RedisSessionConfig {
 
}
 

若是須要添加失效時間可使用如下的寫法:

@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60) //1分鐘失效
補充一下:
這個session的過時時間住了在註解上配置,也能夠在java中設置的:
session.setMaxInactiveInterval(3 * 60);//3分鐘失效
 

 
 
 
(二)9.30 出現問題: 

 
 

Error creating bean with name 'enableRedisKeyspaceNotificationsInitializer'

 
 

根據提示,去相應的頁面查看解決方案數據庫

Firing SessionDeletedEvent or SessionExpiredEvent is made available through the SessionMessageListener which listens to Redis Keyspace events. In order for this to work, Redis Keyspace events for Generic commands and Expired events needs to be enabled. For example:瀏覽器

redis-cli config set notify-keyspace-events Egx

If you are using @EnableRedisHttpSession the SessionMessageListener and enabling the necessary Redis Keyspace events is done automatically. However, in a secured Redis enviornment the config command is disabled. This means that Spring Session cannot configure Redis Keyspace events for you. To disable the automatic configuration add ConfigureRedisAction.NO_OP as a bean.緩存

For example, Java Configuration can use the following:tomcat

@Bean
public static ConfigureRedisAction configureRedisAction() {
    return ConfigureRedisAction.NO_OP;
}

XML Configuration can use the following:

<util:constant
    static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>
因此在redisconfig上注入bean

[java]  view plain  copy
  1. @Configuration  
  2. public class HttpSessionConfig {  
  3.     @Bean  
  4.     public static ConfigureRedisAction configureRedisAction() {  
  5.         return ConfigureRedisAction.NO_OP;  
  6.     }  
  7. }  

(三)原理簡述

  1. 每次請求都經過NoSql數據庫查詢,若是存在,則獲取值;反之存放值。  
  2. 我是經過redis來實現session的共享,其主要有一下兩種方法:  
  3. 1、經過tomcat服務器的拓展功能實現  
  4.     這種方式比較簡單,主要是經過繼承session的ManagerBase類,實現重寫session相關的方法,這種比較簡單,  
  5.     參考源碼連接(http://download.csdn.net/detail/fengshizty/9417242)。  
  6. 2、經過filter攔截request請求實現  
  7.     下面主要介紹這樣實現方式:  
  8.     (1)寫HttpSessionWrapper實現HttpSession接口,實現裏面session相關的方法。  
  9.     (2)寫HttpServletRequestWrapper繼承javax.servlet.http.HttpServletRequestWrapper類,重寫對於session  相關的方法。  
  10.     (3)寫SessionFilter攔截配置的請求url,過去cookie中  
  11.     的sessionId,若是爲空,對這次請求重寫生成一個新的sessionId,在sessionId構造新的HttpServletRequestWrapper對象。  
  12.     (4)寫SessionService實現session到redis的保存和過去,其key爲sessionId,value爲session對於的Map。  
  1.  

以上是常規實現的步驟,spring 幫咱們作了

增長配置類:

[java]  view plain  
  1. @EnableRedisHttpSession  
  2. public class HttpSessionConfig {  
  3.     @Bean  
  4.     public JedisConnectionFactory connectionFactory() {  
  5.             return new JedisConnectionFactory();  
  6.     }  
  7. }  
這個配置類有什麼用呢?

官方文檔:

The Spring configuration is responsible for creating a Servlet Filter that replaces the HttpSession implementation with an implementation backed by Spring Session. 

也就是說,這個配置類能夠建立一個過濾器,這個過濾器支持Spring Session代替HttpSession發揮做用

The @EnableRedisHttpSession annotation creates a Spring Bean with the name of springSessionRepositoryFilter that implements Filter. The filter is what is in charge of replacing the HttpSession implementation to be backed by Spring Session. In this instance Spring Session is backed by Redis.

@EnableRedisHttpSession註解會建立一個springSessionRepositoryFilter的bean對象去實現這個過濾器。過濾器負責代替HttpSession。

也就是說,HttpSession再也不發揮做用,而是經過過濾器使用redis直接操做Session。

(四)redis的數據

key的簡單介紹說明:

# 存儲 Session 數據,數據類型hash
Keyspring:session:sessions:XXXXXXX

# Redis TTL觸發Session 過時。(Redis 自己功能),數據類型:String
Keyspring:session:sessions:expires:XXXXX

#執行 TTL key ,查看剩餘生存時間


#定時Job程序觸發Session 過時。(spring-session 功能),數據類型:Set
Keyspring:session:expirations:XXXXX
取自:

Spring-Session實現Session共享入門教程


另有一片源碼分析:

Spring Session解決分佈式Session問題的實現原理

https://blog.csdn.net/xlgen157387/article/details/60321984

相關文章
相關標籤/搜索