分布式session解决方案

一、基础概念

1.什么是session?

session是为了解决HTTP协议为无状态而产生的一个概念

服务器为每个用户创建一个会话,存储用户的相关信息,以便多次请求能够定位到同一个上下文。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。
当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。

Web开发中,web-server可以自动为同一个浏览器的访问用户自动创建session,提供数据存储功能。最常见的,会把用户的登录信息、用户信息存储在session中,以保持登录状态。

自己的理解:session是浏览器和服务器进行一次交互后产生的一种数据结构,他可以记录用户的基本信息,以达到下一次访问后,可以记住浏览的用户是谁和它的基本信息。

2.session的生命周期

1.session创建

Sessinon在用户第一次访问服务器时创建,需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。

在Java中,是Web应用程序在调用HttpServletRequest的getSession方法时,由Web容器(比如Tomcat)创建的。

即请求要到达后台服务器

2.Session什么时候失效?

  1. 服务器会把长时间没有活动的Session从服务器内存中清除,此时Session便失效。Tomcat中Session的默认失效时间为20分钟。

  2. 调用Session的invalidate方法。

3.Session与浏览器

虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。

这是因为Session需要使用Cookie作为识别标志。HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。

Session依据该Cookie来识别是否为同一用户。

该Cookie为服务器自动生成的,它的maxAge属性一般为-1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。

但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。

sessionId: 一个sessionId可以唯一标识一个用户,这样就可以简单地进行用户识别。
sessionId可以保存到客户端,但session只能保存到服务器中。

4 session和cookies

1.session和cookies的区别

主要是安全机制的区别

1.保存机制。
cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。

2.从安全角度。
因为cookie保存到是客服端故存在安全问题,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗。考虑到安全应当使用session。

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能 考虑到减轻服务器性能方面,应当使用COOKIE。(若对session做集中式存储,则不会出现此问题)

4、空间限制角度,单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中

2.session和cookies的联系

当服务端往session中保存一些数据时,Response中自动添加了一个Cookie:
JSESSIONID:xxxx,再后续的请求中,浏览器也是自动的带上了这个Cookie,服务端根据Cookie中的JSESSIONID取到了对应的session。

二、分布式session

session共享

将session存储到redis等分布式缓存数据库中,而不是应用服务器如tomcat内部中,这样就可以保证session的一致性。

1.什么是session一致性问题?

只要用户不重启浏览器,每次http短连接请求,理论上服务端都能定位到session,保持会话。

但在分布式应用中,情况将不一样。

单服务器web应用中,session信息只需存在该服务器中,这是我们前几年最常接触的方式,但是近几年随着分布式系统的流行,单系统已经不能满足日益增长的百万级用户的需求,集群方式部署服务器已在很多公司运用起来,当高并发量的请求到达服务端的时候通过负载均衡的方式分发到集群中的某个服务器,这样就有可能导致同一个用户的多次请求被分发到集群的不同服务器上,就会出现取不到session数据的情况,于是session的共享就成了一个问题。

2.Session一致性解决方案

一下列举了业界内常用的几种解决方案
在这里插入图片描述

1.session同步

思路:多个web-server之间相互同步session,这样每个web-server之间都包含全部的session

优点:web-server支持的功能,应用程序不需要修改代码

不足:

1.session的同步需要数据传输,占内网带宽,有时延。

2.所有web-server都包含所有session数据,数据量受内存限制,无法水平扩展。

3.主从架构固有的保证一致性会牺牲可用性的特定,但进行主从同步时,登陆的请求将被阻塞,显然不符合用户实际需求。

2.客户端存储法

思路:服务端存储所有用户的session,内存占用较大,可以将session存储到浏览器cookie中

优点:服务端不需要存储

缺点:

1.每次http请求都携带session,占外网带宽

2.数据存储在端上,并在网络传输,存在泄漏、篡改、窃取等安全隐患

3.session存储的数据大小受cookie限制

“端存储”的方案虽然不常用,但确实是一种思路。

3.反向代理hash一致性

思路:使用 Nginx (或其他复杂均衡软硬件)中的 IP 绑定策略,同一个 IP 只能在指定的同一个机器访问,但是这样做失去了负载均衡的意义,当挂掉一台服务器的时候,会影响一批用户的使用,风险很大;

反向代理层做逻辑处理

方案一:ip进行hash

反向代理层使用用户ip来做hash,以保证同一个ip的请求落在同一个web-server上.

方案二:含有业务属性的字段hash

反向代理使用http协议中的某些业务属性来做hash,例如sid,city_id,user_id等,能够更加灵活的实施hash策略,以保证同一个浏览器用户的请求落在同一个web-server(即不同的user_id对应不同的web-server).

总结:让专业的软件做专业的事情,反向代理就负责转发,尽量不要引入应用层业务属性,除非不得不这么做(例如,有时候多机房多活需要按照业务属性路由到不同机房的web-server)。

4.后端统一集中存储(主流方案)

思路:将session存储在web-server后端的存储层,数据库或者缓存

优点:

1.没有安全隐患

2.可以水平扩展,数据库/缓存水平切分即可,可以存储较多的session。

3.web-server重启或者扩容都不会有session丢失

