不论你工作多久,早期的应用架构设计(一个war包打天下),大家应该都不陌生。
在这个架构下,在用户访问的内容中,有些信息/数据是用户使用其他功能时都需要频繁使用的(用户的基本信息、登陆信息、权限信息、区域信息等),为了提升系统吞吐量,提升用户感知度,我们会怎么做?
将这部分信息放到session中。
//存储信息 session.set(userid,userinfo);//{name,age,role,privilege} //获取信息 session.get(userid,userinfo)
好处不言而喻:
- 减少与数据库的交互
- 节省资源
- 提升用户感知度
- 提升系统的吞吐量
这时候问题来了,如果用户量激增了怎么办?Session信息是保存哪里?Tomcat----->JVM
这时候一个war包打天下的最大的问题就凸显出来,无法满足高并发环境。我们学习的时候常关心的分布式架构应用而生,通过多台服务器来共同负载用户请求压力。
请大家思考一个问题,我们原来的设计,为了提升用户感知度及系统吞吐量,将访问频次较高的用户基本信息放进了session中。如果此时变成了分布式架构,会有什么影响?如果登陆是Tomcat1响应,其他操作(查看私信、朋友圈)是Tomcat2响应,会出现什么问题?
用户登陆时访问数据库获取到用户的基本信息(包括鉴权信息)存储在我们的session 中,此时是保存在tomcat1的jvm中,当分流软件分流到另外一台tomcat2主机时,无法获取到我们登陆时获取到的session信息。
这个问题就是我们常说的:session一致性(共享)。需求也应用而生。
需求:不管哪台服务器响应我们的需求,都能拿到我们存储在session中的用户基本信息,而不用从DB中获取(连接资源很宝贵,重要的事情说三遍!!!)。
那有什么解决方案呢?
session复制(同步)
解决方案:
多个web-server之间相互同步session,这样每个web-server之间都包含全部的session
优点:
web-server支持的功能,应用程序不需要修改代码
实现简单、配置较少、当网络中有机器Down掉时不影响用户访问
缺点:
session的同步需要数据传输,占内网带宽,有网络延迟
广播式复制到其余机器有一定廷时,带来一定网络开销
所有web-server都包含所有session数据,数据量受内存限制,水平扩展收到限制,web-server越多,受限越大。
在客户端存储session信息
解决方案:
服务端存储所有用户的session,内存占用较大,可以将session存储到浏览器cookie中,每个端只要存储一个用户的数据了。
优点:
服务端不需要存储。
缺点:
每次http请求都携带session,占带宽,数据存储在端上,并在网络传输,存在泄漏、篡改、窃取等安全隐患,session存储的数据大小受cookie限制。
反向代理hash一致性
Session Sticky 方式管理,即粘性Session、当用户访问集群中某台机器后,强制指定后续所有请求均落到此机器上
解决方案:
反向代理层使用用户ip,或者http协议中的某些业务属性来做hash,以保证同一个ip的请求落在同一个web-server上。
优点:
只需要改nginx配置,不需要修改应用代码
实现简单、配置方便、没有额外网络开销
可以支持web-server水平扩展
缺点:
如果web-server重启,一部分session会丢失,产生业务影响,例如部分用户重新登录
如果web-server水平扩展,rehash后session重新分布,也会有一部分用户路由不到正确的session
后端统一集中存储
解决方案:
将session存储在web-server后端的存储层,数据库或者缓存
优点:
没有安全隐患
可靠性好
可以水平扩展,数据库/缓存水平切分即可
web-server重启或者扩容都不会有session丢失
缺点:
增加了一次网络调用
需要修改应用代码
增加了维护工作量
实现复杂、稳定性依赖于缓存的稳定性、Session信息放入缓存时要有合理的策略写入
最后
以上为现在通用的Session一致性(共享)解决方案,建议大家结合Nginx、Docker理解会更香。