回顾
前几天,刚刚搭建了apache httpd的静态网站,并为其开启的SSL。http://my.oschina.net/xpbug/blog/197454
今天在其基础上,我们将使用tomcat搭建集群,并把httpd改造成一个load banlencer的逆向代理。
应用的开发
首先,我需要开发一个web应用,来测试我的集群,于是,我创建了一个动态web项目,取名叫sessiontest. 在此项目中,只有两个jsp文件。
第一个select.jsp. 这个文件相当于一个购物车,将用户选中的内容提交,并展示用户选中的物品。
1<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 3<html> 4 <head> 5 <title>Your selections</title> 6 </head> 7 <body> 8 <% 9 String selections = (String)session.getAttribute("selections"); 10 selections=selections==null?"":selections; 11 %> 12 <form action="successful.jsp" method="post"> 13 <p>What do you prefer?</p> 14 <p><input type="checkbox" name="car" value="car" <% 15 if(selections.indexOf("car")>-1) out.print("checked=\"checked\""); %> />Car</p> 16 <p><input type="checkbox" name="bike" value="bike" <% 17 if(selections.indexOf("bike")>-1) out.print("checked=\"checked\""); %> />Bike</p> 18 <p><input type="checkbox" name="train" value="train" <% 19 if(selections.indexOf("train")>-1) out.print("checked=\"checked\""); %> />Train</p> 20 <p><input type="checkbox" name="plane" value="plane" <% 21 if(selections.indexOf("plane")>-1) out.print("checked=\"checked\""); %> />Plane</p> 22 <input type="submit" value="Submit" /> 23 </form> 24 </body> 25</html>
第二个文件是successful.jsp, 它将select.jsp提交的选项包存入session中。
1<%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4<html> 5<head> 6<title>Successful</title> 7</head> 8<body> 9<% 10 StringBuffer sb = new StringBuffer(); 11 if (null !=request.getParameter("car"))sb.append("car;"); 12 if (null !=request.getParameter("bike"))sb.append("bike;"); 13 if (null !=request.getParameter("train"))sb.append("train;"); 14 if (null !=request.getParameter("plane"))sb.append("plane;"); 15 16 session.setAttribute("selections", sb.toString()); 17%> 18Successful, please go back to check.<br> 19<a href="select.jsp">Back</a> 20</body> 21</html>
将项目导出为sessiontest.war,并部署到tomcat中的用户界面为:
http://localhost:8080/sessiontest/select.jsp

http://localhost:8080/sessiontest/successful.jsp

接下来,我会使用这个web应用来测试我的集群。
最简单的集群
如下图所示,最简单的集群并不是一个真正的集群,tomcat1和tomcat2只是运行了同一个应用,比如我的sessiontest.war, 它们两个之间并没有任何通信,共享。Apache只是根据访问量进行负载平衡。一旦其中一个tomcat关机,所有的request都将被转发到另一个tomcat上去。而之前工作在第一个tomcat上的用户会丢失信息,比如session,运行环境。

-
首先在本机上安装两个tomcat, 也就是生成2分tomcat的copy。下面将这两个tomcat分别以tomcat1和tomcat2命名。
-
维持tomcat1的port的配置,但需要向其server.xml中添加一个属性 jvmRoute="node1":
<Engine name="Catalina" defaultHost="localhost" jvmRoute="node1"> -
修改tomcat2的port的配置,并向其server.xml中添加一个属性 jvmRoute="node2":
1<Server port="8006" shutdown="SHUTDOWN"> 2<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/> 3<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" /> 4<Engine name="Catalina" defaultHost="localhost" jvmRoute="node2"> -
将之前的应用sessiontest.war分别部署到两个tomcat上。测试localhost:8080/sessiontest/select.jsp和localhost:8081/sessiontest/select.jsp。这样,集群的两个node就跑起来了。
-
配置apache httpd,开启负载平衡。基于上一篇文章配好的https://www.test0.com 的网站,我将把集群挂在这个网站下面,将下面的配置加入virtualhost中。不要忘记开启proxy_balancer module。
1<VirtualHost *:443> 2 ServerName www.test0.com 3 ProxyPass /sessiontest balancer://mycluster 4 <Proxy balancer://mycluster> 5 BalancerMember ajp://127.0.0.1:8009/sessiontest loadfactor=1 route=node1 6 BalancerMember ajp://127.0.0.1:8010/sessiontest loadfactor=1 route=node2 7 ProxySet stickysession=JSESSIONID 8 ProxySet lbmethod=byrequests 9 </Proxy> 10</VirtualHost>stickysession的意义在于,一个用户可以根据其cookie中的jsessionid固定的访问一个tomcat,这样不会在两个tomcat之间跳来跳去而丢失运行信息和session。
开启集群节点之间的通信
接下来,我将开启tomcat1和tomcat2之间的通信,这样它们可以共享session和一些内存信息。一个正在tomcat1上访问的用户,因为tomcat1的关机而转移到tomcat2上,也不会丢失session信息了。

-
修改原web应用,在sessiontest的web.xml中添加一段。表明此应用需要在cluster之间进行同步。然后重新部署此应用。
<distributable/> -
分别修改tomcat1和tomcat2的server.xml,加入相同的一段代码。 Tomcat使用组播技术,使得各个node之间建立连接,唯一需要声明的是你的Recervier端口,在4000-4999之间任选一个。
1 <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" 2 channelSendOptions="8"> 3 4 <Manager className="org.apache.catalina.ha.session.DeltaManager" 5 expireSessionsOnShutdown="false" 6 notifyListenersOnReplication="true"/> 7 8 <Channel className="org.apache.catalina.tribes.group.GroupChannel"> 9 <Membership className="org.apache.catalina.tribes.membership.McastService" 10 address="228.0.0.4" 11 port="45564" 12 frequency="500" 13 dropTime="3000"/> 14 <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" 15 address="auto" 16 port="4444" 17 autoBind="100" 18 selectorTimeout="5000" 19 maxThreads="6"/> 20 21 <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> 22 <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> 23 </Sender> 24 <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> 25 <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/> 26 </Channel> 27 28 <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" 29 filter=""/> 30 <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> 31 32 <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" 33 tempDir="/tmp/war-temp/" 34 deployDir="/tmp/war-deploy/" 35 watchDir="/tmp/war-listen/" 36 watchEnabled="false"/> 37 38 <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> 39 </Cluster> -
分别启动tomcat1和tomcat2.请等一个启动完再启动另一个。集群创建完毕。
-
为了测验集群,我将负载平衡的stickysession关掉。请注释掉配置中的ProxySet stickysession=JSESSIONID. 重启apache. 这时候用户的request会在tomcat1和tomcat2之间跳来跳去。
-
访问https://www.test0.com/sessiontest/select.jsp 你会发现即使request在两个tomcat之间跳来跳去,但购物车里的信息永远不会丢失。
待续
配置ldap认证和授权,并开发一个登录页面。http://my.oschina.net/xpbug/blog/198765