【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;
    }
}
原文地址:https://www.cnblogs.com/haoworld/p/redis-fen-bu-shisession.html