Spring-Session 和 Redis实现Session共享

简介

Session一直是我们做集群时一个很头疼的问题,之前有一个GitHub上开源的Tomcat-redis-session-manager,但是它只支持到Tomcat7,所以不是一种最佳选择,所以才会有今天的Spring-session 和 redis 来做session共享 。

session共享的几种方式

  1. Tomcat的Session复制(在<Engine>节点下+Cluster

1、实现方式简单,但是只适合在小集群中使用,如果集群过大Session间的复制将会带来很大的流量消耗
2、 tomcat的session复制分为两种, 一种是全局试的(all-to-all), 这意味着一个node(tomcat实例)的session发生 变化之后, 它会将这些变更复制到其他所有集群组的成员;另一种是局部试的, 它会用到BackupManager, BackupManager能实现只复制给一个Buckup Node, 并且这个Node会部署相同的Web应用, 但是这种方式并没用经过很多的测试。
3、Tomcat的session复制是基于IP组播(multicast)来完成的。简单的说就是需要进行集群的tomcat通过配置统一的组播IP和端口来确定一个集群组, 当一个node的session发生变更的时候, 它会向IP组播发送变更的数据, IP组播会将数据分发给所有组里的其他成员(node)。
4、如果换了别的web服务器就没办法使用了(与web容器耦合性太强)

  1. 第三方:Tomcat-redis-session-manager

而且现在官方也没去更新tomcat-redis-session-manager的jar包了(仍然停留在支持tomcat7上,一些自己修改的jar包除外)。
只支持到了Tomcat7

  1. 利用Nginx Session共享

Nginx中的ip_hash 技术能够将某个ip的请求负载均衡到同一台服务器上,这样一来这个IP下的某个客户端和后台就可以就能建立起固定的session。ip_hash 是在upstream配置中定义的。具体配置如下:

upstream www.test.com {
	ip_hash;
	server 192.168.74.131:8080;
	server 192.168.74.131:8081;
}

server {
	listen 80;
	server_name www.test.com; ## server_name要与自定义的upstream一致。
	location / {
	proxy_pass http://www.test.com; ## 添加代理路径。
}

ip_hash 是通过请求端的ip地址计算hash值,与后端服务器定位。由于相同的ip计算出的hash值都是一样的,所以同一台机器的请求每次都可以落到相同的服务器上。但这种方式的局限性太大。比如,客户端请求的ip是动态的或者那台服务宕机了,对应的后端服务器出现故障。这些都使session共享变得不可用。所以使用ip_hash方式实现的session共享不是一个最佳的解决方案

  1. Spring-session 和 redis

1.Spring Session提供了redis、jvm的map、mongo、gemfire、hazelcast、jdbc等多种存储session的容器的方式。
2.同一个浏览器同一个网站,支持多个session。
3.不依赖于cookie。可通过header来传递sessionID
4.WebSocket和spring-session结合,同步生命周期管理。
5.使用简单
6.不依赖与具体的web容器

web.xml 中 spring session的配置

这里使用了Spring Web提供的代理过滤器,将拦截到的请求全部交给一个名为springSessionRepositoryFilter的过滤器进行处理(注意:这个过滤器要配置在第一个)

<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> 

applicationContext.xml中配置Spring Session和Redis,如下:

hostName:redis的地址,port 为redis的服务端口号

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="10"/><!-- 最大空闲连接数, 默认8个 -->
        <property name="maxTotal" value="20"/><!-- 最大连接数, 默认8个 -->
        <property name="blockWhenExhausted" value="true"/><!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
        <property name="maxWaitMillis" value="1000"/><!-- 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1 -->
        <property name="testOnBorrow" value="true"/><!-- 在获取连接的时候检查有效性, 默认false -->
    </bean>
    
    <!-- redis连接配置,依次为主机ip,端口,密码,是否使用池,连接池配置引用 -->
    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" 
        p:host-name="192.168.17.132" p:port="6379" p:password="123456" p:usePool="true" p:pool-config-ref="jedisPoolConfig">
    </bean>
    
    <!-- 配置spring-session -->
    <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <!-- session过期时间,单位是秒 -->
        <property name="maxInactiveIntervalInSeconds" value="30"></property>
    </bean>
</beans>

注意,用了spring session后,在web.xml设置的session过期时间是无效。因为此session已经不是原来的存储在容器缓存内的session了,而是被封装多了一层后存储在redis的session。
只需要上述两步就完成了Spring-session的配置了,是不是很简单!

Server端示例:

@Controller
public class HelloController {
    @RequestMapping("/setsession")
    @ResponseBody
    public void setSession(HttpSession session, String name) {
        session.setAttribute("name", name);
    }

    @RequestMapping(value = "/getsession",produces = "text/html;charset=utf-8")
    @ResponseBody
    public String getSession(HttpSession session, HttpServletRequest req) {
        return session.getAttribute("name").toString()+"-----"+req.getServletContext().getRealPath("/");
    }
}
参考1
参考2
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值