不足:增加了一次网络调用,并且需要修改应用代码。

对于db存储还是cache,个人推荐后者:session读取的频率会很高,数据库压力会比较大。
如果有session高可用需求,cache可以做高可用,但大部分情况下session可以丢失,一般也不需要考虑高可用。

三、 spring-session

1.为什么要spring-session?

在传统单机web应用中,一般使用tomcat/jetty等web容器时,用户的session都是由容器管理。浏览器使用cookie中记录sessionId,容器根据sessionId判断用户是否存在会话session。这里的限制是,session存储在web容器中,被单台服务器容器管理。

session管理职责的转变

简单点说就是请求http请求经过Filter职责链,根据配置信息过滤器将创建session的权利由tomcat交给了Spring-session中的SessionRepository,通过Spring-session创建会话,并保存到对应的地方。

在这里插入图片描述

spring-session的核心思想在于:

将session从web容器中剥离,存储在独立的存储服务器中。
目前支持多种形式的session存储器:Redis、Database、MogonDB等。session的管理责任委托给spring-session承担,当request进入web容器,根据request获取session时,由spring-session负责从存储器中获取session,如果存在则返回,如果不存在则创建并持久化至存储器中。

2.spring-session工作原理

1.SR340规范与spring-session的透明继承

JSR340是Java Servlet 3.1的规范提案,其中定义了大量的api,包括:servlet、servletRequest/HttpServletRequest/HttpServletRequestWrapper、servletResponse/HttpServletResponse/HttpServletResponseWrapper、Filter、Session等,是标准的web容器需要遵循的规约,如tomcat/jetty/weblogic等等。

spring-session对JSR340是透明的如:

  • 接口适配:仍然使用HttpServletRequest获取session,获取到的session仍然是HttpSession类型——适配器模式

  • 类型包装增强:Session不能存储在web容器内,要外化存储——装饰模式

2.交互流程

再详细阅读源码之前先来看张图,介绍下spring-session中的核心模块以及之间的交互。

在这里插入图片描述

spring-session分为以下核心模块:

  • SessionRepositoryFilter:Servlet规范中Filter的实现,用来切换HttpSession至Spring
    Session,包装HttpServletRequest和HttpServletResponse
  • HttpServerletRequest/HttpServletResponse/HttpSessionWrapper包装器:包装原有的HttpServletRequest、HttpServletResponse和Spring Session,实现切换Session和透明继承HttpSession的关键之所在
  • Session:Spring Session模块
  • SessionRepository:管理Spring Session的模块
  • HttpSessionStrategy:映射HttpRequst和HttpResponse到Session的策略

SessionRepository

A repository interface for managing {@link Session} instances.

SessionRepository接口的源码如下:

S createSession();
void save(S session);
S getSession(String id);
void delete(String id);

即创建、保存、获取、删除Session的接口行为

五、应用实战

1.session与cookie踩坑日记

1.cookie的路径问题

cookie.setPath(“/”)之后,可以在webapp文件夹下的所有应用共享cookie,而cookie.setPath(“/webapp_b/”)只能在webapp_b应用下的获得。

@see cookie.setPath()的用法 https://www.cnblogs.com/tianguook/archive/2013/11/30/3451609.html

2.shiro修改session的默认名称的方法

配置文件如下:

    <bean id="shiroSessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<property name="sessionDAO" ref="sessionDAO"/>
		<!-- <property name="sessionValidationScheduler" ref="shiroSessionValidationScheduler"/> -->
		<property name="sessionValidationInterval" value="1800000"/>  <!-- 相隔多久检查一次session的有效性 -->
		<property name="globalSessionTimeout" value="1800000"/>  <!-- session 有效时间为半小时 (毫秒单位)-->
		<property name="sessionIdCookie.domain" value=".xxx.com"/>
		<property name="sessionIdCookie.name" value="jsid"/>
		<property name="sessionIdCookie.path" value="/"/>
		<!-- <property name="sessionListeners">
			<list>
				<bean class="com.concom.security.interfaces.listener.SessionListener"/>
			</list>
		</property> -->
	</bean>

@see 我的shiro之旅: 十 自定义shiro的SessionIdCookie https://blog.csdn.net/LHacker/article/details/19341735

3.同域名下的的session问题

场景:同域名下的多项目,浏览器会保存所有的cookie信息包括sessionid,如果cookie的name值相同,则会产生覆盖。

解决办法:不同的项目用不同的sessionid名称,这样项目之间就不会出现sessionid覆盖问题,同时服务端也可以不同的sessionid处理自己的回话。

@see 同域名下的多项目谨防sessionid互相影响,造成严重后果 https://blog.csdn.net/sl0007/article/details/17278629

参考资料

1.http://blog.csdn.net/agfagafsdfas/article/details/22531331
2.分布式系统session一致性的问题https://www.cnblogs.com/study-everyday/p/7853145.html
3.session的生命周期https://www.cnblogs.com/shizhijie/p/8422662.html
4.cookie 和session 的区别详解http://www.cnblogs.com/shiyangxt/archive/2008/10/07/1305506.html
5.spring-session(一)揭秘 https://www.cnblogs.com/lxyit/p/9672097.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值