组长,欣赏看了一下我:
对,你这个方案确实可行。
不过么,如果用这种方案,首先你要想好加密方案。
用户信息可是我们的敏感数据,不能让别人轻易的窃取或者篡改数据了。
除了这个,这个方案每次请求都要携带 Cookie 传输,这会占用外网的带宽,如果 Cookie 过大,会增大网络的开销。
另外,我们存储的数据大小,容易受到 Cookie 限制。
所以这种还是不怎么常用,不过也是一种思路。
我比较推荐下面两种方案。
Session 粘滞(Sticky Sessions)
组长:
刚才应该看到了,我只是对 Nginx 的配置做了一些修改,然后这个问题就解决了吧。
其实这是因为我修改 Nginx 默认的负载均衡策略,使用 IP Hash 的方式。
Nginx 会使用请求者的 IP 来做 Hash,然后分发到一台机器上,这样可以保证同一 IP 的请求都落在同一台 Tomcat 上。
架构图如下:
Session 粘滞-IP Hash
上面这种方式我们使用 Nginx 四层负载均衡方式,其实 Nginx 还可以做到七层负载均衡方式,也就是使用 Http 协议中的一些业务属性来做 Hash,常见的有 userId,loginId等等。
架构图如下:
一致性 Session-Session 粘滞-七层
阿粉:
这种方案看起来挺简单的,我们只需要修改 Nginx 配置就好了,应用端配置无需改动。
只要请求来源 IP 足够的随机,那么 IP HASH 之后两台应用上的流量将会足够随机。
另外后面如果两台机器扛不住,我们还可以水平扩展,再加机器,只要修改 Nginx 配置即可。
组长:
你说的这几点都很正确!
不过你有没有想过,像我们公司这种情况,所有人的出口的 IP 都是一个。那么我们公司的所有请求只会到一台机器上,那我们这种情况等于又变成单点了。
另外如果 Tomcat 重启,Session 由于是放置在内存内存中,这一部分的 Session 将会丢失,这就导致这部分用户将会重新登录。
最后,如果我们临时再加机器,修改完 Nginx 配置,重新启动之后,Nginx 将会重新计算 Hash 分发请求。
这种情况就会导致有一部分用户重新路由到一台新机器上,由于没有 Session,又需要重新登录了。
不过么,Tomcat 重启或者新加机器次数不会很多,所以这个问题也不大,用户体验稍差点。
今天的我们这个问题解决方案就先使用这个。
不过后面我们还是改成下面这种方式。
后端集中存储
组长:
上面几种的方式我们都是把 Session 存储在应用内存上,应用机器只要重启,Session 就会丢失。
为了这个解决这个问题,我们将 Session 单独存起来,保存到 Redis 或者 MySQL 中。
不过由于 Session 需要过期失效的特性,不需要持久化保存,所以这里我建议使用 Redis 来保存。
这样架构就变成下方这样的:
一致性 Session-Session 后端存储
我们使用这种方案,上没有 Session 丢失的风险,当然前提是 Redis 不能宕机。
另外后期如果应用可以直接水平扩展。
如果后面应用的请求量很大,一台 Redis 扛不住了,那我们可以其实可以做集群扩展,根据缓存 Key 做路由。
阿粉:
对对,这种方式好~
组长:
你不要高兴的太早,我们使用这个方案需要付出一定的代价的。
首先我们每次请求都需要调用一次 Redis ,这就增加一次网络的开销。
另外,引入 Redis,我们需要对相应的代码做出修改,这样复杂度就变高。
所以说,这个方案有利也有弊,当然对于我们的场景来说,利大于弊。
阿粉:
恩,好像是这样的。
组长:
好了,这么晚了,问题解决了,我们去撸个串,我请客!
阿粉:
老大,🐂!
组长拍了拍阿粉的脑袋:
我这一顿不是白吃哦,下个星期你把现在方式修改一下,修改成 Session 集中存储的方式。
给你一个小提示,可以使用 spring-session。
阿粉:
好吧,吃人嘴短,下周我研究下。
总结
最后阿粉总结一下,当我们后端 Web 应用扩展到多台后,我们就会碰到分布式一致性 Session 的问题,主流解决方案有四种:
- Session 复制:利用 Tomcat 等 Web 容器同步复制
- Session 前端存储:利用用户浏览器中 Cookie 保存 Session 信息
- Session 粘滞方案:利用 Nginx 可以做四层 Hash 或七层 Hash 的特性,保证用户的请求都落在同一台机器上
- Session 后端集中存储方案:利用 Redis 集中存储 Session,Web 应用重启或扩容,Session 也无需丢失。
上面四种方案,优先推荐第四种。
当然第四种方案需要一定的开发工作量,前期还没改造的过程可以选择 第三种方案中间过渡。
好了,后面阿粉就要使用 Session 后端存储方案改造这个工程了,后面阿粉再跟大家分享一下 spring-session。