tomcat集羣



概述

Tomcat是J2EE開發當中使用最多的應用服務器,本章就來介紹一下使用Apache2應用服務器加上Tomcat6一起實現應用集羣與負載均衡。這裏我們使用的Tomcat爲7.0.26;Apache版本爲2.2,如果您機器上沒有,請到www.apache.org上下載,Tomcat7.0.26有兩個,我們這裏稱之爲tomcat1和tomcat2,下文中如果沒特指tomcat1還是tomcat2,那麼tomcat1和tomcat2都要進行操作,apache2.2只有一個。所以都準備好之後,接下來我們就來看看如何進行配置。

配置Tomcat集羣

打開tomcat下conf/server.xml文件,找到<Engine name="Catalina" defaultHost="localhost">,增加jvmRoute屬性,以支持AJP負載均衡。
tomcat1改爲<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
tomcat2改爲<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm2">
因爲我們的兩個Tomcat在是一臺機器上運行,所以我們有必要修改其中一個Tomcat採用端口,以保證兩個同時運行時不會產生衝突(當然,如果兩個tomcat不在一臺機器上運行,那麼這個步驟就可以省略)。我們這裏修改的是tomcat2,打開tomcat2下conf/server.xml文件,修改如下:


<Server port="8005"shutdown="SHUTDOWN">
修改爲
<Server port="9005"shutdown="SHUTDOWN">

<Connector port="8080"protocol="HTTP/1.1" connectionTimeout="20000"redirectPort="8443"/>
修改爲
<Connector port="9080"protocol="HTTP/1.1"    connectionTimeout="20000" redirectPort="9443"/>。

<Connector port="8009"protocol="AJP/1.3"redirectPort="8443"/>
修改爲
<Connector port="9009"protocol="AJP/1.3"redirectPort="9443"/>

端口修改完成,我們需要來配置一個集羣環境中的session複製,打開tomcat下conf/server.xml文件,在<Engine></Engine>節點內加入下面代碼:


  <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="6">
 
          <Manager className="org.apache.catalina.ha.session.BackupManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"
                   mapSendOptions="6"/>
          <!--
          <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="5000"
                      selectorTimeout="100"
                      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"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
          </Channel>
 
          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/>
 
          <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.ClusterSessionListener"/>
</Cluster>

其中同臺機器上的TCP端口不能有衝突,所以在上面的配置當中,對於Tomcat2需要修改節點Culster->Channel->Reciver的port屬性,默認爲5000,tomcat識別的範圍爲4000-4100,這裏把tomcat2的這個port屬性修改爲4001。

這些配置都完成後,接下來我們就可以在這兩個Tomcat當中添加一個簡單應用來實際測試一下集羣效果。

測試Tomcat集羣

在tomcat/webapps下,新建一文件夾爲test,test文件夾下創建WEB-INF目錄,創建標準web.xml文件,文件中一定要加入<distributable/>標籤以支持分佈式應用。

web.xml文件內容如下:


<?xml version="1.0"encoding="ISO-8859-1"?> <web-app xmlns="<a href="http://java.sun.com/xml/ns/javaee" "="">http://java.sun.com/xml/ns/javaee"  xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance" "="">http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee                       <a href="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" "="">http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   version="3.0"   metadata-complete="true">
    <display-name>Welcome to Test Tomcat7 Cluster</display-name>  
    <description>Welcome to Test Tomcat7 Cluster</description>
    <distributable/>
</web-app>

在test文件夾下建立test.jsp文件,文件內容如下:


<%@ page contentType="text/html; charset=UTF-8"%>
<%@ page import="java.util.*"%>
<html><head><title>Cluster App Test</title></head>
<body>
Server Info:
<%
out.println(request.getLocalAddr() +" : " + request.getLocalPort()+"<br>");%>
<%
  out.println("<br> ID "+ session.getId()+"<br>");
  // 如果有新的 Session 屬性設置
  String dataName = request.getParameter("dataName");
  if(dataName != null&& dataName.length() > 0) {
     String dataValue = request.getParameter("dataValue");
     session.setAttribute(dataName, dataValue);
  }
  out.println("<b>Session 列表</b><br>");
  System.out.println("============================");
  Enumeration e = session.getAttributeNames();
  while(e.hasMoreElements()) {
     String name = (String)e.nextElement();
     String value = session.getAttribute(name).toString();
     out.println( name +" = " + value+"<br>");
         System.out.println( name +" = " + value);
   }
%>
  <form action="index.jsp"method="POST">
    名稱:<input type=text size=20name="dataName">
     <br>
    值:<input type=text size=20name="dataValue">
     <br>
    <input type=submit>
   </form>
</body>
</html>

這個簡單的JSP可以把提交的值保存到Session當中,同時顯示出來。

啓動tomcat1,等tomcat1啓動完成後,啓動tomcat2。先訪問tomcat1對應的test工程http://localhost:8080/test.jsp頁面,輸入值並提交,然後把鏈接轉到tomcat2對應的test工程http://localhost:9080/test.jsp頁面,看看session內容是否相同,如果相同則說明session複製成功,也就是羣集成功。
接下來我們在這兩個Tomcat前端添加一個Apache Http Server,所有訪問請求通過這個Http Server進行轉發,根據tomcat1或2的忙碌情況決定轉發給tomcat1或者是tomcat2去處理用戶請求。

Apache負載均衡

打開並修改apache安裝目錄下conf/httpd.conf文件,找到下面這些內容:


#LoadModule negotiation_module modules/mod_negotiation.so
#LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
#LoadModule proxy_http_module modules/mod_proxy_http.so

去掉這些#,也就是啓用這些被註釋掉的功能,並且在文件的未尾處添加下面這些內容:


ProxyPass / balancer://cluster/ stickysession=JSESSIONID
 
ProxyPassReverse / balancer://cluster/
<proxy balancer://cluster>
          BalancerMember ajp://127.0.0.1:8009 loadfactor=1 route=jvm1
          BalancerMember ajp://127.0.0.1:9009 loadfactor=1 route=jvm2
</proxy>

重新啓動apache,以apache作爲負載均衡器的tomcat集羣建立完成,所有請求都可以通過請求apache http server,通過這個http server轉發到具體的tomcat服務器。

Tomcat集羣和Session複製詳解

Cluster


<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">

Tomcat集羣的主元素,在Cluster元素裏面配置了集羣的詳細信息。目前Tomcat僅提供了org.apache.catalina.ha.tcp.SimpleTcpCluste作爲唯一的實現類。下面是Cluster詳細屬性:

屬性

描述

className

Cluste的實現類,當前org.apache.catalina.ha.tcp.SimpleTcpCluste作爲唯一的實現類。

channelSendOptions

Session發送方式,默認值爲:8。當消息通過SimpleTcpCluster發送時,用來決定如何發送信息。


int options= Channel.SEND_OPTIONS_ASYNCHRONOUS |
Channel.SEND_OPTIONS_SYNCHRONIZED_ACK | Channel.SEND_OPTIONS_USE_ACK;

Channel.SEND_OPTIONS_SYNCHRONIZED_ACK =0x0004
Channel.SEND_OPTIONS_ASYNCHRONOUS =0x0008
Channel.SEND_OPTIONS_USE_ACK =0x0002

如果使用異步(ASYNCHRONOUS)加應答(USE_ACK)方式來發送消息,那麼值應該是10(8+2)或者0x000B。

Manager


<Manager className="org.apache.catalina.ha.session.DeltaManager"
                  expireSessionsOnShutdown="false"
                  notifyListenersOnReplication="true"/>

Manager用來在Tomcat節點之前複製Session,當前有兩個實現類,分別爲:org.apache.catalina.ha.session.DeltaManagert和org.apache.catalina.ha.session.BackupManager。DeltaManager調用SimpleTcpCluster.send方法來發送信息,複製併發送Session到集羣下所有的節點,不管這個節點有沒有部署當前程序。
BackupManager通過自己直接調用channel來發送信息,複製併發送Session到集羣下部署了當前程序的節點。
DaltaManager的優點是經過實踐確認和證明的,非常可靠,而BackupManager在可靠性上不如DaltaManager。DaltaManager缺點是要求集羣節點必須部署了同樣的程序,節點必須是同種類的。
下面是Manager的屬性描述:

屬性

描述

className

Manager的實現類。

notifyListenersOnReplication

如果設置爲true,當session屬性被複制和移動的時候,session listener被通知

expireSessionsOnShutdown

當一個web程序被結束時,tomcat分發銷燬命令到每個Session,並通知所有session listener執行。當集羣下某個節點被停止時,如果想銷燬所有節點下的的Session,設置爲true,默認爲false 。

BackupManager屬性:

屬性

描述

mapSendOptions

BackupManager通過一個可複製的map來實現session接受和發送,通過設置mapSendOptions來設定這個map以何種方式來發送信息,默認爲:6(asynchronous)。

Channel


<Channel className="org.apache.catalina.tribes.group.GroupChannel">

Channel是Apache Tribes的主組件,channel管理一組子組件,並和它們一起組成了tomcat實例間的通訊框架。在tomcat集羣中,DeltaManager通過SimpleTcpCluster調用channel來實現信息傳遞,而BackupManager自己調用channel以及子組件這些組件來實現信息傳遞。ReplicatedContext也會調用channel傳遞context屬性。
下面是channel子組件
*MemberShip
MemberShip組件自動檢索發現集羣裏的新節點或已經停止工作的節點,併發出相應的通知。默認使用組播(Multicast)實現。
*Sender
Sender組件管理從一個節點發送到另外一個節點的出站連接和數據信息,允許信息並行發送。默認使用TCP Client Sockets。
*Receiver
Receiver組件負責監聽接收其他節點傳送過來的數據。默認使用non-blocking TCP Server sockets。
*Interceptor
Channel通過Interceptor堆棧進行消息傳遞,在這裏可以自定義消息的發送和接收方式,甚至MemberShip的處理方式。

Value


<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"filter=" .*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.css;.*\.txt; "/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

Cluster下的Value同其他tomcat value一樣,value在調用Http Request 鏈中起着攔截器的作用,用來決定什麼情況下數據需要被複制。
org.apache.catalina.ha.tcp.ReplicationValve,ReplicationValue在Http Request結尾判斷當前數據是否需要被複制。它的具體屬性描述如下表所示:

屬性

描述

className

org.apache.catalina.ha.tcp.ReplicationValve,ReplicationValue

filter

Filter內容爲url或者文件結尾,當訪問鏈接配置filter時,不論實際session有沒有改變,集羣會認爲session沒有任何變化,從而不會複製和發送改變的session屬性。Filter寫法如下:filter=" .\.gif;.\.js;.\.jpg;.\.png;.\.css;.\.txt; "。filter使用正則表達式,每個url或者後綴以逗號分開。

Deployer

使集羣支持farmed deployment。這個功能還很弱,在變化和更改中。

ClusterListener


<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/></Cluster>

Clusterlistener用來追蹤信息發送和接收。JvmRouteSessionIDBinderListener用來監聽session id的變化。這個listener僅當使用mod_jk並且屬性有jvmRoute時才起作用。當session id 改變後,JvmRouteBinderValve將廣播這個信息並被此listener捕獲。ClusterSessionListener用來監聽集羣組件接收信息,當使用DeltaManager的時候,信息被集羣接收,並通過ClusterSessionListener傳遞給Session Manager。

Apache負載均衡詳解


ProxyPass / balancer://cluster/ stickysession=JSESSIONID
 
ProxyPassReverse / balancer://cluster/
<proxy balancer://cluster>
          BalancerMember ajp://127.0.0.1:8009 loadfactor=1 route=jvm1
          BalancerMember ajp://127.0.0.1:9009 loadfactor=1 route=jvm2
</proxy>

通過Apache自帶的mod_proxy某塊來使用代理技術連接tomcat, ajp_proxy需要tomcat提供ajp服務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章