spring-session做分布式共享
分布式,集群环境下session如何处理?
如果不共享session的请求下,对手机进行短信验证.
对短信验证的步骤如下 :
- 一. 获取验证码,把获取得到的验证码保存到该用户的session中
- 二. 然后把该验证码以短信的方式发送到手机上.
- 三. 用户在进行操作的时候,所要提交的表单中需要包含,要操作的信息和输入的验证码.
后台会把用户输入的验证码与session中的验证码进行对比,如果验证通过,则可以进行后续的操作.
在这个流程中,验证码存到session中,之后验证码的校验是这个流程的关键.
如果session不共享,那么请求分配到的是不同机器上,那么就会有数据不同步的问题
为了解决以上遇到的问题,需要处理的问题是,session如何在分布式环境上共享.
网上提供了三种常用的分布式环境,管理session的方案
session复制
将一台机器上的session数据以广播的形式发布到其余机器上
session绑定
指的是如果机器A有用户A的session信息,那么用户A在访问的时候,仍被分配到机器A上,(如上的例子,则需要单独去短信模块中进行验证)
session集中式管理
这种方式,是建立一个单独的服务器,共同处理集群中的session信息.
权衡一下这几种方案
- 第一种方案中每台机器上都存有大量的session信息,对网络的依赖较大.
- 第二种方案中,session信息只存在指定的某台机器上,如果某台机器down掉之后,会有用户信息的丢失.
- 结合上面的几种优缺点.决定还是使用第三种方案,如果为了考虑可用性,可以建立多个服务器管理session.
最终采用的解决方案,用户获取验证码之后,把验证码保存到Redis里面.然后用户在操作之后,把输入的验证码与存到session中的验证码对比,如果验证码正确则可以继续操作.
当然系统能不使用session就尽量不使用session,但是对于之前开发的项目很多地方使用到了session,为了系统稳定,则需要维护之前的.
之前项目使用的session处理是 tomcat-redis-session-manager
https://github.com/jcoleman/tomcat-redis-session-manager 上面提供的
用这个可以解决tomcat session共享的问题,但是这样依赖于环境,需要配置环境.
之前项目就是用的是 tomcat-redis-session-manager 因为太依赖环境,并且只支持tomcat 7,后面我换成了spring-session进行管理session.
spring-session 不仅配置简单,而且有人持续维护更新,为什么不适用spring-session呢.
spring-session 配置
pom.xml 加入依赖
1 | <dependency> |
web.xml 加入配置
1 | <!-- spring-session 做session共享 --> |
配置redis和spring-session
1 |
|
这样就OK了,这样把这个项目打成war部署到多台服务器,只要redis是同一个源那么他们的session就是一样的. (当然域名要一样)
好了session共享搞定了,并且不依赖环境了,但是后面又遇到一个不同域名需要进行session共享的问题
因为我们后台系统是只能用内网才能访问,所以后台系统并没有申请域名,直接使用的是IP
比如 : 10.0.0.122,10.0.0.123,这两台机器是集群部署,但是按照上面的配置,session是无法共享的,因为域名不一致
后面翻阅了spring-session的文档,找到了答案
http://docs.spring.io/spring-session/docs/current-SNAPSHOT/reference/html5/guides/custom-cookie.html
http://docs.spring.io/spring-session/docs/current-SNAPSHOT/reference/html5/guides/java-custom-cookie.html
spring-session 不同域名共享配置
配置如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!-- 设置Cookie domain 和 名称 -->
<bean id="defaultCookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer">
<!-- 10.0.0.122,10.0.0.123 -->
<property name="DomainNamePattern" value="(^10.0.0.12)[2-3]{1}"/>
<property name="cookieName" value="JsessionID"/>
</bean>
<!--
用 spring-session 做分布式session
将session放入redis
设置 3600 秒
-->
<bean id="redisHttpsessionConfiguration"
class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpsessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="3600" />
</bean>
如果正则表达式觉得很难去写,可以写个单元测试慢慢匹配
源代码 org.springframework.session.web.http.DefaultCookieSerializer 中就是这样匹配的