集群的负载均衡器由开源的 Apache 服务器担任,集群中的 Web 服务器由两个 Tomcat 服务器分别担任,后台的数据库服务器由一个 MySQL 服务器担任。
提示:本教程中介绍的是
Web 集群,因此数据库服务器只有一个,并没有搭建集群。在需要的情况下,多台数据库服务器也可以组成集群以提高服务能力与可靠性。
二、安装JDK
三、安装TOMCAT
下载tomcat,可以通过下面的命令下载:
#wget
http://apache.mirror.phpchina.com/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.tar.gz
解压启动测试:
#tar -zxvf apache-tomcat-6.0.18.tar.gz
#./apache-tomcat-6.0.18/bin/startup.sh
在浏览器中输入:http://localhost:8080,看是否启动正常,若正常进行第三步。
下面通过一个简单的"
Test.jsp "程序进一步验证 Tomcat
是否安装成功,新建名称为"
Test.jsp "的 Jsp 源文件并在其中输入如下代码。
<%@ page
contentType="text/html;charset=GBK"%>
<html>
<head>
<title> Tomcat_ _测试 </title>
</head>
<body>
<font color = "red" size = "20" >
<% out.print( "_ _恭喜您,成功的安装并启动了 Tomcat_ _!!! " ); %>
</font>
</body>
</html>
重启(命令如下),然后输入:http://localhost:8080/Test.jsp 看是否正常。
#./apache-tomcat-6.0.18/bin/shutdown.sh
#./apache-tomcat-6.0.18/bin/startup.sh
四:TOMCAT集群的搭建
安装两个或以上tomcat
#./apache-tomcat-6.0.18/bin/shutdown.sh
#mv apache-tomcat-6.0.18 /usr/local/TC6_A
#cd /usr/local
#cp -a TC6_A TC6_B
提 示:进行上述步骤操作的原因是,本案例中集群的各个 Tomcat 服务器实例运行在同一个物理服务器上,因此集群中有几个 Tomcat 实例一般就需要几个 Tomcat 的安装。另外,由于集群中的各个 Tomcat 实例位于同一个物理服务器上的一个操作系统下,因此各个实例占用的各种网络端口不能相同,否则集群中的多个 Tomcat 实例不能同时正常启动,下面的步骤将介绍如何修改 Tomcat 实例需要使用的各个网络端口。
修改 Tomcat 实例需要使用的各个网络端口
找到 server.xml 配置文件中的" Server "配置项目,并进行修改。
<Server port="8005"
shutdown="SHUTDOWN">
<Server port="10005" shutdown="SHUTDOWN">
<Server port="20005" shutdown="SHUTDOWN">
说明:第一行为两个
Tomcat 修改前的情况,第二行为
TC6_A Tomcat 修改后的情况,第三行为
TC6_B Tomcat 修改后的情况。
找到 server.xml 配置文件中的相应" Connector "配置项目,并进行修改。
修改前内容如下:
<!-- Define an AJP 1.3 Connector on port
8009 -->
<Connector port = "8009" protocol = "AJP/1.3"
redirectPort = "8443" />
TC6_A 中修改后内容如下:
<!-- Define an AJP 1.3 Connector on port
8009 -->
<Connector port = " 10009 " protocol = "AJP/1.3" redirectPort
= " 10043 " />
TC6_B 中修改后内容如下:
<!-- Define an AJP 1.3 Connector on port
8009 -->
<Connector port = " 20009 " protocol = "AJP/1.3"
redirectPort = " 20043 " />
提示:此步骤目的是修改
AJP Connector 端口。
找到 server.xml 配置文件中的另一个相应" Connector "配置项目,并进行修改。
修改前内容如下:
<Connector port = "8080"
protocol = "HTTP/1.1" connectionTimeout = "20000"
redirectPort = "8443" />
TC6_A 中修改后内容如下:
<Connector port = "10001"
protocol = "HTTP/1.1" connectionTimeout = "20000"
redirectPort = "10043" />
TC6_B 中修改后内容如下:
<Connector port = "20001"
protocol = "HTTP/1.1" connectionTimeout = "20000"
redirectPort = "20043" />
提示:此步骤目的是修改
HTTP Connector 端口,其中的"
10001 "与" 20001
"是未来通过浏览器访问集群中各个 Tomcat 实例的 HTTP 端口。
通过修改 Engine 配置选项,配置集群中每个 Tomcat 实例的名称。
修改前内容如下:
<!-- You should set jvmRoute to support
load-balancing via AJP ie :
<Engine name = "Standalone" defaultHost = "localhost"
jvmRoute = "jvm1">
<Engine name = "Catalina" defaultHost = "localhost">
-->
TC6_A 中修改后内容如下:
<Engine name = "Standalone"
defaultHost = "localhost" jvmRoute = " Tomcat1">
TC6_B 中修改后内容如下:
<Engine name = "Standalone"
defaultHost = "localhost" jvmRoute = " Tomcat2">
提示:请读者注意在修改过程中要注释掉原来 name 为 Catalina 的 Engine 配置项目,将 name 为 Standalone 的 Engine 配置项目的注释去掉并修改 jvmRoute 属性。
修改配置文件中的
Cluster 配置项目,对集群的各项参数进行设置。
修改前内容如下:
<Cluster
className="org.apache.catalina.ha.tcp.SimpleTcpCluster" />
TC6_A 中修改后内容如下:
<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>
TC6_B 中修改后内容如下:
<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>
提示:上述配置内容主要是对集群中各个 Tomcat 实例间进行通信的方式、端口以及 Session 共享算法的设置。本教程由于篇幅所限,不能一一详细介绍,有兴趣的读者可以参看 Tomcat 的官方文档,其中有非常详细的说明。
3、测试搭建,分别启动两个tomcat,看是否正常,若正常进行第四步。
http://localhost:10001
http://localhost:20001
4、简单的 JSP 来进一步测试对"
TC6_A "和" TC6_B
"的设置是否成功,分别建立两个文件:Hello.jsp。
<%@ page
contentType="text/html;charset=GBK"%>
<html>
<head>
<title>Tomcat 测试 </title>
</head>
<body>
<font color="red" size="20">
<!— 使用 out 内建对象打印一条消息到输出页面 -->
<% out.print( "Tomcat 集群测试 A !!! " );
%>
</font>
</body>
</html>
TC6_B的改一行输出:
<% out.print( "Tomcat 集群测试 B !!! " );
%>
如果能顺利地在浏览器中见到上述两个页面,则说明集群中的两个 Tomcat 实例工作完全正常。下面就可以为集群安装、设置 Apache 负载均衡器了。
五、Apache负载均衡器的安装与配置
下载安装
# wget
http://www.apache.org/dist/httpd/httpd-2.2.9.tar.gz
# tar -zxvf httpd-2.2.9.tar.gz
# cd httpd-2.2.9
# ./configure --prefix=/usr/local/httpd --enable-mods-shared='proxy proxy_ajp
proxy_balancer'
# make
# make install
配置Apache 为 Tomcat 集群的负载均衡器
ProxyRequests Off
ProxyPass / balancer://myCluster/
<Proxy balancer://myCluster/>
BalancerMember ajp://localhost:10009 route=Tomcat1
BalancerMember ajp://localhost:20009 route=Tomcat2
</Proxy>
说 明:其中" myCluster "是集群的名称," ajp://localhost:10009 route=Tomcat1 " 对应 Tomcat 集群中的 TC6_A 实例," ajp://localhost:20009
route=Tomcat2 " 对应 Tomcat 集群中的 TC6_B 实例。经过上述配置后, Apache 就可以成为前面搭建的 Tomcat 集群的负载均衡器了。
六、感受成果
重启apache httpd后,访问:http://localhost/Hello.jsp。
由 于 Apache 作为 Tomcat 集群的负载均衡器,使用的是轮换算法,其均匀地将请求发送到集群中的各个 Tomcat 实例。因此,从1的测试中可以看出,是轮换访问两个不同 Tomcat 实例中的 Hello.jsp 页面的。当然,看到轮换的情况也就说明 Apache 负载均衡器正常工作了。
七、补充重要细节
1、在应用时候,工程的web.xml里面要加上这么一个属性,实现Session共享:
……
<distributable/>
</web-app>
文件中的“ <distributable/> ”项,是由于本案例将部署到集群中的多个服务器上。如果 在配置文件中没
有此项,则应用在集群中不能实现分布式 Session 共享,也就是说当机后用户状态数据(存放在 Session 中的)无法无缝迁移到 Tomcat 集群中的其他服务器上。此项非常重要,请读者多加留心。
然后在依次启动TC6_A,TC6_B,你会在TC6_A的日志里面看到他们的通信日志,不然就是没有成功。
2、Tomcat6 集群要求负载均衡器工作在“ sticky session ”模式下,否则集群可能工作不正常。
对“ ProxyPass ”项目进行如下修改。
修改前
ProxyPass / balancer://myCluster/
修改后
ProxyPass / balancer://myCluster/
lbmethod=byrequests stickysession=JSESSIONID nofailover=Off
提示: 修改后添加的“ stickysession=JSESSIONID ”项就是让 Apache 负载均衡器工作在“ sticky session ”模式下。所谓“ sticky session ”模式就是对于使用到同一个 Session 的请求绑定到集群中的特定服务器上,而不是轮换访问各个服务器,这样 Session 就不会工作不正常了。当然,对于使用不同 Session 的请求,还是进行负载均衡轮换的