分散式Session的幾種實現方式
阿新 • • 發佈:2019-12-31
SpringBoot 分散式session
在如今伺服器叢集的情況下,使用者登入會話狀態的儲存也從單機的變成了分散式要求的,下面詳細說一下幾種分散式session儲存方案。
- session複製:在支援session複製的伺服器上進行,同步session,保持session一致
方案:tomcat-redis-session-manager
- session粘滯:強行分發session到各個伺服器
方案:負載均衡
- cookie儲存session:把sessionid儲存到cookie中(不安全,cookie容易被盜取,可以儲存不重要的資料)
- session集中管理:把使用者的session儲存在單臺或者叢集伺服器的快取中,所有web伺服器從中拿取session,實現session共享
方案:Redis儲存使用者生成的sessionId或者儲儲存存sessionId的cookie
這裡只講解第四種方案,使用最多最穩定
Redis做快取持久化儲存session
Redis儲存cookie,裡面儲存使用者生成的uuid(token作為sessionId)
- cookie名稱和過期時間
public static final String COOKIE_NAME_TOKEN = "token";
private static final ex = 3600;複製程式碼
- 建立cookie並儲存到redis
private String addCookie(HttpServletResponse response,SeckillUser user){
String token = UUIDUtil.uuid();
redisService.set(token,user);//使用redis把token作為鍵儲存user作為值 我使用jedis自己實現的也可以使用redisTemplate
Cookie cookie = new Cookie(COOKIE_NAME_TOKEN,token);//設定cookie 名稱為token
cookie.setMaxAge(ex);//設定過期時間
cookie.setPath("/");
response.addCookie(cookie);
return token;
}複製程式碼
- uuid作為sessionid生成工具
public class UUIDUtil {
public static String uuid(){
return UUID.randomUUID().toString();
}
}複製程式碼
使用Shiro整合的crazy-cake
(使用Redis儲存SessionId)
- shiro是一個Web安全框架,用於登入認證,使用者身份授權,使用易於
spring-security
,還可以繼承session、cookie分散式儲存
不瞭解的可以看這篇博文:Shiro的使用以及整合redis做快取
快取
-
使用快取儲存session(單伺服器使用EhCacheManager)
- 但是在分散式系統中,伺服器叢集情況下,EhCacheManager無法解決資料共享(會多次查詢資料庫),則選擇使用redis作為快取
Redis實現shiro快取
- 分散式共享session和授權資訊需要把session和授權持久化到資料庫或者快取 shiro叢集為了防止多次插查詢資料庫
-
自定義實現類:或者使用crazycake開源shiro-redis實現好的工具
- RedisSessionDAO 可以繼承EnterpriseCacheSessionDAO實現session控制
- RedisCache 繼承Cache類實現具體redis操作快取(remove、get、set、keys
- RedisCacheManager 實現介面CacheManager的getCache獲得RedisCache交給securityManager管理
使用了ConcurrentMap管理資料和快取,更加高效
- 在
ShiroConfig
配置類中把sessionManager
交給DefaultWebSecurityManager
管理
@Bean
public DefaultWebSessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//session時間
sessionManager.setGlobalSessionTimeout(redisConfig().getTimeout());
//刪除無效session
sessionManager.setDeleteInvalidSessions(true);
log.info("sessionManager注入成功");
sessionManager.setSessionIdCookie(cookie());
// sessionDao 分散式共享session和授權資訊需要把session和授權持久化到資料庫或者快取 shiro叢集為了防止多次插查詢資料庫
sessionManager.setSessionDAO(redisSessionDao());
return sessionManager;
}複製程式碼
- 在
sessionManager
中注入cookie儲存jsessionId
@Bean
public SimpleCookie cookie() {
SimpleCookie cookie = new SimpleCookie("JSESSIONID");
cookie.setHttpOnly(true);
cookie.setPath("/");
return cookie;
}複製程式碼
- 再在
sessionManager
中注入redisSessionDao
負責session持久化
@Bean
public RedisSessionDAO redisSessionDao(){
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());
return redisSessionDAO;
}複製程式碼