一、现状:
1、安全框架使用shiro,sessionManager采用shiro的org.apache.shiro.web.session.mgt.DefaultWebSessionManager,而不是默认的org.apache.shiro.web.session.mgt.ServletContainerSessionManager
2、
ServletContainerSessionManager使用的是容器的session管理,如果搭建tomcat集群的话,可以通过配置tomcat来复制session
3、
DefaultWebSessionManager使用的是shiro框架提供的session管理器,而此管理器配置的存储ehcache缓存,tomcat集群不会复制session
4、使用nginx作为反向代理
5、假设应用服务器有两台A、B
6、shiro和ehcache整合后,默认的session存放的cache name是
shiro-activeSessionCache,配置如下
-
<cache name="shiro-activeSessionCache"
-
maxElementsInMemory = "20000"
-
overflowToDisk="false"
-
eternal="false"
-
diskPersistent="false"
-
timeToLiveSeconds="0"
-
timeToIdleSeconds="0"
-
statistics="true">
-
</cache>
二、问题:
1、用户登录时,用户名密码无误,登录到服务器A,此时,服务器A的ehcache中是有对应用户的session的,登录A成功
2、登录后,页面跳转到主页,此时,ngnix负载均衡到服务器B,而此时服务器B的ehcache中是没有对用session的,登录B失败
3、结果就是又跳回到登录页面,总之就是登录不了系统
三、解决方案:
在继续使用ehcache作为session缓存的前提下,按照官方文档的说法,有以下两种解决方案
1、使用
Terracotta Cluster搭建一个集群来统一管理cache,貌似企业版,要收费,因此这种方案不考虑
2、就是社区免费版提供的
Replication方案,这种方案下面又有3中方式
1)RMI Replicated Caching
2)Replicated Caching using JGroups
3)Replicated Caching using JMS
看起来第一种RMI是想对简单的,因此选择RMI复制方式
3、最终目标:用户登录时,session存放在服务器A的cache里面,同时,服务器A会复制相同的一份数据更新到服务器B,这样一来,跳转到服务器B之后,用户的session依然是有效的
四、步骤
假设服务器A的IP:192.168.1.101,服务器B的IP:
192.168.1.102
RMI方式其实也有两种peerDiscovery方式:自动和手动
1、自动方式,这种方式最终配置会比较简单,特别是集群里面有很多服务器的时候,但是在防火墙后面的话也需要额外做一些工作
1)防火墙设置
需要根据配置文件打开以下端口40001(TCP)、40002(TCP)、4446(UDP),其中4446是用于组播的端口(这个我不熟,自己理解的,可能有误)
开启multicast的命令,只在centos7下面用过,其他操作系统请自查
firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -m udp -p udp -m pkttype --pkt-type multicast -j ACCEPT
firewall-cmd --reload
2)ehcache.xml配置文件
A、配置RMICacheManagerPeerListenerFactory
-
<cacheManagerPeerListenerFactory
-
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
-
properties="hostName=localhost, port=40001, remoteObjectPort=40002, socketTimeoutMillis=2000" />
防火墙下面一定要注意remoteObjectPort的配置,这个是一个坑,官网文档中都没提,如果没有防火墙的话,这个属性可以不配置,默认是一个随机的端口
这里的两个端口40001、40002,还有一个hostName需要配置真实的IP地址,例如
服务器A的IP:192.168.1.101,服务器B的IP:192.168.1.102
B、配置自动发现方式cacheManagerPeerProviderFactory
点击(此处)折叠或打开
-
<cacheManagerPeerProviderFactory
-
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
-
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
-
multicastGroupPort=4446, timeToLive=32" />
属性peerDiscovery=automatic意思就是自动发现
multicastGroupAddress=230.0.0.1就是组播地址
multicastGroupPort=4446就是组播端口 (这也就是为什么防火墙需要打开4446这个端口的原因)
timeToLive=32的含义如下(一般如果ehcache都在同一个子网下的话,填写1即可)
0 is restricted to the same host
1 is restricted to the same subnet
32 is restricted to the same site
64 is restricted to the same region
128 is restricted to the same continent
255 is unrestricted
C、针对每一个需要同步复制的cache进行配置
-
<cache name="shiro-activeSessionCache"
-
maxElementsInMemory = "20000"
-
overflowToDisk="false"
-
eternal="false"
-
diskPersistent="false"
-
timeToLiveSeconds="0"
-
timeToIdleSeconds="0"
-
statistics="true">
-
<cacheEventListenerFactory
-
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
-
properties="replicateAsynchronously=false" />
-
</cache>
主要是加这样一个子元素:
-
<cacheEventListenerFactory
-
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
-
properties="replicateAsynchronously=false" />
replicateAsynchronously=false 该属性默认是true,意思就是异步复制cache,把它设置为false是为了防止,这边后台session还没复制过去到B服务器呢,前台已经跳转到B服务器了。
其他属性采用了默认值,如果需要修改的话,请参考官方文档修改。
D、对于其他需要复制的Cache进行上一步骤的配置
1、手动方式,这种方式最终配置会比自动方式复杂一些,特别是集群里面有很多服务器的时候
1)防火墙设置
需要根据配置文件打开以下端口40001(TCP)、40002(TCP),这两个端口和自动方式一样都需要开启,而4446端口不需要开启,因为不需要组播,我们后面手动配置
2)ehcache.xml配置文件
A、配置RMICacheManagerPeerListenerFactory:这个配置和自动方式下的配置完全一致。
-
<cacheManagerPeerListenerFactory
-
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
-
properties="hostName=localhost, port=40001, remoteObjectPort=40002, socketTimeoutMillis=2000" />
防火墙下面一定要注意remoteObjectPort的配置,这个是一个坑,官网文档中都没提,如果没有防火墙的话,这个属性可以不配置,默认是一个随机的端口
这里的两个端口40001、40002,还有一个hostName需要配置真实的IP地址,例如服务器A的IP:192.168.1.101,服务器B的IP:192.168.1.102
B、配置手动发现方式cacheManagerPeerProviderFactory :这个配置和自动方式不一样,这也是两种方式最主要的区别
假设还有第三台服务器192.168.1.103,
那么在192.168.1.101上需要这么配
-
<cacheManagerPeerProviderFactory
-
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
-
properties="peerDiscovery=manual,rmiUrls=//192.168.1.102:40001/shiro-activeSessionCache|//192.168.1.103:40001/shiro-activeSessionCache" />
那么在192.168.1.102上需要这么配
-
<cacheManagerPeerProviderFactory
-
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
-
properties="peerDiscovery=manual,rmiUrls=//192.168.1.101:40001/shiro-activeSessionCache|//192.168.1.103:40001/shiro-activeSessionCache" />
-
那么在192.168.1.103上需要这么配
-
<cacheManagerPeerProviderFactory
-
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
-
properties="peerDiscovery=manual,rmiUrls=//192.168.1.102:40001/shiro-activeSessionCache|//192.168.1.101:40001/shiro-activeSessionCache" />
-
其中peerDiscovery=manual就是手动配置的意思
rmiUrls就是远程主机的地址,每台服务器的配置都不一样,这也是我们推荐使用自动discovery的原因。
当然,可能因为防火墙或者其他原因(比如虚拟机什么的,官网好像有提到),不能使用组播的时候,就可以使用这种手动方式
C、针对每一个需要同步复制的cache进行配置:这个配置和自动方式下的配置完全一致。
-
<cache name="shiro-activeSessionCache"
-
maxElementsInMemory = "20000"
-
overflowToDisk="false"
-
eternal="false"
-
diskPersistent="false"
-
timeToLiveSeconds="0"
-
timeToIdleSeconds="0"
-
statistics="true">
-
<cacheEventListenerFactory
-
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
-
properties="replicateAsynchronously=false" />
-
</cache>
主要是加这样一个子元素:
-
<cacheEventListenerFactory
-
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
-
properties="replicateAsynchronously=false" />
replicateAsynchronously=false 该属性默认是true,意思就是异步复制cache,把它设置为false是为了防止,这边后台session还没复制过去到B服务器呢,前台已经跳转到B服务器了。
其他属性采用了默认值,如果需要修改的话,请参考官方文档修改。
D、对于其他需要复制的Cache进行上一步骤的配置
阅读(5029) | 评论(0) | 转发(0) |