1. 程式人生 > 程式設計 >分散式Session的幾種實現方式

分散式Session的幾種實現方式

SpringBoot 分散式session

在如今伺服器叢集的情況下,使用者登入會話狀態的儲存也從單機的變成了分散式要求的,下面詳細說一下幾種分散式session儲存方案。

  1. session複製:在支援session複製的伺服器上進行,同步session,保持session一致

方案:tomcat-redis-session-manager

  1. session粘滯:強行分發session到各個伺服器

方案:負載均衡

  1. cookie儲存session:把sessionid儲存到cookie中(不安全,cookie容易被盜取,可以儲存不重要的資料)
  2. 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管理資料和快取,更加高效

  1. 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;
    }複製程式碼

  1. sessionManager中注入cookie儲存jsessionId
@Bean
    public SimpleCookie cookie() {
        SimpleCookie cookie = new SimpleCookie("JSESSIONID");
        cookie.setHttpOnly(true);
        cookie.setPath("/");
        return cookie;
    }複製程式碼

  1. 再在sessionManager中注入redisSessionDao負責session持久化
@Bean
    public RedisSessionDAO redisSessionDao(){
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());
        return redisSessionDAO;
    }複製程式碼