Tomcat集群
对于WEB应用集群的技术实现而言,最大的难点就是如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块。要实现这一点,大体上有两种方式,一种是把所有Session数据放到一台服务器上或者数据库中,集群中的所有节点通过访问这台Session服务器来获取数据;另一种就是在集群中的所有节点间进行Session数据的同步拷贝,任何一个节点均保存了所有的Session数据。两种方式都各有优点,第一种方式简单、易于实现,但是存在着Session服务器发生故障会导致全系统不能正常工作的风险;第二种方式可靠性更高,任一节点的故障不会对整个系统对客户访问的响应产生影响,但是技术实现上更复杂一些。常见的平台或中间件如microsoft asp.net和IBM WAS都会提供对两种共享方式的支持,tomcat也是这样,但是一般采用第二种方式。
集群说明:1. 负载均衡(Load Balance):当同一客户端发起一个请求时,apache始终将请求转发到同一个节点 (sticky session),当另一个客户端或同一客户端从一个新的浏览器窗口发起请求时,apache会把请求分发到另一节点 上,依次轮询,当然,可以在apache上设置后端tomcat的分发权重。从而达到负载均衡的效果。
2. 高可用(High availablity):当其中一台tomcat server 突然crash时,apache会将这在进行的请求分发到集群中其他tomcat server上,由于集群member 之间已经session replication,所以原来的session 会在另外一节点上继续进行,此时,请求已发生了无缝转移,在客户端完全感觉不到故障已发生。
* Tomcat 通过SimpleTcpcluster类进行基于内存的会话复制(in-memory replication)。Tomcat Cluster 通过组播(心跳包)方式决定组成员关系(通过TCP协议进行数据传输和其他交流),每一个节点在启动时和运行时都会有规律地(默认500毫秒)发送组播心跳包,同一个Cluster内的节点会在相同的组播地址和端口监听这些信息;在一定的dropTime内(默认3S)不发送组播报的节点就会被认为是死去并被从cluster删去;Session replication 请求和session 更新通过直接TCP 连接在cluster成员间传送,也就是说当replication session 时,节点会生成一个直接向其他节点的TCP连接。
配置:
1.Apache的配置
Listen 8051
<VirtualHost *:8051>
ServerAdmin [email protected]
ServerName localhost
ServerAlias localhost
ProxyPass /myweb balancer://cluster/myweb stickysession=JESSIONID|jessionid lbmethod=byrequests timeout=5 maxattempts=3
ProxyPassReverse / balancer://cluster
ProxyRequests Off
ProxyPreserveHost On
ErrorLog "logs/tctest_error.log"
CustomLog "logs/tctest_access.log" commmon
<proxy balancer://cluster>
BalancerMember ajp://192.168.55.229:8009 route=jvm_a
BalancerMember ajp://192.168.55.231:8009 route=jvm_b
</proxy>
</VirtualHost>
Tomcat会在创建session时会根据根据jvmRoute的值在sessionID后面追加route值(接下来将要配置),例如167A7621C8ACEF496A0E3D7720F7C35E.jvm1。客户端访问时,如果是已建立的session,有route值,apache就sticky session,使该请求一直分发到上次访问的tomcat server上,如果是第一次请求则根据既定规则分发。
2.Tomcat的配置
1修改server.xml
分别修改为:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm_a">
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm_b">
2 在server.xnml的<Engine> </Engine> 之间添加
<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"
droptTime="3000"/>
Membership用于发现集群中的其他节点,这里的address用的是组播地址使用同一个组播地址和端口的多个节点同属一个子集群,因此通过自定义组播地址和端口就可将一个大的tomcat集群分成多个子集群。
<Receiver classname="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4000"
autoBind="100"
seceltorTimeout="5000"
maxThreads="6"/>
receiver用于各个节点接收其他节点发送的数据,在默认配置下tomcat会从4000-4100间依次选取一个可用的端口进行接收,自定义配置时,如果多个tomcat节点在一台物理服务器上注意要使用不同的端口。
<Sender classname="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport classname="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
Sender用于向其他节点发送数据,具体实现通过Transport配置
<Interceptor classname="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor classname="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
Channel 是一个抽象的端口,和socket类似,集群member通过它收发信息。
<Valve classname="org.apache.catalina.ha.tcp.ReplicationValve"
filter=""/>
Valve用于在节点向客户端响应前进行检测或进行某些操作,ReplicationValve就是用于检测当前的响应是否涉及Session数据的更新,如果是则启动Session拷贝操作,filter用于过滤请求,如客户端对图片,css,js的请求就不会涉及Session,因此不需检测,默认状态下不进行过滤,监测所有的响应。
在生产环境中使用以下选项:
<Valve className=”org.apache.catalina.ha.tcp.ReplicationValve”
filter=”.*\.gif;.*\.js;.*\.jpg;.*\.htm;.*\.html;.*\.txt;”/>
即当对静态页面图片等访问时不进行session replication。
<Valve classname="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
设置此选项是,当一个节点crash时,访问跳到另一个节点,此时session ID 会将jvmRoute值和以前的session Id 绑定在一起想·
<ClusterListener classname="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener classname="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
3修改webapps/myweb/WEN-INF/web.xml
添加<distributable/> 标签
即只在<web-app> 和</web-app>之间添加
<distributable/>
4在weapps创建一个测试应用myweb(此次试验可以直接cp –rf examples myweb)
修改index.jsp 为以下内容:
Tomcat_a:
<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*" %>
<html><head><title>Cluster Test</title></head>
<body>
<%
//HttpSession session = request.getSession(true);
System.out.println(session.getCreationTime());
out.println("<br> SESSION ID:" + session.getId()+"<br>");
out.println("Session serviced by master"+"<br>");
out.println("Session created time is :"+session.getCreationTime()+"<br>");
%>
</body>
</html>
(访问时是会显示session ID ,server name,session 创建的时间,格式如下:)
=============================================================
=============================================================