点击关注公众号,实用技术文章及时了解

平常做的项目都是在一台应用系统,并且所有的操作都在一台Tomcat服务器上,并不会引发Session共享的问题,所以并不会对我们的系统产生影响,但是当我们部署多个微服务的时候,再搭配Nginx进行负载均衡时,如果不处理分布式Session问题,我们在系统中访问不同功能时就会频繁出现用户登录的操作。

图解分析原因:

前提:用户登录功能和图中的商品订单模块、秒杀抢购模块属于单独的微服务模块

用户登录成功后想要访问图中其他两个模块的功能时,由于Nginx使用默认负载均衡策略(轮询),这时请求会按照时间顺序逐一分发到后端应用上,也就是说用户在Tomcat1上登录成功之后,用户的信息放在Tomcat1的Session里,过了一会,用户想要进行秒杀活动的功能操作,请求又被Nginx分发到了Tomcat2,而这时的Tomcat2上的Session里还没有用户信息,于是就是出现让用户重新登录的情况,在微服务分布式项目中,不同的功能模块必然会被分列成各自的微服务,假设访问一个功能都需要重新登录一次,用户的体验必然会大幅度下降!

那如何来解决分布式Session问题呢?

一、解决方案列举

1. Session复制

优点:

  • 无需修改代码,只需要修改Tomcat配置

缺点:

  • Session同步传输占用内网宽带

  • 多台Tomcat同步性能指数级下降

  • Session占用内存,无法有效水平扩展

2. 前端存储

优点:

  • 不占用服务器内存

缺点:

  • 存在安全风险

  • 数据大小受cookie限制

  • 占用外网宽带

3. Session粘滞

优点:

  • 无需修改代码

  • 服务端可以水平扩展

缺点:

  • 增加新机器,会重新Hash,导致重新登录

  • 应用重新启动后,需要重新登录

4. 后端集中存储

优点:

  • 安全

  • 容易水平扩展

优点:

  • 增加复杂度

  • 需要修改代码

二、Java代码实现解决分布式Session

1. SpringSession - Redis解决分布式Session

添加依赖

<!--Redis-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--commons-pools2 对象池依赖-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
<!--spring session 依赖-->
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId>
</dependency>

添加Redis配置

## Redis配置
spring:redis:# 服务器地址host: localhost# 端口port: 6379# 数据库database: 0# 超时时间connect-timeout: 10000mslettuce:pool:# 最大连接数max-active: 8# 最大连接阻塞等待时间 默认 -1max-wait: 10000ms# 最大空闲时间 默认8max-idle: 200# 最小空闲连接 默认8min-idle: 5

业务逻辑实现

/*** 登录功能* @param loginVo* @return*/
@Override
public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {String username = loginVo.getUserName();String password = loginVo.getPassword();User user = userMapper.selectByUserName(username);if (user == null){throw new GlobalException(RespBeanEnum.LOGIN_ERROR);}//判断密码是否正确if (!MDUtils.formPassToDBPass(password,user.getSalt()).equals(user.getPassword())){throw new GlobalException(RespBeanEnum.LOGIN_ERROR);}//使用UUID生成字符串代替CookieString ticket = UUIDUtil.uuid();request.getSession().setAttribute(ticket,user);CookieUtil.setCookie(request,response,"userTicket",ticket);return RespBean.success();
}

视图控制层

/*** 跳转商品列表* @param session* @param model* @return*/
@RequestMapping("/toList")
public String toList(HttpSession session, Model model,@CookieValue("userTicket")String ticket){if (StringUtils.isEmpty(ticket)){return "login";}User user = (User) session.getAttribute(ticket);if (user == null){return "login";}model.addAttribute("user",user);return "goodsList";
}

登录测试

打开Redis管理软件发现Session信息已经添加到Redis中了

2. Redis解决分布式Session

导入依赖

<!--Redis-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--commons-pools2 对象池依赖-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>

Redis配置参考 【SpringSession - Redis解决分布式Session】

业务逻辑层

@Override
public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {String username = loginVo.getUserName();String password = loginVo.getPassword();User user = userMapper.selectByUserName(username);if (user == null){throw new GlobalException(RespBeanEnum.LOGIN_ERROR);}//判断密码是否正确if (!MDUtils.formPassToDBPass(password,user.getSalt()).equals(user.getPassword())){throw new GlobalException(RespBeanEnum.LOGIN_ERROR);}//成功CookieString ticket = UUIDUtil.uuid();//将用户信息存入到redis中redisTemplate.opsForValue().set("userTicket",ticket);redisTemplate.opsForValue().set("user:"+ticket,user);//request.getSession().setAttribute(ticket,user);CookieUtil.setCookie(request,response,"userTicket",ticket);return RespBean.success();
}/*** 根据cookie获取cookie* @param ticket* @return*/
@Override
public User getUserByByCookie(String ticket,HttpServletRequest request,HttpServletResponse response) {if (StringUtils.isEmpty(ticket)){return null;}User user = (User) redisTemplate.opsForValue().get("user:" + ticket);if (user == null){CookieUtil.setCookie(request,response,"userTicket",ticket);}return user;
}

视图控制层

/*** 跳转商品列表* @param session* @param model* @return*/
@RequestMapping("/toList")
public String toList(HttpSession session, Model model,HttpServletRequest request,HttpServletResponse response){String ticket = (String) redisTemplate.opsForValue().get("userTicket");if (StringUtils.isEmpty(ticket)){return "login";}//User user = (User) session.getAttribute(ticket);User user = userService.getUserByByCookie(ticket, request, response);if (user == null){return "login";}model.addAttribute("user",user);return "goodsList";
}

测试成功

查看Redis管理工具

来源:blog.csdn.net/Gaowumao/article/

details/124309548

推荐

Java面试题宝典

技术内卷群,一起来学习!!

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!

深入了解分布式 Session,这篇就够了!相关推荐

  1. 分布式中Redis实现Session终结篇

    上一篇使用Redis实现Session共享方式虽然可行,但是实际操作起来却很麻烦,现有代码已经是这个样子了,总不可能全部换掉吧!好吧,这是个很实际的问题,那么能不能实现无侵入式的分布式Session共 ...

  2. [转]分布式中Redis实现Session终结篇

    本文转自:http://www.cnblogs.com/yanweidie/p/4763556.html 上一篇使用Redis实现Session共享方式虽然可行,但是实际操作起来却很麻烦,现有代码已经 ...

  3. Cookie、Session、Token、JWT 看一篇就够了

    目录 Cookie.Session.Token.JWT 看一篇就够了 什么是认证(Authentication) 什么是授权(Authorization) 什么是凭证(Credentials) 怎么让 ...

  4. 从新手到架构师,一篇就够:从100到1000万高并发的架构演进之路

    1.引言 本文以设计淘宝网的后台架构为例,介绍从一百个并发到千万级并发情况下服务端的架构的14次演进过程,同时列举出每个演进阶段会遇到的相关技术,让大家对架构的演进有一个整体的认知.文章最后汇总了一些 ...

  5. IM扫码登录技术专题(三):通俗易懂,IM扫码登录功能详细原理一篇就够

    本文引用了作者"大古同学"的"二维码扫码登录是什么原理"一文的主要内容,为了更好的理解和阅读,即时通讯网收录时有修订和改动,感谢原作者的分享. 1.引言 自从微 ...

  6. 170222、使用Spring Session和Redis解决分布式Session跨域共享问题

    使用Spring Session和Redis解决分布式Session跨域共享问题 原创 2017-02-27 徐刘根 Java后端技术 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用 ...

  7. Hbase基础(特点、架构、应用场景、集群搭建、HA设计)这一篇就够了

    Hbase基础(特点.架构.应用场景.集群搭建.HA设计)这一篇就够了 1. Hbase特点 2. Hbase VS RDBMS 3. Hbase架构及版本选择 4. Hbase应用场景 5. Ntp ...

  8. api网关选型_如何轻松打造百亿流量API网关?看这一篇就够了(下)

    如何轻松打造百亿流量API网关?看这一篇就够了(上) 上篇整体描述了网关的背景,涉及职能.分类.定位环节,本篇进入本文的重点,将会具体谈下百亿级流量API网关的演进过程. 准备好瓜子花生小板凳开始积累 ...

  9. 基于ZooKeeper的分布式Session实现

    基于ZooKeeper的分布式Session实现 [转 http://blog.csdn.net/jacktan/article/details/6112806] 认识ZooKeeper ZooKee ...

最新文章

  1. mysql 监控语句_做一个mysql监控系统应该掌握的一些基本语句
  2. SAR 和光学图像配准研究
  3. DL之DNN优化技术:利用Batch Normalization(简介、入门、使用)优化方法提高DNN模型的性能
  4. C++ 标准模板库(STL)
  5. 向上造型和向下造型_国标舞So easy?!亲,你怕是凹错造型咯~
  6. 华为4X和4C无法使用电信4G的解决办法
  7. Python day13文件的读写
  8. 国内的优秀HTML5前端开发框架
  9. 李宏毅机器学习——逻辑回归
  10. Freeswitch视频会议终于成功,及提供解决办法
  11. 汉诺塔c语言代码实现
  12. reviewboard使用 与原理
  13. 链接Maya和UE4实现real-time预览——Connecting Maya to Unreal with Live Link
  14. 开源项目9GAG源码解析与Material改造(一)
  15. cox回归模型python实现_生存分析Cox回归模型(比例风险模型)的spss操作实例
  16. tzoj 3847 Mowing the Lawn (单调队列 )
  17. 操作系统:什么是中断?
  18. 前端基础第一天:HTML常用标签知识点
  19. 项目 调度 服务器,(2)项目构建(Reactor部分)【Lars-基于C++负载均衡远程服务器调度系统教程】...
  20. SPSS Modeler 多元线性回归分析(指南 第九章)

热门文章

  1. sql server任何版本安装新实例
  2. [13]-Connectors
  3. MAC终端给文件夹权限
  4. linux下文件读写
  5. minecraft1.16种子JAVA版_我的世界Java1.16.1版本水下要塞种子分享
  6. 免费超大量邮件发送服务,Kewail提供SMTP和API支持
  7. 今日金融词汇---股票后面的‘通’是什么意思
  8. bzoj3211花神游历各国
  9. 四、JavaScript 函数 - 章节课后练习题及答案
  10. java for循环map赋值_Java for循环Map集合优化实现解析