打开 tomcat
官网: http://tomcat.apache.org/ , 找到需要配置的tomcat版本的文档,这里以 tomcat7
为例,
找到对应的 Clustering
配置(因为配置session共享,就是配置集群),如下图
即,配置tomcat7集群的文档地址: http://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html
如上图官方的文档中所说,只需配置
节点即可
但其实在 tomcat
的 conf/server.xml
的配置文件中,已经有此项配置,只是被注释了,只需将注释 打开 即可,如下图
此时,准备一个 tomcat
,如上打开 conf/server.xml
中 Cluster
的节点配置,再准备一个简单的 javaWeb应用
(打印 sessionId
,做验证配置是否成功),放到 tomcat
的 webapps
目录下
打印 sessionId
的 jsp
如下
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
session replication
SessionID:<%=session.getId() %>
因为是在本地做验证,所以,再将以上配置完成的 tomcat
再复制一份,然后修改 tomcat
的端口,这里我两个 tomcat
的应用端口是 8081
和 8082
,如下图所示
tomcat
的 webapps
目录,如下
修改完成配置之后,分别启动 tomcat
,打开浏览器测试之后,如下
测试发现,两个 tomcat
的 sessionId
并不一致?!
另外,还发现了一个问题,就是 来回刷新 浏览器的
两个tomcat的应用
的index.jsp,浏览器显示的 两个sessionId
在不断的变化 ,但是这个问题跟配置session共享
无关,是cookie的作用域
导致的,后续再单独写一篇笔记讲。
此时我们再返回 tomcat
官网配置 Cluster
的文档处,继续阅读,找到其中的 Cluster Basics
标签那,如下图所示,
文档中,说要配置 session复制
必须完成以下几步:
节点 (x,这个没有配)
并且 jvmRoute 属性值与 workers.properties 中的 worker name 匹配 (x,没配,不用管)所以,意思就是,在 conf/server.xml
中配置了 Cluster
节点外,还需要在 web应用
的 web.xml
文件里面配置
节点,如下图所示
配置完成之后,重新启动两个 tomcat
,重新刷新浏览器的页面,此时如下图所示,sessionId 已经一致,即 session共享
配置成功。
上文在官网中截取的,配置 Cluster 节点的图,如下所示,
图中最后提到的,The following is the default cluster configuration
如下配置,
<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.JvmRouteSessionIDBinderListener" />
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
Cluster>
即配置
与上面这一大段的配置内容,效果是一样的,但是这样一来,细粒度越小,可以调整的内容也就越多
在上面的这么多配置中,需要注意的是,address="228.0.0.4"
这个地址为 组播地址,属于 ip地址
中的 D类地址
这个地址可以改,但是只能改为另一个组播地址。如果随便填一个非组播地址,tomcat启动的时候会报一个 Not a multicast address
的错误,这个报错来自 java
的 java.net.MulticastSocket
,如下所示,
在配置了 Cluster
节点之后,tomcat
启动的过程中,会调用 org.apache.catalina.tribes.membership.McastService
的 start()
方法,然后在方法中验证 address
的值是否是一个组播地址(D类地址
,它的第1个字节的前四位固定为 1110
,即 ipv4
的地址的下限为 224.0.0.1
)
在 tomcat
文档的最后,有讲到这个问题:
当配置了 Cluster
节点的 tomcat
启动的时候,会创建 Host
对象,并用一个集群对象与之关联。启动过程中,到了解析 Context
(即 web应用
)的时候,如果 web应用
的 web.xml
配置了
的节点,则 Cluster
的对象会创建一个 manager
去管理 session复制
。之后,Cluster
的对象将启动一个 membership
的服务(多播)和一个 replication
的服务(tcp单播)。下图是关于上述描述的 tomcat源码
。
Tomcat
之间的 session replication
通信是使用简单的 多播ping
建立的。每个 Tomcat实例
将定期发出 多播ping
,在 ping消息
中,会包含 Tomcat实例
的 IP
和 TCP侦听端口
去进行 与其他实例的 session复制
。如果 Tomcat实例
在给定的时间范围内没有收到此类ping,则该成员被视为已死。
当 Tomcat实例
收到 组播ping
,该成员就会被添加到集群中,在下一个复制请求时,发送实例将通过集群的成员列表侦听的 ip和端口
信息(单播)建立 TCP Socket连接
,进行 session复制
。
组播传输:在发送者和每一接收者之间实现点对点网络连接,如果一台发送者同时给多个接收者传输相同的数据,也只需要复制一份的相同数据包,它提高了数据的传输效率。
在因特网中的IP组播也是用组播组的概念,每个组都有一个特别分配的地址,要给该组发送的计算机将使用这个地址作为分组的目标地址。在IPv4中,这些地址在D类地址空间中分配,而IPv6也有一部分地址空间保留给组播组。
需要注意的是,主机组播时仅发送一份数据,只有数据在传送路径出现分岔时才将分组复制后继续转发。
即,在 Tomcat
启动时,发送 组播ping
建立集群的成员列表。在下一个 session复制
的请求时,根据集群成员列表的各成员侦听的 ip和端口
,逐一建立 socket连接
,进行 session复制
。