第一,为什么会出现分布式Session
现在我们的项目都是服务化的,都是分布式的,服务器节点一般都是部署在不同服务器下的(同一个服务部署到不同的机器上),通过负载均衡进行访问的,所以呢,Session,也就被分布式化了,因为Session会话只能在同一台服务器上生效,在这种情况下,就会导致,用户访问不同的服务器导致Session会话不一致的问题,在JavaWeb中根本没有设置SessionId的方法,所以SessionID是只读的,而且SessionID是服务器内部生成的所以这就成了一个难题
第二,如何解决?
以下是市面上总结的四种解决方案
A.使用session内部共享机制可以解决跨域Session的处理,但是Session同步时会有问题的,当网络出现了延迟卡顿,那么很容易出现问题,而且实现起来非常复杂,所以我们不会用这种方案来做的
B.使用数据库存放Session(但是存储数据库里面需要进行查询校验,耗费数据库性能),所以何不把他放到缓存里面呢,所以这个方案我们也放弃了
C.Memcached(高效率的缓存数据库),他的并发效率效率比Redis高,他每秒的QPS(每秒访问量)可以达到10万,所以说,也是很不错的了,而redis的QPS只能达到5万,那么为什么我们秒杀中不使用memcached呢?用户是需要共享session,秒杀的时候,很多用户会去抢一样东西,产生我们的资源竞争,虽然它的效率比redis高,但是!!请注意,memcached中有个BUG,在进行加或者进行减的时候(decr和incr)会出现库存问题,如果你传过来的秒杀需求数量值大于你的真实库存值的时候,这时候就会默认库存为0,到现在这个问题还没有解决,所以,这个时候我们肯定不会用它,因为它有BUG,所以呢redis的可靠性就比mecached高,虽然效率没它高吧,但是数据最起码不会出现问题
D.第四种就是用我们的redis了,redis可靠性比较高,也没有什么突出或者致命的的BUG
所以我推荐,分布式Session解决方案就用redis解决
那么如何进行实现的呢?
服务其内部生成会话id,当客户端与服务器建立请求的时候,就会把服务器的sessionid通过cookie的方式写入到客户端里面来机制,这样就能保证是同一个会话了
具体点说:就是在建立请求时,建立一个SessionID,以response.addCookie(“Jsessionid”,"值")的方式发送到客户端(在登陆成功的时候产生唯一ID存储到Cookie中,id为key,用户登录对象为value的方式存储)
在操作功能的时候每次都获取到redis中ID与request->Header中的cookie进行对比,如果是就让其进行操作
看一下核心代码
private void addCookie(HttpServletResponse response,String token , UserInfo user) {
// 存储到redis中
redisService.set(COOKIE_TOKEN_PREFIX, token, user, TimeUnit.SECONDS, 3600);
// 创建Cookie发送到客户端
Cookie cookie = new Cookie(COOKIE_TOKEN_PREFIX, token);
cookie.setMaxAge(3600);
cookie.setPath("/");
// 添加到客户端
response.addCookie(cookie);
}
@Override
public boolean login(HttpServletResponse response, LoginVo loginVo) {
UserInfo userInfo = userMapper.getUserByAccount(loginVo.getAccount());
if (userInfo == null) {
throw new GlobalException(CodeMsg.ACCOUNT_ERROR);
}
// 获取数据库中存储的密码及盐值
String pass = userInfo.getUserPassword();
String salt = userInfo.getSalt();
// 获取页面输入的密码
String inputPass = loginVo.getPassword();
String handlerPass = MD5Util.clientPassToDbPass(inputPass, salt);
if (!pass.equals(handlerPass)) {
throw new GlobalException(CodeMsg.PASSWORD_ERROR);
}
// 模拟会话ID
String token = UUIDUtil.uuid();
// 调用添加保存cookie
addCookie(response, token,userInfo);
return true;
}
/**
* 根据token值获取到对应用户信息
* @param token
* @return
*/
public UserInfo getUserByToken(String token) {
return null;
}
为了安全这里进行了MD5加密
其实就是这么回事,并不困难,有帮助的话记得点赞!