集群的負載均衡器由開源的 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 的請求,還是進行負載均衡輪換的