现在的位置: 首页 > 综合 > 正文

Tomcat负载均衡

2017年08月21日 ⁄ 综合 ⁄ 共 10941字 ⁄ 字号 评论关闭

1.1 术语定义

服务软体是b/s或c/s结构的s部分,是为b或c提供服务的服务性软件系统。 

服务硬体指提供计算服务的硬件、比如pc机、pc服务器。 

服务实体通指服务软体和服务硬体。 

客户端指接受服务实体服务的软件或硬件。 

1.2 两大关键特性

集群是一组协同工作的服务实体,用以提供比单一服务实体更具扩展性与可用性的服务平台。在客户端看来,一个集群就象是一个服务实体,但事实上集群由一组服务实体组成。与单一服务实体相比较,集群提供了以下两个关键特性: 

可扩展性--集群的性能不限于单一的服务实体,新的服务实体可以动态地加入到集群,从而增强集群的性能。 
高可用性--集群通过服务实体冗余使客户端免于轻易遇到out of service的警告。在集群中,同样的服务可以由多个服务实体提供。如果一个服务实体失败了,另一个服务实体会接管失败的服务实体。集群提供的从一个出错的服务实体恢复到另一个服务实体的功能增强了应用的可用性。 
1.3 两大能力

为了具有可扩展性和高可用性特点,集群的必须具备以下两大能力: 

负载均衡--负载均衡能把任务比较均衡地分布到集群环境下的计算和网络资源。 
错误恢复--由于某种原因,执行某个任务的资源出现故障,另一服务实体中执行同一任务的资源接着完成任务。这种由于一个实体中的资源不能工作,另一个实体中的资源透明的继续完成任务的过程叫错误恢复。 
负载均衡和错误恢复都要求各服务实体中有执行同一任务的资源存在,而且对于同一任务的各个资源来说,执行任务所需的信息视图(信息上下文)必须是一样的。 

1.4 两大技术

实现集群务必要有以下两大技术: 

集群地址--集群由多个服务实体组成,集群客户端通过访问集群的集群地址获取集群内部各服务实体的功能。具有单一集群地址(也叫单一影像)是集群的一个基本特征。维护集群地址的设置被称为负载均衡器。负载均衡器内部负责管理各个服务实体的加入和退出,外部负责集群地址向内部服务实体地址的转换。有的负载均衡器实现真正的负载均衡算法,有的只支持任务的转换。只实现任务转换的负载均衡器适用于支持ACTIVE-STANDBY的集群环境,在那里,集群中只有一个服务实体工作,当正在工作的服务实体发生故障时,负载均衡器把后来的任务转向另外一个服务实体。 
内部通信--为了能协同工作、实现负载均衡和错误恢复,集群各实体间必须时常通信,比如负载均衡器对服务实体心跳测试信息、服务实体间任务执行上下文信息的通信。 
具有同一个集群地址使得客户端能访问集群提供的计算服务,一个集群地址下隐藏了各个服务实体的内部地址,使得客户要求的计算服务能在各个服务实体之间分布。内部通信是集群能正常运转的基础,它使得集群具有均衡负载和错误恢复的能力。 

()环境说明
(1)服务器有4台,一台安装apache,三台安装tomcat
(2)apache2.0.55、tomcat5.5.15、jk2.0.4、jdk1.5.6或jdk1.4.2
(3)ip配置,一台安装apache的ip为192.168.0.88,三台安装tomcat的服务器ip分别为192.168.0.1/2/4

()安装过程
(1)在三台要安装tomcat的服务器上先安装jdk
(2)配置jdk的安装路径,在环境变量path中加入jdk的bin路径,新建环境变量JAVA_HOME指向jdk的安装路径
(3)在三台要安装tomcat的服务器上分别安装tomcat,调试三个tomcat到能够正常启动
(4)tomcat的默认WEB服务端口是8080,默认的模式是单独服务,我的三个tomcat的WEB服务端口修改为7080/8888/9999
修改位置为tomcat的安装目录下的conf/server.xml
修改前的配置为

     <Connector port="8080" maxHttpHeaderSize="8192"
                maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
                enableLookups="false" redirectPort="8443" acceptCount="100"
                connectionTimeout="20000" disableUploadTimeout="true" />

修改后的配置为

     <Connector port="7080" maxHttpHeaderSize="8192"
                maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
                enableLookups="false" redirectPort="8443" acceptCount="100"
                connectionTimeout="20000" disableUploadTimeout="true" />

依次修改每个tomcat的监听端口(7080/8888/9999)

(5)分别测试每个tomcat的启动是否正常

http://192.168.0.1:7080

http://192.168.0.2:8888
http://192.168.0.4:9999/

()负载均衡配置过程
(1)在那台要安装apache的服务器上安装apache2.0.55,我的安装路径为默认C:\Program Files\Apache Group\Apache2
(2)安装后测试apache能否正常启动,调试到能够正常启动http://192.168.0.88
(3)下载jk2.0.4后解压缩文件
(4)将解压缩后的目录中的modules目录中的mod_jk2.so文件复制到apache的安装目录下的modules目录中,我的为C:\Program Files\Apache Group\Apache2\modules
(5)修改apache的安装目录中的conf目录的配置文件httpd.conf,在文件中加LoadModule模块配置信息的最后加上一句LoadModule jk2_module modules/mod_jk2.so
(6)分别修改三个tomcat的配置文件conf/server.xml,修改内容如下
修改前

     <!-- An Engine represents the entry point (within Catalina) that processes
          every request.   The Engine implementation for Tomcat stand alone
          analyzes the HTTP headers included with the request, and passes them
          on to the appropriate Host (virtual host). -->

     <!-- You should set jvmRoute to support load-balancing via AJP ie :
     <Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">         
     --> 
         
     <!-- Define the top level container in our container hierarchy -->
     <Engine name="Catalina" defaultHost="localhost">

修改后

     <!-- An Engine represents the entry point (within Catalina) that processes
          every request.   The Engine implementation for Tomcat stand alone
          analyzes the HTTP headers included with the request, and passes them
          on to the appropriate Host (virtual host). -->

     <!-- You should set jvmRoute to support load-balancing via AJP ie :-->
     <Engine name="Standalone" defaultHost="localhost" jvmRoute="tomcat1">         
     
         
     <!-- Define the top level container in our container hierarchy 
     <Engine name="Catalina" defaultHost="localhost">
     -->

将其中的jvmRoute="jvm1"分别修改为jvmRoute="tomcat1"和jvmRoute="tomcat2"和jvmRoute="tomcat3"

(7)然后重启三个tomcat,调试能够正常启动。
(8)在apache的安装目录中的conf目录下创建文件workers2.propertie,写入文件内容如下

# fine the communication channel 
[channel.socket:192.168.0.1:8009] 
info=Ajp13 forwarding over socket

#配置第一个服务器 
tomcatId=tomcat1 #要和tomcat的配置文件server.xml中的jvmRoute="tomcat1"名称一致
debug=0 
lb_factor=1 #负载平衡因子,数字越大请求被分配的几率越高

# Define the communication channel 
[channel.socket:192.168.0.2:8009] 
info=Ajp13 forwarding over socket
tomcatId=tomcat2 
debug=0 
lb_factor=1 

# Define the communication channel 
[channel.socket:192.168.0.4:8009] 
info=Ajp13 forwarding over socket
tomcatId=tomcat3 
debug=0 
lb_factor=1 

[status:] 
info=Status worker, displays runtime information.  

[uri:/jkstatus.jsp] 
info=Display status information and checks the config file for changes. 
group=status: 

[uri:/*] 
info=Map the whole webapp 
debug=0

(9)在三个tomcat的安装目录中的webapps建立相同的应用,我和应用目录名为TomcatDemo,在三个应用目录中建立相同 WEB-INF目录和页面index.jsp,index.jsp的页面内容如下

<%@ page contentType="text/html; charset=GBK" %>
<%@ 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.print("<b>Session 列表</b>");

   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=20 name="dataName">
      <br>
     :<input type=text size=20 name="dataValue">
      <br>
     <input type=submit>
    </form>
</body>
</html>

(10)重启apache服务器和三个tomcat服务器,到此负载 均衡已配置完成。测试负载均衡先测试apache,访问http://192.168.0.88/jkstatus.jsp
能否正常访问,并查询其中的内容,有三个tomcat的相关配置信息和负载说明,访问http://192.168.0.88/TomcatDemo/index.jsp看能够运行,
能运行,则已建立负载均衡。

()tomcat集群配置
(1)负载均衡配置的条件下配置tomcat集群
(2)分别修改三个tomcat的配置文件conf/server.xml,修改内容如下
修改前

        <!-- 
         <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
                  managerClassName="org.apache.catalina.cluster.session.DeltaManager"
                  expireSessionsOnShutdown="false"
                  useDirtyFlag="true"
                  notifyListenersOnReplication="true">

             <Membership 
                 className="org.apache.catalina.cluster.mcast.McastService"
                 mcastAddr="228.0.0.4"
                 mcastPort="45564"
                 mcastFrequency="500"
                 mcastDropTime="3000"/>

             <Receiver 
                 className="org.apache.catalina.cluster.tcp.ReplicationListener"
                 tcpListenAddress="auto"
                 tcpListenPort="4001"
                 tcpSelectorTimeout="100"
                 tcpThreadCount="6"/>

             <Sender
                 className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
                 replicationMode="pooled"
                 ackTimeout="5000"/>

             <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
                    filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
                   
             <Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
                       tempDir="/tmp/war-temp/"
                       deployDir="/tmp/war-deploy/"
                       watchDir="/tmp/war-listen/"
                       watchEnabled="false"/>
                      
             <ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener"/>
         </Cluster>
         -->   

修改后

        <!-- modify by whh -->
         <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
                  managerClassName="org.apache.catalina.cluster.session.DeltaManager"
                  expireSessionsOnShutdown="false"
                  useDirtyFlag="true"
                  notifyListenersOnReplication="true">

             <Membership 
                 className="org.apache.catalina.cluster.mcast.McastService"
                 mcastAddr="228.0.0.4"
                 mcastPort="45564"
                 mcastFrequency="500"
                 mcastDropTime="3000"/>

             <Receiver 
                 className="org.apache.catalina.cluster.tcp.ReplicationListener"
                 tcpListenAddress="auto"
                 tcpListenPort="4001"
                 tcpSelectorTimeout="100"
                 tcpThreadCount="6"/>

             <Sender
                 className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
                 replicationMode="pooled"
                 ackTimeout="5000"/>

             <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
                    filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
                   
             <Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
                       tempDir="/tmp/war-temp/"
                       deployDir="/tmp/war-deploy/"
                       watchDir="/tmp/war-listen/"
                       watchEnabled="false"/>
                      
             <ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener"/>
         </Cluster>
        <!-- modify by whh -->

将集群配置选项的注释放开即可,如上。

(3)在Conf目录下建立jk2.properties文件,写入下面一行,其中端口为相应的Tomcat对应的AJP端口。
channelSocket.port=8009
(4)重启三个tomcat。到此tomcat的集群已配置完成。

()应用配置
对于要进行负载和集群的的tomcat目录下的webapps中的应用中的WEB-INF中的web.xml文件要添加如下一句配置
<distributable/>
配置前

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
   <display-name>TomcatDemo</display-name>
</web-app>

配置后

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
   <display-name>TomcatDemo</display-name>
    <distributable/>
</web-app>

 

补充说明:

   由于tomcatHTTP处理部分都由Java所写(5.5.12版本以后出现了native库,用以提高其I/OSSL的性能[1]),在高并发的情况下负载较高。而apache对于静态文件的处理能力比tomcat强,所以tomcat开发组开发了与apache结合使用的mod_jk模块。该协议由apache作请求代理,将HTTP协议的请求转化为AJP协议包,并传给后端的tomcatmod_jkapache现在普遍使用AJP1.3协议[2]它是一个二进制格式的协议,比字符格式的HTTP协议解析速度要快。

除了性能的提升,mod_jk另外的一个作用可以实现apachetomcat一对多的对应,

使后端tomcat负载均衡。mod_jk也提供apachetomcat链接情况的监控。

mod_jk模块的典型工作流程是这样的:一个HTTP请求过来,mod_jk模块根据其URI选择合适的worker来进行处理。如果是lb_worker(负载均衡的worker),就再根据各种条件选择后台合适的ajp_worker(处理AJP协议的worker)。ajp_workerHTTP协议的包,组装成AJP协议格式的包,然后选取一条空闲的链接,发送给后台的tomcat服务器。等到后台将数据发送过来时,接收并解析AJP协议,重新组装成HTTP协议,然后把结果发送给客户端。

更多内容参考:http://zhumeng8337797.blog.163.com/blog/static/100768914201182301341191/ 

抱歉!评论已关闭.