2019独角兽企业重金招聘Python工程师标准>>>
session共享的前生今世
Session及cookie基本概念及生命周期
- session
当浏览器发起一个新的HTTP请求时,WEB服务端会主动创建一个session.并分配一个sessionID作为服务端识别客户端的一个标识,session对象会保存在服务端.此时session对象处于NEW STATE状态,如果调用
session.isNew()
则返回true.当服务器处理完相应的请求时候,会将sessionID同reponse响应消息 一起传回客户端浏览器,并将其存到该客户端浏览器的cookie中。当客户端再发送其它http请求的时候.会将sessionID连同request消息一起发送给服务端。服务端再根据传过来的sessionID将这次request与保存在服务端的session对象联系起来.此时的session对象已不是NEWSTATE状态.这样循环多次.直到session对象超时或销毁.
注:当客户端浏览器禁用cookie时,sessionID将不能保存在cookie中,一般此种情况,会使用url重写,将sessionID作为请求参数来进行客户端和浏览器的信息传输交互
- cookie cookie是在客户端保存一些少量数据的解决方案.而session是在服务端保存少量数据的方案. 如果cookie不设定时间的话就表视它的生命周期为浏览器会话的期间,只要关闭浏览器,cookie就消失了,这种cookie被称为会话cookie.其一般不保存在硬盘上.而是保存在内存中。如果设置了过期时间.那么浏览器会把cookie保存到硬盘中,再次打浏览器时会依然有效.直到它的有效期超时;
注:会话cookie可以在一个浏览器间的不同的tab页中共享。随浏览器主进程的关闭而失效 存储在硬盘中的cookie可以在不同浏览器进程间共享。
分布式系统session共享问题的由来
目前大多数大型web应用都采用了分布式服务集群的部署方式,所谓集群,就是让一组计算机服务器协同工作,解决大并发,高可用,水平扩展的问题。但是在服务集群中,session共享往往是一个比较头疼的问题。因为session是在服务器端保存的,如果用户跳转到其他物理服务器的话,session就会丢失,一般情况下,session对象在后端是不可跨物理服务器而存在。于是就有了分布式系统的session共享问题。 目前公司有很多的应用都是集群布置环境,但是,有很多项目运维在配置f5作负载均衡时,作了访问地址ip hash算法来分担流量,该算法根据访问客户端的IP地址进行归类并和集群中的真实的服务器数取模,得到一个固定值,来分配真实的服务器,这样的确可以分担部分的流量,但并没有起到failover的功能,即这台服务器挂机后,该客户端的请求信息仍然会发送到该服务器上,并且,如果服务器集群中,真实的服务器有硬件性能上的差异,在这种分配策略上也做不到所谓的“能者多劳”。所以,要做到真正的HA,这种算法是不合适的。
所以,为了提高程序的HA及提供failover,在应用端如果是集群布置,并且在应用的开发过程中,如果在session中保存了相关的内容,则最好要提供分布式的session解决方案。
常用的集群Session共享的方式
- 客户端Cookie保存方案,将原来保存在session中的内容以加密的方式保存在客户端cookie中。
- 优点:减轻服务器端的压力,每次session信息被写回客服端,然后经浏览器再次提交到服务器。即使两次请求即使在集群中的不同服务器上完成,由于session信息都是随请求信息一起提交,也可以到达session共享。
- 缺点:
- 传递cookie时,http信息头的长度限制使我们只能够在cookie中存入少量的用户信息;
- 需要额外地做session信息加密的工作;
- 如果采用这种方式,每次访问网站二级域名时都会在http信息头中带有这些以cookie形式存储的值信息,会占用一定的带宽;
- 信息存储是在客户端进行,用户完全可以禁用cookie或删除cookie,不是很可靠
- 服务器间Session同步方案,将session对象在集群中的所有物理机上作同步 服务器间session同步策略,不同的容器有不同的解决方案。一般常用以下2种
- 使用主-从服务器的架构,当用户在主服务器上登录后,通过脚本或者守护进程的方式,将session信息传递到各个从服务器中,这样,用户访问其它的从服务器时,就可以读到session信息。 缺点:比如速度慢、不稳定等,另外,如果session信息传递是主->从单向的,会有一些风险,比如主服务器down了,其它服务器无法获得session信息
- Session 对象的集群中的广播机制。 一台主机中产生session中,将此session对象在集群网络中进行广播同步,各集群中的主机收到广播后,再同步到本地的session内存域中。 缺点:如果session内容中有大型对象时,不适合传输。集群范围中网络中对存在大量的广播消息,占用带宽,会有延时.
- 使用集中统一管理Session方案 即将集群中各主机产生的session对象都存储到一个中心存储结构中,目前比较流行的存储结构是:redis集群,Memcache,mysql数据库等。这种集中存储的结构,能斛决上面方案中的一些弊断。但也有一些应用上问题。比如选择mysql作存储结构中,mysql数据库可以用作存储的session对象,但在并发量高时,对数据库的读写要求较高,还需要另外提高session失效的相关算法。Redis集群,memcache主要是以内存为存储介质,有先天的读写优势,并且都能提供失效机制,特别适合用来作session的存储结构。所以,这一种比较好的解决方案。 目前这两种方案都有容器插件的方式部署在容器中有解决方案,但有其相应的缺点:
- 插件的版本更新不及时。
- 对容器不透明,不同容器要适配不同的插件。
- 插件本身的稳定性无法控制。
- 运维在配置集群时,还要特别注意相关插件的配置。增加了维护的难度。
相应的优点就是:对程序透明,开发程序时候,不用考虑集群,还是单机环境。布置简单,没有额外的工作量。
Spring Session的使用方式
第一步:引入依赖,根据需要配置相应的存储
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId><version>1.3.1.RELEASE</version><type>pom</type><exclusions><exclusion><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId></exclusion><exclusion><groupId>redis.clients</groupId><artifactId>jedis</artifactId></exclusion></exclusions></dependency>
第二步:web应该配置filter过滤器。
<filter><filter-name>springSession</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping><filter-name>springSession</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
第三步:配置相应的SPRING BEAN
<bean id="springSession" class="org.springframework.session.web.http.SessionRepositoryFilter"c:sessionRepository-ref="redisOperationsSessionRepository" p:httpSessionStrategy-ref="cookieHttpSessionStrategy" />
<bean id="defaultCookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer"p:cookiePath="/" />
<bean id="cookieHttpSessionStrategy" class="org.springframework.session.web.http.CookieHttpSessionStrategy"p:cookieSerializer-ref="defaultCookieSerializer" />
<bean name="redisOperationsSessionRepository" class="org.springframework.session.data.redis.RedisOperationsSessionRepository"c:redisConnectionFactory-ref="connectionFactory" p:defaultMaxInactiveInterval="${session.timeout}" />
- 使用spring session的优点
- 统一项目中对session共享问题的处理方案。
- 降低运维复杂度,使解决方案和容器解耦。
- 构建统一的session存储redis环境,不需要每个项目都自行构建一套session的存储介质。公司正式环境也可以构建统一的,HA,FAILOVER的session存储环境。逐步降低一个应用占用物理服务器超配的现象。
- 缺点
- Spring session解决方案是spring社区新的子项目,面世时间不长,目前1.3版本。有集成稳定性,及集成兼容性的风险。特别是公司里一些老的系统,由于jdk,spring的版本都较低,是不是适合上,要综合评估。
- 集成对应用有一定的调整工作量。
- 存储样式 127.0.0.1:6379> keys *
- 1) “spring:session:expirations:1235654675878”
- 2) “spring:session:sessions:fdf-d1e4-44b3-a83a-FDSA”