SpringBoot 使用 Redis 實現 Session 共享

SpringBoot 使用 Redis 實現 Session 共享

使用 Redis 實現 Session 共享

1 什麼是 Session

因爲 HTTP 協議是無狀態的協議,於是服務端須要記錄用戶的狀態時,就須要用某種機制來識具體的用戶。Session 是另外一種記錄客戶狀態的機制,不一樣的是 Cookie 保存在客戶端瀏覽器中,而 Session 保存在服務器上。客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上,這就是 Session。客戶端瀏覽器再次訪問時只須要從該 Session 中查找該客戶的狀態就能夠了。java

2 爲何須要同步session ?

當用戶量比較大時候一個tomcat可能沒法處理更多的請求,超過單個tomcat的承受能力,可能會出現用戶等待,嚴重的致使tomcat宕機。

在這裏插入圖片描述

這時候咱們後端可能會採用多個tomcat去處理請求,分派請求,不一樣請求讓多個tomcat分擔處理。

登陸的時候可能採用的是tomca1,下單的時候可能採用的是tomcat2 等等等。web

若沒有session共享同步,可能在tomcat1登陸了,下一次請求被分派到tomcat2上,這時候用戶就須要從新登陸。redis

在實際工做中咱們建議使用外部的緩存設備來共享 Session,避免單個節點掛掉而影響服務,使用外部緩存 Session 後,咱們的
共享數據都會放到外部緩存容器中,服務自己就會變成無狀態的服務,能夠隨意的根據流量的大小增長或者減小負載的設備。

目前主流的分佈式 Session 管理有兩種方案。spring

1 Session 複製

部分 Web 服務器可以支持 Session 複製功能,如 Tomcat。用戶能夠經過修改 Web 服務器的配置文件,讓 Web 服務器進行 Session 複製,保持每個服務器節點的 Session 數據都能達到一致。數據庫

這種方案的實現依賴於 Web 服務器,須要 Web 服務器有 Session 複製功能。當 Web 應用中 Session 數量較多的時候,每一個服務器節點都須要有一部份內存用來存放 Session,將會佔用大量內存資源。同時大量的 Session 對象經過網絡傳輸進行復制,不但佔用了網絡資源,還會由於複製同步出現延遲,致使程序運行錯誤。apache

在微服務架構中,每每須要 N 個服務端來共同支持服務,不建議採用這種方案。後端

這種session 管理方式,能夠參考此篇文章:傳送門瀏覽器

2 Session 集中存儲

在單獨的服務器或服務器集羣上使用緩存技術,如 Redis 存儲 Session 數據,集中管理全部的 Session,全部的 Web 服務器都從這個存儲介質中存取對應的 Session,實現 Session 共享。將 Session 信息從應用中剝離出來後,其實就達到了服務的無狀態化,這樣就方便在業務極速發展時水平擴充。緩存

Spring Session
Spring Session 提供了一套建立和管理 Servlet HttpSession 的方案。Spring Session 提供了集羣 Session(Clustered Sessions)功能,默認採用外置的 Redis 來存儲 Session 數據,以此來解決 Session 共享的問題。tomcat

Spring Session 爲企業級 Java 應用的 Session 管理帶來了革新,使得如下的功能更加容易實現:

API 和用於管理用戶會話的實現; HttpSession,容許以應用程序容器(即 Tomcat)中性的方式替換 HttpSession;
將 Session 所保存的狀態卸載到特定的外部 Session 存儲中,如 Redis 或 Apache Geode
中,它們可以以獨立於應用服務器的方式提供高質量的集羣; 支持每一個瀏覽器上使用多個
Session,從而可以很容易地構建更加豐富的終端用戶體驗; 控制 Session ID
如何在客戶端和服務器之間進行交換,這樣的話就能很容易地編寫 Restful API,由於它能夠從 HTTP 頭信息中獲取 Session
ID,而沒必要再依賴於 cookie; 當用戶使用 WebSocket 發送請求的時候,可以保持 HttpSession 處於活躍狀態。
須要說明的很重要的一點就是,Spring Session 的核心項目並不依賴於 Spring 框架,所以,咱們甚至可以將其應用於不使用
Spring 框架的項目中。

環境搭建:
版本:

SpringBoot 2.0.5.RELEASE
JDK 1.8

引入依賴包

<dependency>

<groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--spring session 和 redis starter集成包 目的用於分佈式session管理-->
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>


    <!--redis-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!--springboot 2.0 以後底層鏈接池採用 Lettuce 做爲鏈接池 導入此包-->
    <!--Spring Boot 1.0 默認使用的是 Jedis 客戶端,2.0 替換成了 Lettuce,-->
    <!--但若是你從 Spring Boot 1.5.X 切換過來,幾乎感覺不大差別,-->
    <!--這是由於 spring-boot-starter-data-redis 爲咱們隔離了其中的差別性。-->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>



    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional> <!-- 這個須要爲 true 熱部署纔有效 -->
    </dependency>


    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

配置文件

server.port=8080



# Redis 配置
# Redis 數據庫索引(默認爲0)
spring.redis.database=0
# Redis 服務器地址
spring.redis.host=localhost
# Redis 服務器鏈接端口
spring.redis.port=6379  
# Redis 服務器鏈接密碼(默認爲空)
spring.redis.password=
# 鏈接池最大鏈接數(使用負值表示沒有限制)
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.shutdown-timeout=100
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
/**
 *
 * maxInactiveIntervalInSeconds: 設置 Session 失效時間
 * 使用 Redis Session 以後,原 Spring Boot 中的 server.session.timeout 屬性再也不生效。
 *
 */
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class SessionConfig {
}

登陸以及獲取session代碼

@RequestMapping(value = "/setSession")
    public Map<String, Object> setSession (HttpServletRequest request){
        Map<String, Object> map = new HashMap<>();
        request.getSession().setAttribute("message", request.getRequestURL());
        map.put("request Url", request.getRequestURL());
        return map;
    }

    @RequestMapping(value = "/getSession")
    public Object getSession (HttpServletRequest request){
        Map<String, Object> map = new HashMap<>();
        map.put("sessionId", request.getSession().getId());
        map.put("message", request.getSession().getAttribute("message"));
        return map;
    }


    @RequestMapping(value = "/login")
    public String login (HttpServletRequest request,String userName,String password){
        String msg="logon failure!";

        if (userName!=null && "admin".equals(userName) && "123".equals(password)){
            request.getSession().setAttribute("user",userName);
            msg="login successful!";
        }
        return msg;
    }

而後複製一份 該端口爲8282

測試:
在端口是8282 的項目中登陸
在這裏插入圖片描述

而後在端口是8282 和 8080的項目中獲取session
在這裏插入圖片描述

在這裏插入圖片描述

兩個服務中session id 是一致的,說明咱們的session管理成功。

使用Spring Session 能夠將session單獨的從每一個服務總抽離出來,存儲到redis中進行集中管理。相對於每一個服務複製session的方式可謂簡便至極,也不須要在每一個Tomcat中修改配置文件,添加jar包等操做。

相關文章
相關標籤/搜索