快速實現 Tomcat 叢集 Session 共享

聞人_發表於2019-01-28

快速實現 Tomcat 叢集 Session 共享

前言

在應對巨大的使用者流量的網際網路場景中, 搭建 Tomcat 叢集是緩解 Web 伺服器負載的解決方式中必不可少的,而隨之帶來的會話資訊即 Session 不同步的問題也暴露出來: 使用者剛登入後,再次操作卻提示需要重新登入,嚴重影響著使用者體驗. 本文主要研究如何使用 Spring Session 框架來解決 Tomcat 叢集會話共享問題.若有補充,歡迎斧正.

正文

環境準備
  • 3個 Tomcat 例項
  • Redis
專案結構

專案比較簡單,除了啟動類之外,就只有一個控制器類.

快速實現 Tomcat 叢集 Session 共享

控制器實現

UserController 主要有兩個請求方法, 一個接受使用者登入,另一個獲取登入資訊的;當呼叫 login 介面後將請求資料存在當前的 Session 中,然後在 Session 有效的期間內呼叫 getUserInfo 介面都能獲取到對應登入時的資料.

@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping("/login")
    public String login(HttpSession session, HttpServletRequest request) {
        String id = request.getParameter("id");
        String name = request.getParameter("name");
        HashMap<Object, Object> userInfo = new HashMap<>(16);
        userInfo.put("id", id);
        userInfo.put("name", name);
        session.setAttribute("USER_INFO", userInfo);
        return userInfo + "  成功儲存到會話中";
    }

    @RequestMapping("/getUserInfo")
    public String getUserInfo(HttpSession session, HttpServletRequest request) {
        Object user_info = session.getAttribute("USER_INFO");
        if (user_info == null) {
            return "請先登入,再讀取會話資料";
        }
        return "從會話中讀取資料 " + user_info;
    }
}
複製程式碼

現在我們將3個 Tomcat 例項搭建成叢集,然後都運轉這個專案; 如果我們針對一個 Tomcat 例項傳送登入請求,然後再次傳送獲取使用者資訊請求,此時這個 Tomcat 是能夠正確返回之前登入後儲存的資訊;而當我們在另一個 Tomcat 例項嘗試獲取使用者資訊時,則會返回 "請先登入,再讀取會話資料";這說明這兩個 Tomcat 例項的會話資訊是獨立存在的.

使用 Spring Session

現在想要讓這些 Tomcat 間能夠對會話資訊共享,只要登入一次,就可以在其他叢集例項上訪問資料,就可以使用 Spring Session 框架實現,它能在對程式無任何侵入的情況 實現 Session 的共享. 首先我們要做 POM 檔案引入 Spring Session 相關的庫

    <dependency>
		<groupId>org.springframework.session</groupId>
		<artifactId>spring-session-data-redis</artifactId>
	</dependency>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
    </dependency>
複製程式碼

從依賴的庫可以看到 Spring Session 利用記憶體資料庫 Redis 來儲存會話資訊,以此達到叢集間會話的共享.

引入後依賴庫之後,我們就需要在 application.properties 檔案上進行 Session 的配置.

server.servlet.session.timeout=3600 //1
spring.session.redis.flush-mode=IMMEDIATE //2 
spring.session.redis.namespace=spring:session //3

// 4
spring.redis.host=127.0.0.1
spring.redis.password=
spring.redis.port=6380
複製程式碼

先簡單對檔案新增的配置進行簡單的說明:

  1. 限定 Session 超時時間,預設單位為秒
  2. 設定 Session 重新整理模式,有 ON_SAVE 和 IMMEDIATE; IMMEDIATE 表示立即寫到 Redis 中;而 ON_SAVE 表示只有當執行 SessionRepository.save(org.springframework.session.Session) 時才會寫入到 Redis.
  3. 存放到 Redis 中會話的名稱空間.
  4. 連線 Redis 資料庫

然後在將專案打包到各個 Tomcat 之後再次呼叫登入請求,然後在 Redis 中查詢下當前所有 KEYS

快速實現 Tomcat 叢集 Session 共享
從圖裡就可以看出快取中對 Session 資料的命名就是以前配置檔案中的名稱空間來的,我們取一下里面的 KEY 檢視它的內容,裡面就有我們所存的使用者資訊
快速實現 Tomcat 叢集 Session 共享

然後我們再對另個 Tomcat 請求獲取使用者資訊,就可以發現返回結果不再是之前的"請先登入,再讀取會話資料",而能正常返回在之前一臺 Tomcat 例項上登入的會話資料資訊.這也說明了 Tomcat 叢集間的會話共享實現了, 是不是很簡單呢?

參考

相關文章