springboot基礎:多節點登錄session共享

前言

通常我們的session保存在服務器內存中,那麼當我們部署多臺服務器時,如何實現session共享

傳統的單點登錄示例

  1. 新建一個springboot 項目,引入web-starter、lombok配置依賴
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
  1. 添加模擬登錄登出的代碼
package com.summergao.sessiontest.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@RestController
@RequestMapping("/sessiontest")
@Slf4j
public class SessionTestController {

    /**
     * 登錄
     * @param request
     * @param name
     * @return
     */
    @GetMapping("/login")
    public String login(HttpServletRequest request, String name) {
        log.info("登錄:{}", name);
        HttpSession session = request.getSession();
        session.setAttribute("name", name);
        return name + " login success";
    }

    /**
     * 登出
     * @param request
     * @return
     */
    @GetMapping("/logout")
    public String logout(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String name= session.getAttribute("name") + "";
        session.removeAttribute("name");
        log.info("登出:{}", name);
        return name + " logout success";
    }

    /**
     * 獲取用戶名
     * @param request
     * @return
     */
    @GetMapping("/getusername")
    public String getUsername(HttpServletRequest request) {
        HttpSession session = request.getSession();
        return "hello," + session.getAttribute("name") + "";
    }
}

3. 啓動服務器測試demo是否正常。可以看到登錄成功,並且能夠獲取到用戶名。

http://localhost:8081/sessiontest/login?name=SummerGao

http://localhost:8081/sessiontest/getusername

4. 模擬多服務器,此時在8082再啓動一臺服務器

-Dserver.port=8082

http://localhost:8082/sessiontest/getusername

可以發現8082這臺服務器並不能獲取到用戶名,說明session未在多服務器之間共享。server1登錄後,server2無法獲取到server1的登錄信息(session)。

如何解決多服務器session共享的問題?

我們只需要將session存儲到DB裏面,兩臺server共享DB,即可實現sesssion共享。

springboot提供了mongodb、redis、jdbc、hazelcast(一款分佈式緩存)等方案。
這裏我們選擇redis作爲session共享方案,redis作爲noSQL數據庫,其性能非常優秀。由於採用了外部的DB存儲,所以多節點的部署可以既可以在同一臺物理機器上,也可以在不同的物理機器上,沒有地理的限制。
那麼具體如何實現session共享呢?

由於選擇了redis的方案,所以需要先擁有一臺可用的redis服務器。如果已經有redis,可以忽略。
安裝方案:

安裝redis

  • docker安裝redis的方案:
docker run -d  --name redis -p 6379:6379 -d redis:latest
  • windows安裝redis方案

一路next即可,沒啥難度。可參考: https://www.redis.com.cn/redis-installation.html

  • 管理redis的可視化工具

RedisDesktopManager

一款桌面的redis管理工具,可以輔助用戶查看redis裏面的數據,對數據進行操作和管理。

 

session共享實踐

下面我們基於前面的代碼對項目進行修改,使其實現多服務器之間的session共享。

 

  1. 導入依賴
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
  1. 配置spring-session方案
spring:
  # session配置
  session:
    timeout: 86400 # 設置session失效時間
    store-type: redis # 修改spring-session存儲配置,默認存儲到服務器內存中,現在設置存到redis中(關鍵)
  # redis配置
  redis:
    port: 6379 # redis的端口號(這裏是我的redis容器在docker中對應的端口號)
    host: localhost # redis服務器ip
    password:  # 密碼(默認爲空)
    database: 0 # 設置存入redis的哪一個庫(默認是0)

3. 兩個服務都啓動,在其中一臺服務器進行登錄測試,如果兩臺服務器都能獲取到username即視爲session實現了共享。

到此,基於redis的多服務器session共享成功。

登出

執行登出操作,可以看到兩個服務器都不能獲取username,則表明單點登出,多節點都會登出。

http://localhost:8081/sessiontest/logout

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章