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

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

分布式 session 的4个解决方案,你觉得哪个最好?_第1张图片
原理:

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

这样做的话,我们无论去哪个服务器,都相当于能拿到全量的session数据,这样就不用担心负载均衡到哪个服务器了。面试宝典:https://www.yoodb.com 即将上线,免费刷题,无套路!

优点:

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

缺点:

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

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

总结:

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

方案2:客户端存储

分布式 session 的4个解决方案,你觉得哪个最好?_第2张图片
原理:

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

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

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

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

总结:

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

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

分布式 session 的4个解决方案,你觉得哪个最好?_第3张图片
原理:

利用了我们负载均衡机制,我们可以利用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:统一存储(推荐)

分布式 session 的4个解决方案,你觉得哪个最好?_第4张图片
原理:

我们之前出现的所有问题是,因为浏览器访问我们服务的时候,由于负载均衡机制会跳到不同的服务器,而又由于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域名下的,我们都能用

分布式 session 的4个解决方案,你觉得哪个最好?_第5张图片

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

流程:

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

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

作者:半格咖啡

https://blog.csdn.net/hxxzbgkf/article/details/122727176

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

最近有很多人问,有没有读者交流群!加入方式很简单,公众号Java精选,回复“加群”,即可入群!

Java精选面试题(微信小程序):3000+道面试题,包含Java基础、并发、JVM、线程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架构设计等,在线随时刷题!

------ 特别推荐 ------

特别推荐:专注分享最前沿的技术与资讯,为弯道超车做好准备及各种开源项目与高效率软件的公众号,「大咖笔记」,专注挖掘好东西,非常值得大家关注。点击下方公众号卡片关注

文章有帮助的话,点在看,转发吧!

你可能感兴趣的:(java,redis,数据库,session,分布式)