参考地址:
http://developer.51cto.com/art/201105/260375.htm
http://www.360doc.com/content/13/1224/19/13247663_339826101.shtml
http://www.imooo.com/web/xml-soap/254546.htm
http://zyycaesar.iteye.com/blog/296606
http://blog.csdn.net/zhuying_linux/article/details/6590700
通过网上查找资料,知道了tomcat其实是可以实现session共享的,下面就具体的说明下怎么配置实现多个服务器之间的session共享。
1、最简单的实现tomcat之间session共享的方法:
第一步:启动负载均衡器如(nginx),这里就不讲了;
第二步:准备多台tomcat服务器;
第三步:修改conf目录下的server.xml文件,去掉下面这句的注释,然后再web.xml文件的节点</web-app>前加上<distributable />(这个是tomcat进行session复制所必须的,否则session不能进行复制!)即可;
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
或者改变Tomcat的content.xml配置文件,修改 <Context distributable="true">,配置好之后启动服务器就可以了。
2、<Cluster>标签详解,<Cluster>默认配置如下
<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"/> <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.MessageDispatch15Interceptor"/> </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>前面提到的<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>简单配置就等同于默认配置。
Cluster
Tomcat集群配置。集群的配置比较复杂,默认的集群配置可以满足一般的开发需求
常用属性:
className-指定Cluster使用的类
channelSendOptions-Cluster发送消息的方式
channelSendOptions可以设置为2、4、8、10,每个数字代表一种方式
2 = Channel.SEND_OPTIONS_USE_ACK(确认发送)
4 = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK(同步发送)
8 = Channel.SEND_OPTIONS_ASYNCHRONOUS(异步发送)
在异步模式下,可以通过加上确认发送(Acknowledge)来提高可靠性,此时channelSendOptions设为10
Manager
Manager决定如何管理集群的Session信息。Tomcat提供了两种Manager:BackupManager和DeltaManager
BackupManager-集群下的所有Session,将放到一个备份节点。集群下的所有节点都可以访问此备份节点
DeltaManager-集群下某一节点生成、改动的Session,将复制到其他节点。DeltaManager是Tomcat默认的集群Manager,能满足一般的开发需求
使用DeltaManager,每个节点部署的应用要一样;使用BackupManager,每个节点部署的应用可以不一样
常用属性:
className-指定实现org.apache.catalina.ha.ClusterManager接口的类
expireSessionsOnShutdown-设置为true时,一个节点关闭,将导致集群下的所有Session失效
notifyListenersOnReplication-集群下节点间的Session复制、删除操作,是否通知session listeners
maxInactiveInterval-集群下Session的有效时间(单位:s)。maxInactiveInterval内未活动的Session,将被Tomcat回收。默认值为1800(30min)
Channel
Channel是Tomcat节点之间进行通讯的工具。Channel包括5个组件:Membership、Sender、Transport、Receiver、Interceptor
Membership
Membership维护集群的可用节点列表。它可以检查到新增的节点,也可以检查到没有心跳的节点
常用属性:
className-指定Membership使用的类
address-组播地址
port-组播端口
frequency-发送心跳(向组播地址发送UDP数据包)的时间间隔(单位:ms)。默认值为500
dropTime-Membership在dropTime(单位:ms)内未收到某一节点的心跳,则将该节点从可用节点列表删除。默认值为3000
组播(Multicast):一个发送者和多个接收者之间实现一对多的网络连接。一个发送者同时给多个接收者传输相同的数据,只需复制一份相同的数据包。它提高了数据传送效率,减少了骨干网络出现拥塞的可能性
相同组播地址、端口的Tomcat节点,可以组成集群下的子集群
Receiver
接收器,负责接收消息
接收器分为两种:BioReceiver(阻塞式)、NioReceiver(非阻塞式)
常用属性:
className-指定Receiver使用的类
address-接收消息的地址
port-接收消息的端口
autoBind-端口的变化区间
如果port为4000,autoBind为100,接收器将在4000-4099间取一个端口,进行监听
selectorTimeout-NioReceiver内轮询的超时时间
maxThreads-线程池的最大线程数
Sender
发送器,负责发送消息
Sender内嵌了Transport组件,Transport真正负责发送消息
Transport分为两种:bio.PooledMultiSender(阻塞式)、nio.PooledParallelSender(非阻塞式)
Interceptor
Cluster的拦截器
TcpFailureDetector-网络、系统比较繁忙时,Membership可能无法及时更新可用节点列表,此时TcpFailureDetector可以拦截到某个节点关闭的信息,并尝试通过TCP连接到此节点,以确保此节点真正关闭,从而更新集群可以用节点列表
MessageDispatch15Interceptor-MessageDispatch15Interceptor查看Cluster组件发送消息的方式是否设置为Channel.SEND_OPTIONS_ASYNCHRONOUS(Cluster标签下的channelSendOptions为8时)。设置为Channel.SEND_OPTIONS_ASYNCHRONOUS时,MessageDispatch15Interceptor先将等待发送的消息进行排队,然后将排好队的消息转给Sender
Valve
Valve可以理解为Tomcat的拦截器
ReplicationValve-在处理请求前后打日志;过滤不涉及Session变化的请求
JvmRouteBinderValve-Apache的mod_jk发生错误时,保证同一客户端的请求发送到集群的同一个节点
Deployer
同步集群下所有节点的一致性。Deployer没试验成功过。。。
ClusterListener
监听器,监听Cluster组件接收的消息
使用DeltaManager时,Cluster接收的信息通过ClusterSessionListener传递给DeltaManager
3、使用这样方法配置的集群会将Session同步到所在网段上的所有配置了集群属性的实例上(此处讲所在网段可能不准确,因为用的228.0.0.4地址进行的广播,我不清楚这是个什么性质的广播地址)。也就是说如果该广播地址下的所有Tomcat实例都会共享Session,那么假如有几个互不相关的集群,就可能造成Session复制浪费,所以为了避免浪费就需要对节点多做点设置了,如下:
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"> <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"/> Channel> Cluster>
tomcat的集群部署修改动作都比较简单,但实际在运行过程中会出现一系列的问题,我这里列举我在配置后使用过程中出现的一些问题和要点,供大家参考:
1、用户存入SESSION中的数据的问题
使用tomcat集群进行SESSION复制,必须要保证你的session中存放的所有对象都是实现了java.io.Serializable接口 的,因为session复制就是序列化对象到其他WEB应用服务器上的,所以如果没有实现该接口,那么SESSION同步将会失败。另外一点,就是如果要 同步的机器比较多的话,那么要注意保证SESSION中存放的数据比较小,不要什么都存放到SESSION中,因为复制SESSION也是需要开销的,数 据越大开销也越大。
2、Tomcat执行SESSION复制的触发条件
我们在tomcat的server.xml文件中集群部分cluster标签中可以看到属性:useDirtyFlag, 如果这个设置为true(默认的),那么只有当使用setAttribute往session中设置数据的时候才会同步其他WEB服务器的 SESSION,如果为false,那么每一次请求的sesison都会被同步到其他服务器上。因此在操作SESSION的时候要特别注意,避免出现 SESSION无法同步的问题。
举个简单的例子,比如我们在单机应用情况下修改SESSION中用户的某一个数据,那么通常就是:
User user = (User)request.getSession().getAttribute("user");
User.setName("my name");
这样我们就是直接存取出来,然后进行修改,虽然在单机情况下没有问题,但是在集群条件下,这样就导致了多台WEB服务器上的SESSION不同步的问 题,因为SESSION并没有改变,Tomcat无法监视session中某个数据的值是否发生了变化。因此,我们还需要执行如下操作以保证 SESSION的同步:
request.getSession().setAttribute(“user”, user);
所以,我们在操作SESSION的时候要特别注意!另外的建议就是,我们应该尽可能的不要修改SESSION中的数据。
因为Tomcat的SESSION复制通信是通过组播功能来实现不同服务器之间的交互的,所以需要在服务器上开通组播功能,windows默认情况下是开通组播服务的,而Linux系统下默认是没有开通的,我们需要通过如下命令来开通其组播功能:
route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
如果需要服务器启动时即开通组播需在/etc/sysconfig/static-routes文件内加入eht0 net 224.0.0.0 netmask 240.0.0.0。具体组播概念请查阅CCNP相关内容。
可以通过netstate -g 来查看组播状态,也可以在route -e 命令中看到