Tomcat集群session共享方式

第一种方式:nginx配置 ip_hash轮询机制实现,这个实现方式简单,但是有很大的局限性,同一个ip,会被分配始终访问同一个tomcat,因为ip不变,nginx计算出来的hash也就不变,除非这个tomcat挂了,才会分配到另外一个tomcat访问,万一出现这种情况,session就会丢失,分配到的新tomcat并没有它在前一个tomcat里的session,所有,这并不是session共享,只是尽量保证某一连接始终分发到固定的服务器而已。
假如在一个公司内的所有员工,访问的外网服务器,通过这种方式配置集群,将无法实现负载均衡,因为对外网nginx而言,这些人全部来自一个外网ip,所以,全部会被分配到一个tomcat上,而集群中其它tomcat将一直闲置。
另外,也有可能出现某些高频访问,始终压在一台服务器上的情况。
这样都是大大的弱化了nginx的负载均衡能力。

第二种方式,nginx不配置,tomcat服务配置session复制功能。
在Server.xml中,1)取消Cluster节点的注释. (2)保持每个Engine 节点jvmRoute的值是相同的.
tomcat的session复制是基于IP组播(multicast)来完成的。将集群的tomcat通过配置统一的组播IP和端口来确定一个集群组, 当一个node的session发生变更的时候, 它会向IP组播发送变更的数据, IP组播会将数据分发给所有组里的其他成员(node).
(网络通讯方式,1,tcp/ip,一对一通讯。2,udp广播方式通讯,发送全部网内机器某一端口,需要的机器监听端口接受数据处理数据,不需要的机器直接不理睬就行。3,组播方式,配置统一的组播IP和端口来确定一个集群组,集群内开黑通讯)







port="45564"
frequency="500"
dropTime="3000"/> 

autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
















同时, 在web.xml里增加描述,就是告诉tomcat,这个项目是可分布式的。。。

这种配置方式,相对简单,无需更改项目代码,也实现了真正的session共享,整个集群,只要有一个tomcat存活,那么其它tomcat都死掉了都重启了,session都不会丢失。
缺点也很明显,session在网络内复制的过程中,会有一定的延迟,当然,延迟长短,取决于网络环境、session个数(用户多不多)、session信息大小、集群的服务器个数。

所以,它适用于小集群、少用户的web服务。。。

以上配置会报错
ava.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: xxxxxxxx
原因是:tomcat停止时,保存session资源,然后在重启服务后,会尝试恢复session。
解决办法一:配置tomcat在关闭的时候就不去保存session资源。
配置于Context标签内

PersistentManager对Session进行持久化到文件系统或数据库中


    

解决办法二:
将那些需要放在session的类进行序列化。
也就是让类实现接口java.io.Serializable即可。

第三种方式,nginx不配置,使用nosql或者sql数据库,实现session共享,特别是spring + redis方式。

1、添加依赖
特别注意,引入不同的版本时,可能会引起原有jar包版本不兼容


  org.springframework.session
  spring-session-data-redis
  1.2.1.RELEASE


  redis.clients
  jedis
  2.8.1

2、配置
spring-mvc.xml:
RedisHttpSessionConfiguration


    

由于使用了这里的配置,由redis负责接管Session,原来web.xml里配置的Session超时时间就会失效了

还有一个redis连接池的配置。。。。
redis.clients.jedis.JedisPoolConfig
org.springframework.data.redis.connection.jedis.JedisConnectionFactory

3、web.xml添加拦截器
特别注意,这个filter要写在比较靠前的第一个的位置


    springSessionRepositoryFilter
    org.springframework.web.filter.DelegatingFilterProxy


    springSessionRepositoryFilter
    /*

这种配置方式,也较简单,需要更改一定的项目配置,实现了真正的session共享,可靠性很高。
缺点是项目配置有一定修改,每次访问多一个网络开销(去redis取session,开销也很小了)

所以,它适用于大集群、多用户的web服务。。。

Spring4.3,这里需要注意,所有Spring的xml的配置文件里标签要变为 -4.3.xsd

静态文件资源访问配置:要注意这里的静态文件不要放到WEB-INF里,要放到项目内,例如项目下的resources
这样就可以放行静态文件的访问

还有一个比较大的坑,使用Spring Session实际是Spring加入了一个Filter,其本质是:对每一个请求的request都会被DelegatingFilterProxy进行了一次封装。那么,在Controller里面拿出的request实际上是封装后的request,因为Session要存在Session,所以调用request.getSession()的时候,实际上拿到是Spring封装后的session ,因此对于request实际上拿到是Spring封装后的request。那么可能会导致Request.getInputStream无法获取到流数据,对于使用raw格式,即非Key,Value参数的提交 会被Spring-Session获取,当contentType为application/x-www-form-urlencoded时,就会被解析成Paramater,从而导致request.getInputStream的数据再获取时为空了。

还有就是Controller里如果用到了request.setCharacterEncoding(“GBK”); 设置字符集,这样的请求也无法生效,因为request.setCharacterEncoding只有在request.getSession或者request.getParamater之前使用有效,而由于使用Spring Session加入了filter,所以Controller里的request.setCharacterEncoding这种方式转编码就失效了,解决办法,可以是new String(request.getParameter(key).getBytes(), “GBK”),获取到参数后转码。

另外,对于多项目间session共享,跨域名session共享,还得继续分析源码,坑较多。

你可能感兴趣的:(web)