分布式 session 的4个解决方案,你觉得哪个最好?

点击上方“Java基基”,选择“设为星标”

做积极的人,而不是积极废人!

每天 14:00 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:blog.csdn.net/hxxzbgkf/

article/details/122727176


分布式环境session解决的4个方案

方案1:session复制(session同步)

2594a60b17e94c085dc2d3201cb71602.png
原理:

就是让这两个服务器之间互相同步session,比如左边服务器之前保存了一个1,右边服务器之前保存了一个2,他们两个一同步,那么左边服务器保存了1,2,右边服务器也保存了1,2。

这样做的话,我们无论去哪个服务器,都相当于能拿到全量的session数据,这样就不用担心负载均衡到哪个服务器了

优点:

tomcat原生支持,只需要修改一下配置文件,好多tomcat之间就能复制session

缺点:

session同步需要通过网络进行数据传输,就有延迟问题,同时会占用大量带宽,这样会压缩我们整个业务的带宽,会降低我们的处理能力

假如我们这里有100台tomcat,每一个tomcat里面session都只存了1G的数据,我们想要用同步方案来做的话,那相当于其他tomcat都要保存剩下99个人的所有全量数据,那相当于每个tomcat都至少需要100G的内存才能将session整个全量保存下来。因此,这个解决方案受到内存限制,我们服务器无法水平扩展,不能复制上好多个tomcat来进行使用

总结:

如果是大型分布式集群环境,由于所有的web-server都全量保存数据,所以这种方案我们不使用。而如果是小型系统里面,就3/5个tomcat,我们想使用的话,就简单配置一下也还可以

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

方案2:客户端存储

6daacaf7638d5c6bda16c875b15790af.png
原理:

我们让客户端自己来存储session,我们服务器想用哪些数据,读取浏览器带过来的cookie即可。这样可以节省服务器资源

缺点:(都是缺点)
  • 每次http请求,携带用户在cookie中的完整信息,浪费网络带宽

  • session数据放在浏览器的cookie中,有些浏览器遵循的标准不一样,它的长度限制不一样,比如长度限制4k,因此不能保存大量信息

  • session数据放在cookie中,存在泄露、篡改、窃取等安全隐患

总结:

上面的缺点都很致命,因此我们实际绝对不会使用这种方案

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

方案3:HASH一致性(推荐)

81feecfc30ca338271dd717b505917c4.png
原理:

利用了我们负载均衡机制,我们可以利用ip的哈希一致性,只要来自于同一个ip的,那我们就永远给它定位到同一个服务器,我们也不给它跑到第二个服务器了,这样比如标绿色的浏览器去的标绿色的服务器里面存的东西,无论多少次请求过来,都会落到标绿色服务器的身上,我们就能取得到

我们hash一致性还可以结合业务字段,如下面的图,凡是456号用户他的请求都落在绿色服务器,凡是123号这个用户他的请求都落在橙色服务器

优点:
  • 只需要改负载均衡nginx的配置,让它做一个ip hash,而不需要修改应用代码

  • 负载是均衡的:只要hash属性的值分布是均匀的,多台web-server的负载就是均衡的

  • 支持web-server水平扩展(而session复制方案是不行的,受内存限制)

缺点:
  • session还是存在web-server中,因此web-server突然闪断或者重启了,可能会导致部分session丢失,这部分用户只要下次再过来,所有的数据都没了,他需要重新登录一遍,所有东西都得重新做一遍

  • 如果我们服务器要水平扩展,如果我们固定了也好,但是如果原来是2台服务器,现在加到了4台服务器,现在想要做哈希的话,相当于重新得计算一下,假设我们以前计算哈希最简单的方式,按照ip地址得到一个整数型的哈希,如果只有2台服务器,那么就可以对2求余操作,求到余数,如果余数是1,就落到第一台服务器,如果没有余数,就落到第二台服务器。但如果变成了4台服务器,我们相当于就要对4进行求余操作,如果余1,落到第一台服务器,余2落到第二台服务器,余3落到第三台服务器,没有余数我们落到第四台服务器。(即水平扩展后,rehash后session重新分布,会有一部分用户路由不到正确的服务器)

总结:

以上缺点问题不大,而且后来呢,我们ip 哈希的这种也用的比较多,因为基于session本来就是具有有效期的,就算这次因为水平扩展原因或者服务器闪断原因没有了,那就相当于浏览器关掉了呗,那我们让用户重新再做一次登录即可

方案4:统一存储(推荐)

37286d24e19b1d6f5ec59747242f7ce3.png
原理:

我们之前出现的所有问题是,因为浏览器访问我们服务的时候,由于负载均衡机制会跳到不同的服务器,而又由于session是每个服务器各自存储在各自内存空间的,所以这导致我们跳到下一个服务器以后,我们上一个服务器session里面的数据它就用不到了,那怎么办呢?

那我们就可以让session统一存储,无论是你哪个服务器,哪个tomcat,你的session都不要存储到你的内存里面了,全部呢,大家都可以存到数据库,或者redis之类的速度更快的nosql中间件等等,所以,我们可以使用这种方案

优点:
  • 没有安全隐患,没有让浏览器自己存储到cookie里,所有的数据都是我们后台统一存储,浏览器肯定是没办法访问到的,只要我们保障了我们后台的redis的安全,就没有人能去篡改里面相关的数据

  • 水平扩展也很容易,无论我们web服务器有多少个,10个,100个,1000个,反正大家都去redis中做存取,即使redis不够用了,我们做redis集群,每个里面存一点,每个里面存一点

  • 我们服务器即使重启、宕机,下次再启动了,我们session也不会丢失,因为session都是redis里面存着,跟我们业务服务器宕机与否没有任何关系

缺点:
  • 从内存中取数据是非常快的,也不需要网络交互,而如果我们存储到了redis里面,我们想要从session里面取数据,我们还得连接redis,再来一次网络交互

  • 我们需要修改应用代码:如将所有的getSession方法替换为从Redis查数据的方式

总结:

好的一点是,spring早就意识到了这个问题,专门编写了一个框架叫SpringSession,它就可以完美的解决我们session统一存储问题

session共享问题之不同服务-子域session共享

什么叫子域:比如之前发给auth.mall.com,我们可以给它放大作用域,比如我们只要是mall.com域名下的,我们都能用

1d473cfa224a34ef13e7d6afb44a02c5.png

因此如果在登录成功往浏览器回写cookie的时候,把这个作用域域名能改成父域名就好了,但这个操作又是我们tomcat默认自己发的,你第一次使用session,他就自己发的,所以如果我们自己来写这段逻辑还是非常麻烦的,我们整合springSession来解决这个问题

流程:

首先浏览器会在认证服务里面登录成功,认证服务会将登录成功的用户存储到session里面,但是它存session的时候,我们不让他存储到自己的内存里面,我们让它存储到redis里面。

接下来呢,给我们浏览器回写cookie里面是jsessionid,回写的时候,又让我们这个session对应的jsessionid这个cookie默认的作用域不能只是我们认证服务,让它放大作用域,一放大到mall.com以后,浏览器下次访问任何服务,那我们都会带上这个cookie叫jsessionid的,因为我们访问其他服务都是其他子域名的,因为所有服务,session都统一用redis存取,所以我们访问到了其他服务,其他服务就算要按照jsessionid取出session里面的数据,他也去session里面查



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

bf63e7da37afa981a89237770dccfbc1.png

已在知识星球更新源码解析如下:

d0eaceed200cb451272d0936f3631f5a.jpeg

25650737a338a6b833380c73851f0f02.jpeg

8e18aae519dbb0bf718bfc5d04a39702.jpeg

6c0f8a722082a0e70927ebee657d6d4f.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值