⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/hxxzbgkf/article/details/122727176 「半格咖啡」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

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

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

原理:

就是让这两个服务器之间互相同步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,我们想使用的话,就简单配置一下也还可以

方案2:客户端存储

原理:

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

缺点:(都是缺点)
  • 每次http请求,携带用户在cookie中的完整信息,浪费网络带宽
  • session数据放在浏览器的cookie中,有些浏览器遵循的标准不一样,它的长度限制不一样,比如长度限制4k,因此不能保存大量信息
  • session数据放在cookie中,存在泄露、篡改、窃取等安全隐患
总结:

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

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

原理:

利用了我们负载均衡机制,我们可以利用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是每个服务器各自存储在各自内存空间的,所以这导致我们跳到下一个服务器以后,我们上一个服务器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域名下的,我们都能用

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

流程:

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

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

文章目录
  1. 1. 方案1:session复制(session同步)
    1. 1.0.0.0.1. 原理:
    2. 1.0.0.0.2. 优点:
    3. 1.0.0.0.3. 缺点:
    4. 1.0.0.0.4. 总结:
  • 2. 方案2:客户端存储
    1. 2.0.0.0.1. 原理:
    2. 2.0.0.0.2. 缺点:(都是缺点)
      1. 2.0.0.0.2.1. 总结:
  • 3. 方案3:HASH一致性(推荐)
    1. 3.0.0.0.1. 原理:
    2. 3.0.0.0.2. 优点:
    3. 3.0.0.0.3. 缺点:
    4. 3.0.0.0.4. 总结:
  • 4. 方案4:统一存储(推荐)
    1. 4.0.0.0.1. 原理:
    2. 4.0.0.0.2. 优点:
    3. 4.0.0.0.3. 缺点:
    4. 4.0.0.0.4. 总结:
  • 4.0.0.1. session共享问题之不同服务-子域session共享
    1. 4.0.0.1.1. 流程: