对于分布式使用Nginx+Tomcat实现负载均衡,最经常使用的均衡算法有IP_Hash、轮训、根据权重、随机等。无论对于哪种负载均衡算法,因为Nginx对不一样的请求分发到某一个Tomcat,Tomcat在运行的时候分别是不一样的容器里,所以会出现session不一样步或者丢失的问题。javascript
实际上实现Session共享的方案不少,其中一种经常使用的就是使用Tomcat、Jetty等服务器提供的Session共享功能,将Session的内容统一存储在一个数据库(如MySQL)或缓存(如Redis)中。html
在之前写的一篇文章中:html5
使用Redis存储Nginx+Tomcat负载均衡集群的Session:http://blog.csdn.net/xlgen157387/article/details/52024139java
这一篇文章中已经学习了一下,如何使用 tomcat-redis-session-manager 开源项目解决分布式session跨域的问题,他的主要思想是利用Servlet容器提供的插件功能,自定义HttpSession的建立和管理策略,并经过配置的方式替换掉默认的策略。tomcat-redis-session-manager重写了Tomcat的org.apache.catalina.session.ManagerBase里边的具体写的操做, 将tomcat的session存储位置指向了Redis:git
RedisSessionManager继承了org.apache.catalina.session.ManagerBase并重写了add、findSession、createEmptySession、remove等方法,并将对session的增删改查操做指向了对Redis数据存储的操做。github
有兴趣可参考一篇Tomcat中session的管理机制:http://www.cnblogs.com/interdrp/p/4935614.htmlweb
不过使用过tomcat-redis-session-manager 的都应该知道,配置相对仍是有一点繁琐的,须要人为的去修改Tomcat的配置,须要耦合Tomcat等Servlet容器的代码,而且对于分布式Redis集群的管理并非很好,与之相对的我的认为比较好的一个框架Spring Session能够真正对用户透明的去管理分布式Session。redis
Spring Session不依赖于Servlet容器,而是Web应用代码层面的实现,直接在已有项目基础上加入spring Session框架来实现Session统一存储在Redis中。若是你的Web应用是基于Spring框架开发的,只须要对现有项目进行少许配置,便可将一个单机版的Web应用改成一个分布式应用,因为不基于Servlet容器,因此能够随意将项目移植到其余容器。算法
官方地址:http://projects.spring.io/spring-session/spring
官方文档地址:http://docs.spring.io/spring-session/docs/1.3.0.RELEASE/reference/html5/
Spring Session提供了一套建立和管理Servlet HttpSession的方案。Spring Session提供了集群Session(Clustered Sessions)功能,默认采用外置的Redis来存储Session数据,以此来解决Session共享的问题。
1、特性
Spring Session提供如下特性:
2、基于XML配置方式的Spring Session案例实现
基于SSM框架的一个小案例,Git OS项目代码地址:http://git.oschina.net/xuliugen/spring-session-demo
项目展现:
(1)基本环境需求
进行使用Spring Session的话,首先的是已经安装好的有一个 Redis服务器!
(2)添加项目依赖(最基本的依赖使用)
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> <version>1.3.0.RELEASE</version> <type>pom</type> </dependency> <dependency> <groupId>biz.paluch.redis</groupId> <artifactId>lettuce</artifactId> <version>3.5.0.Final</version> </dependency>
(3)添加Spring配置文件
添加了必要的依赖以后,咱们须要建立相应的Spring配置。Spring配置是要建立一个Servlet过滤器,它用Spring Session支持的HttpSession实现来替换容器自己HttpSession实现。这一步也是Spring Session的核心。
<context:annotation-config/> <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/> <bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
上述代码注释:
LettuceConnectionFactory实例是配置Redis的ConnectionFactory。
注意:
<bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
查看源代码能够看到,默认的Redis连接配置为:
所以,若是有本身的Redis配置,请修改,例以下边的配置:
<bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"> <property name="hostName" value="192.168.1.149"/> <property name="port" value="6379"/> <property name="password" value="123456"/> </bean>
(5)关于Error creating bean with name ‘enableRedisKeyspaceNotificationsInitializer’错误的处理:
添加以下配置让Spring Session再也不执行config命令
<util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>
若是不添加的话,会报以下错误:
Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'enableRedisKeyspaceNotificationsInitializer' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Unable to configure Redis to keyspace notifications. See http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent Caused by: redis.clients.jedis.exceptions.JedisDataException: ERR unknown command config
(5)在web.xml中添加DelegatingFilterProxy
<filter> <filter-name>springSessionRepositoryFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSessionRepositoryFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping>
DelegatingFilterProxy将经过springSessionRepositoryFilter的名称查找Bean并将其转换为过滤器。对于调用DelegatingFilterProxy的每一个请求,也将调用springSessionRepositoryFilter。
(6)Spring MVC controller代码用于测试:
@Controller
@RequestMapping(value = "/spring/session", produces = {ConstString.APP_JSON_UTF_8}) public class SpringSessionDemoController { @RequestMapping(value = "/setSession.do", method = RequestMethod.GET) public void setSession(HttpServletRequest request, HttpServletResponse response) { String name = request.getParameter("name"); String value = request.getParameter("value"); request.getSession().setAttribute(name, value); } @RequestMapping(value = "/getSession.do", method = RequestMethod.GET) public void getInterestPro(HttpServletRequest request, HttpServletResponse response) { String name = request.getParameter("name"); System.out.println("------" + request.getSession().getAttribute(name)); } @RequestMapping(value = "/removeSession.do", method = RequestMethod.GET) public void removeSession(HttpServletRequest request, HttpServletResponse response) { String name = request.getParameter("name"); request.getSession().removeAttribute(name); } }
(7)测试
访问连接:http://localhost:8080/spring/session/setSession.do?name=xuiliugen&value=123456
使用工具查看Redis内容:
能够发现已经有值了!而且有expirations,能够看到箭头指向的位置,是失效的时间记录值!
(8)到此,Spring Session的使用已经完成!其余具体的细节请参考:http://git.oschina.net/xuliugen/spring-session-demo 项目源代码。
对于分布式环境Session跨域共享的问题,不论是使用开源的框架仍是使用本身开发的框架,都须要明白的一个问题是:在Tomcat容器中建立Session是一个很耗费内存的事情。所以,咱们在本身写相似框架的时候,咱们必定要注意的是,并非Tomcat为咱们建立好了Session以后,咱们首先获取Session而后再上传到Redis等进行存储,而是直接有咱们本身建立Session,这一点是相当重要的!
下一篇:
Spring Session解决分布式Session问题的实现原理:http://blog.csdn.net/xlgen157387/article/details/60321984
参考文章: