【Redis】分布式Session


一、問題引出

1.1 Session的原理

//默認創建一個session,默認值為true沒有找到對應的session 自動創建session
HttpSession session = request. getSession();
session.setAttribute("user", nameValue);
Object value = session.getAttribute("user");
  1. Session分為SessionIdSessionValue,Session本身是一個臨時的,sessionid和token(令牌)非常相似保證臨時且唯一;
  2. 請求和響應過程:服務器端接受到客戶端請求,會創建一個Session,使用響應頭返回SessionId給客戶端。瀏覽器獲取到SessionId后,保存在本地Cookie中;
  3. 下一次請求時:客戶端讀取到本地的SessionId,存放在請求頭中,服務器端從請求頭中獲取到對應的Sessionid,使用SesisonId在本地Session內存中查詢。

1.2 問題概述

1.分布式Session一致性(白話文服務器集群Session共享的問題)
2.分析分布式Session一致性
3.Session的作用?服務器(Tomcat) 與客戶端(瀏覽器)保存整個通訊的會話基本信息。
4.應用場景: javaee基礎 登陸流程做法(賬號密碼登陸成功之后,獲取到userid,存放在session,下次獲取用戶信息的之后,直接從session會話中獲取。)防止表單重復提交。
Session理解本地jvm緩存,sesison存放 服務器,返回sessionid給客戶端。

二、解決方案

  1. 使用nginx (反向代理) ip綁定 同一個ip 只能在指定的同一個機器訪問(沒有 負載均衡)
  2. 使用數據庫效率不是很高
  3. tomcat內置支持對session同步( 不推薦),同步可能會產生延遲
  4. 使用SpringSession框架相當於把我們的Session值緩存到redis中。面試題:你們項目在發布的時候,Session如何控制不失效的? 使用緩存框架,緩存Session的值(一級和二級) Spring Session重寫httpsession框架,將對應的值緩存到redis中有點類似與一級和二級緩存
  5. 以使用token替代Session功能, sessionid不同他的域名也不同,移動會話信息使用令牌方式替代Session,Token最終存放在redis中, redis支持分布式共享

三、代碼實現-使用Token代替Session

Token存放在Redis中

3.1 Service

RedisService.java

@Component
public class RedisService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // public void set(String key, Object object, Long time) {
    // stringRedisTemplate.opsForValue();
    // // 存放String 類型
    // if (object instanceof String) {
    // setString(key, object);
    // }
    // // 存放 set類型
    // if (object instanceof Set) {
    // setSet(key, object);
    // }
    // // 設置有效期 以秒為單位
    // stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
    // }
    //
    public void setString(String key, Object object) {
        // 開啟事務權限
        // stringRedisTemplate.setEnableTransactionSupport(true);
        try {
            // 開啟事務 begin
            // stringRedisTemplate.multi();
            String value = (String) object;
            stringRedisTemplate.opsForValue().set(key, value);
            System.out.println("存入完畢,馬上開始提交redis事務");
            // 提交事務
            // stringRedisTemplate.exec();
        } catch (Exception e) {
            // 需要回滾事務
            // stringRedisTemplate.discard();
        }
    }

    public void setSet(String key, Object object) {
        Set<String> value = (Set<String>) object;
        for (String oj : value) {
            stringRedisTemplate.opsForSet().add(key, oj);
        }
    }

    public String getString(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

}

TokenService.java


@Service
public class TokenService {
    @Autowired
    private RedisService redisService;

    // 新增 返回token
    public String put(String value) {
        //1.判斷是否為空
        if(value == null) {
            return null;
        }
    
        //2. 獲取對應的token(token實際等於key)
        String token = getToken();
        //3.存入redis中
        redisService.setString(token, value);
        //4.返回token
        return token;
    }

    // 獲取信息
    public String get(String token) {
        String reuslt = redisService.getString(token);
        return reuslt;
    }

    public String getToken() {
        return UUID.randomUUID().toString();
    }

}

3.2 TokenController

@RestController
public class TokenController {
    @Autowired
    private TokenService tokenService;
    @Value("${server.port}")
    private String serverPort;

    @RequestMapping("/put")
    public String put(String nameValue) {
        String token = tokenService.put(nameValue);
        return token + "-" + serverPort;
    }

    @RequestMapping("/get")
    public String get(String token) {
        String value = tokenService.get(token);
        return value + "-" + serverPort;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM