Tomcat的Session共享

1、为什么会提出这个问题?
使用Nginx+Tomcat进行负载均衡时,希望使用轮询方式进行负载。但是如果使用轮询方式的话,可能会访问不同的Tomcat,此时如果不进行Session共享,则相当于是一个新的Session。就比如现有系统都是需要认证登录的系统,如果没有Session共享,则会导致用户退出登录。
2、方案1:使用Tomcat内置的Session复制方案
具体配置如下:

    <!-- 第1步:修改server.xml,在Host节点下添加如下Cluster节点 -->
    <!-- 用于Session复制 -->
    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
        <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" />
        <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.4"
                        port="45564" frequency="500" dropTime="3000" />
            <!-- 这里如果启动出现异常,则可以尝试把address中的"auto"改为"localhost" -->
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="4000"
                      autoBind="100" selectorTimeout="5000" maxThreads="6" />
            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
                <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
            </Sender>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector" />
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor" />
        </Channel>
        <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter="" />
        <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve" />
        <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/"
                  deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false" />
        <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
    </Cluster>
     
    <!-- 第2步:在web.xml中添加如下节点 -->
    <!-- 用于Session复制 -->
    <distributable/>

最终在Tomcat日志里可能会打印出如下日志信息:

    29-Mar-2018 15:06:22.181 INFO [localhost-startStop-1] org.apache.catalina.ha.session.DeltaManager.getAllClusterSessions Manager [/ydzwV3], requesting session state from org.apache.catalina.tribes.membership.MemberImpl[tcp://{192, 168, 1, 233}:4010,{192, 168, 1, 233},4010, alive=572778, securePort=-1, UDP Port=-1, id={-56 73 0 62 -31 -122 65 -50 -108 49 -1 -12 -84 -32 -7 -77 }, payload={}, command={}, domain={}, ]. This operation will timeout if no session state has been received within 60 seconds.
    29-Mar-2018 15:06:22.282 INFO [localhost-startStop-1] org.apache.catalina.ha.session.DeltaManager.waitForSendAllSessions Manager [/ydzwV3]; session state send at 3/29/18 3:06 PM received in 107 ms.

3、方案2:使用第三方(个人)基于Tomcat实现的Session管理

这里github上的tomcat-redis-session-manager来实现。
项目地址:https://github.com/jcoleman/tomcat-redis-session-manager
具体配置方法,在上述站点中有详细说明。在此不再赘述。
注意:这种方式还不支持Tomcat8。尽管有人基于上述代码进行了修改,但不能保证可用性。
4、方案3:使用Spring Session实现

Spring Session提供了多种方式来存储Session信息,包括redis、mongo、gemfire、hazelcast、jdbc等。这里用redis来举例说明,首先进行依赖添加,然后进行配置即可。

4、1 添加依赖(gradle)

compile "org.springframework.session:spring-session-data-redis:1.3.2.RELEASE"

注意:当引入上述依赖包时,还会引入如下依赖:

org.apache.commons:commons-pool2:2.4.2
org.springframework.data:spring-data-redis:1.7.10.RELEASE
org.springframework.session:spring-session:1.3.2.RELEASE
redis.clients:jedis:2.8.1

项目中原来使用了Redis作为Spring Cache的实现,当时使用的spring-data-redis是1.4.2.RELEASE版本,现在使用1.7.10.RELEASE版本后,需要把cacheManager这个Bean做如下调整:

    <!-- 调整前 -->
    <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
        c:template-ref="redisTemplate"/>
     
    <!-- 调整后 -->
    <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
        c:redisOperations-ref="redisTemplate">
    </bean>

4、2 进行Spring Session配置

    <!--
        第1步:在Spring配置文件中添加如下bean
        以后在web.xml中配置session超时时间就无效了,如果需要指定session超时时间,则使用maxInactiveIntervalInSeconds来指定,默认是1800s=30min
    -->
    <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"
          p:maxInactiveIntervalInSeconds="1800"/>

??? 这里怎么没有Redis连接配置 ??? 请看RedisHttpSessionConfiguration类中的如下代码:

    // 这里会自动注入connectionFactory,而项目中已经注入了jedisConnectionFactory
    @Bean
    public RedisTemplate<Object, Object> sessionRedisTemplate(
        RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        if (this.defaultRedisSerializer != null) {
            template.setDefaultSerializer(this.defaultRedisSerializer);
        }
        template.setConnectionFactory(connectionFactory);
        return template;
    }

项目中注入的jedisConnectionFactory Bean如下:

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
        p:host-name="${redis.hostname}"
        p:port="${redis.port}"
        p:database="${redis.database}"
        p:poolConfig-ref="redispoolconfig"
        p:use-pool="${redis.usepool}">
    </bean>

所以,如果你项目中从来没有使用过Redis,也可以使用如下配置:

    <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
    <!--
        Jdeis连接工厂Bean
        注意:这种方式没有使用连接池,生产环境下务必需要使用连接池
    -->
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
        p:host-name="192.168.1.233" p:port="6379" p:database="15" p:usePool="false">
    </bean>

下面进行过滤器的配置:

    <!-- 第2步:在web.xml中添加如下过滤器 注意:此过滤器必须放在其他过滤器之前-->
    <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>
    </filter-mapping>

至此,就配置完成啦!
在Redis中查看效果:如果运行成功的话,可以在Redis中查看到key为spring:session:sessions的信息,如下所示:


5、方案对比
针对上述3中方案,以下仅是个人见解。
方案1:使用Tomcat内置的Session复制方案
SimpleTcpCluster        优点:内置
缺点:只适合Tomcat小集群,不适合大集群,因为session复制是all to all的方式
方案2:使用第三方(个人)基于Tomcat实现的Session管理
tomcat-session-manager        优点:已经实现对tomcat7的支持
缺点:第三方支持,支持力度不够,尤其是不能提供对Tomcat8的支持
方案3:使用Spring Session实现
基于redis存储实现        优点:不依赖于特定容器,官方支持
缺点:未发现

所以,我认为还是Spring Session来实现Session共享更加好用。
---------------------
作者:94小白菜
来源:CSDN
原文:https://blog.csdn.net/u012383839/article/details/79756368
版权声明:本文为博主原创文章,转载请附上博文链接!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值