快速實現 Tomcat 叢集 Session 共享
在應對巨大的使用者流量的網際網路場景中, 搭建 Tomcat 叢集是緩解 Web 伺服器負載的解決方式中必不可少的,而隨之帶來的會話資訊即 Session 不同步的問題也暴露出來: 使用者剛登入後,再次操作卻提示需要重新登入,嚴重影響著使用者體驗. 本文主要研究如何使用 Spring Session 框架來解決 Tomcat 叢集會話共享問題.若有補充,歡迎斧正.
正文
環境準備
- 3個 Tomcat 例項
- Redis
專案結構
專案比較簡單,除了啟動類之外,就只有一個控制器類.

控制器實現
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 複製程式碼
先簡單對檔案新增的配置進行簡單的說明:
SessionRepository.save(org.springframework.session.Session)
然後在將專案打包到各個 Tomcat 之後再次呼叫登入請求,然後在 Redis 中查詢下當前所有 KEYS

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

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