分布式中解决session共享方案
1. nginx方案
nginx提供了ip_hash策略,可以保持用户ip进行hash值计算固定分配到某台服务器上,然后只要是该ip则会保持分配到该服务器上,保证用户访问的是同一台服务器,那么session问题就不存在了。这也是解决session共享的一种方式,也称为黏性session。但是假设一台tomcat服务器挂了的话,那么session也会丢失。所以比较好的方案是抽取session。
2. tomcat方案
tomcat与redis集成实现session共享:
环境为tomcat7 + jdk1.6的话:
在所有需要共享session的服务器的tomcat中目录下:
lib目录中添加以下三个jar包,注意版本最好一致,不然极容易出现错误,下边的测试是可用的:
conf目录中content.xml中加入:配置redis服务
环境为tomcat7 + jdk1.7或1.8的话:
在所有需要共享session的服务器的tomcat中目录下:
lib目录中添加以下三个jar包,测试通过:
conf目录中content.xml中加入:配置redis服务
根据我这测试,是jkd1.8+tomcat7,在137和139两台tomcat中加入jar包且进行如上配置:
修改content.xml
添加两个注意点
1、按照如上配置,使用redis数据库,放入session中的对象必须要实现java.io.Serializable接口,使用memcache的可以不用实现Serializable接口
原因是:因为tomcat里使用的将session放置redis使用的工具类,是使用的jdk序列化模式存储的,这一点也是很容易理解的,session.setAttribute(String key, Object value),存储Object类型
object放入redis中又要能取出来,只能是序列化进行存储了,然后取出的时候进行反序列化。
所以我们在session中存储的任何对象,都必须实现序列化接口。
2、按照如上配置,使用redis做session存储空间时,web应用的session-time的时间单位会变成[秒],而不是原本的[分]
原因是:因为tomcat里使用的将session放置redis使用的工具类,在存储时为对tomcat容器时间做转换
在redis中设置过期时间是使用秒作为单位的,有个命令叫expire可以设置redis键值过期时间,所以在context.xml配置文件中我们需要制定session过期时间(默认是60秒,配成1800即30分钟),这一点很重要。
请注意!!!!
context.xml配置说明:
3.Spring Session+Spring Data Redis 解决
(1)引入相关jar包:
这里需要引入Spring Session和Spring Data Redis相关的依赖jar包。可以自行从maven仓库下载,也可以参考使用的jar包:down.51cto.com/data/228183… (2)修改spring-data-redis相关配置:
在项目的spring-data-redis相关配置中添加以下配置:
完整的context_redis_cluster.xml文件如下: <?xml version="1.0" encoding="UTF-8"?>
spring-data-redis-cluster
<!-- 配置Cluster -->
<bean id="redisClusterConfiguration"
class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<property name="maxRedirects" value="${redis.cluster.maxRedirects}" />
<!-- 节点配置 -->
<property name="clusterNodes">
<set>
<bean class="org.springframework.data.redis.connection.RedisClusterNode">
<constructor-arg name="host" value="${redis.cluster.host1}" />
<constructor-arg name="port" value="${redis.cluster.port1}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisClusterNode">
<constructor-arg name="host" value="${redis.cluster.host2}" />
<constructor-arg name="port" value="${redis.cluster.port2}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisClusterNode">
<constructor-arg name="host" value="${redis.cluster.host3}" />
<constructor-arg name="port" value="${redis.cluster.port3}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisClusterNode">
<constructor-arg name="host" value="${redis.cluster.host4}" />
<constructor-arg name="port" value="${redis.cluster.port4}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisClusterNode">
<constructor-arg name="host" value="${redis.cluster.host5}" />
<constructor-arg name="port" value="${redis.cluster.port5}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisClusterNode">
<constructor-arg name="host" value="${redis.cluster.host6}" />
<constructor-arg name="port" value="${redis.cluster.port6}" />
</bean>
</set>
</property>
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.cluster.jedisPoolConfig.maxTotal}" />
<property name="maxIdle" value="${redis.cluster.jedisPoolConfig.maxIdle}" />
<property name="maxWaitMillis"
value="${redis.cluster.jedisPoolConfig.maxWaitMillis}" />
<property name="testOnBorrow"
value="${redis.cluster.jedisPoolConfig.testOnBorrow}" />
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-arg ref="redisClusterConfiguration" />
<constructor-arg ref="jedisPoolConfig" />
<property name="password" value="${redis.cluster.jedisConnectionFactory.password}" />
</bean>
<bean id="stringRedisSerializer"
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
<bean id="jdkSerializer"
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory">
<!-- 序列化方法 -->
<property name="keySerializer" ref="stringRedisSerializer" />
<property name="hashKeySerializer" ref="stringRedisSerializer" />
<property name="valueSerializer" ref="jdkSerializer" />
<property name="hashValueSerializer" ref="jdkSerializer" />
</bean>
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"
p:connection-factory-ref="jedisConnectionFactory" />
<bean id="redisHttpSessionConfiguration"
class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<!--超时时间,默认1800秒-->
<property name="maxInactiveIntervalInSeconds" value="1800" />
</bean>
注:对应的属性文件是:
#Redis Cluster redis.cluster.maxRedirects=3
redis.cluster.host1=192.168.1.30
redis.cluster.port1=7000redis.cluster.host2=192.168.1.30
redis.cluster.port2=7001redis.cluster.host3=192.168.1.30
redis.cluster.port3=7002redis.cluster.host4=192.168.1.224
redis.cluster.port4=7003redis.cluster.host5=192.168.1.224
redis.cluster.port5=7004redis.cluster.host6=192.168.1.224
redis.cluster.port6=7005#JedisPoolConfig
redis.cluster.jedisPoolConfig.maxTotal=1024
redis.cluster.jedisPoolConfig.maxIdle=20
redis.cluster.jedisPoolConfig.maxWaitMillis=100000
redis.cluster.jedisPoolConfig.testOnBorrow=true#JedisConnectionFactory
redis.cluster.jedisConnectionFactory.password=admin
(3)修改web.xml:
在web.xml中添加以下filter:
springSessionRepositoryFilter
org.springframework.web.filter.DelegatingFilterProxy
springSessionRepositoryFilter
/*
注:需要将这个filter放在第一位,其他的如编码、shiro等filter需要放在这之后
到此,Spring Session和Spring Data Redis就整合到项目中了
(4)测试:
运行项目后,可以发现生成了一个名为“SESSION”的cookie。接着在我们登录之后,可以通过其cookie值在redis上取得保存的对应的session对象。如下图所示: