您的位置:首页 > 运维架构 > Tomcat

linux下tomcat集群的负载均衡

2014-12-18 14:55 155 查看
集群:

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

· 可扩展性--集群的性能不限于单一的服务实体,新的服 务实体可以动态地加入到集群,从而增强集群的性能。

· 高可用性--集群通过服务实体冗余使客户端免于轻易遇到out of service的警告。在集群中,同样的服务可以由多个服务实体提供。如果一个服务实体失败了,另一个服务实体会接管失败的服务实体。集群提供的从一个出 错的服务实体恢复到另一个服务实体的功能增强了应用的可用性。

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

· 负 载均衡--负载均衡能把任务比较均衡地分布到集群环境下的计算和网络资源。

· 错误恢复--由于某种原因,执行某个任务的资源出现故障,另一服 务实体中执行同一任务的资源接着完成任务。这种由于一个实体中的资源不能工作,另一个实体中的资源透明的继续完成任务的过程叫错误恢复。

负载均衡 和错误恢复都要求各服务实体中有执行同一任务的资源存在,而且对于同一任务的各个资源来说,执行任务所需的信息视图(信息上下文)必须是一样的。

集 群分类:

Linux集群主要分成三大类( 高可用集群, 负载均衡集群,科学计算集群)

高可用集群( High Availability Cluster)

常见的就是2个节点做 成的HA集群,有很多通俗的不科学的名称,比如"双机热备", "双机互备", "双机".

高可用集群解决的是保障用户的应用程序持续对外提供服 务的能力。 (请注意高可用集群既不是用来保护业务数据的,保护的是用户的业务程序对外不间断提供服务,把因软件/硬件/人为造成的故障对业务的影响降低到最小程 度)。

负载均衡集群(Load Balance Cluster)

负载均衡系统:集群中所有的节点都处于活动状态,它们分摊系统的工作负载。一般Web服 务器集群、数据库集群
和应用服务器集群都属于这种类型。

负载均衡集群一般用于相应网络请求的网页服务器,数据库服务器。这种集群可以在接到请求时,检查接受请求较少,不繁忙的服务器,并把请求转到这些服务器 上。从检查其他服务器状态这一点上 看,负载均衡和容错集群很接近,不同之处是数量上更多。

科学计算集群(High Performance Computing Cluster)

高性能计算(High Perfermance Computing)集群,简称HPC集群。这类集群致力于提供单个计算机所不能提供的强大的计算能力。

负载均衡与双机热备的区别

负载均衡是在这多台服务器之上增加了一台负载均衡服务器,负载均衡服务器的作用是把用户的请求平均分配到每个节点;增加集群整体的处理能力;实现网络访 问的均衡。

双机热备相当于2台服务器其中有一台是另一台的备机,也可以互为备机;主机在运行服务时,备机处于检测状态,主机发生故障后,备机 将接管主机的服务。

负载均衡是解决服务器压力过大,网络请求大量并发而设计的产品; 负载均衡的优点:WEB访问流畅,用户请求平均分布在每个节点上。

双机热备是为保障24*7小时高可用不停机而推出的产品; 双机热备的优点是:能保障用户服务不间断。

负载均衡的缺点:适用静态WEB,如果是数据库将不起作用,数据库的多向同步目前还没有完全解决的 方案。

双机热备缺点:用传统加加阵列的方式增加了存储空间,同样也形成了单点故障;有可能双机热备成为虚设,因为一旦阵列崩溃,服务也意味这 停止。

Tomcat集群的三种负载均衡方式优缺点对照

1.使用DNS轮询.

2.使用Apache R-proxy方式。

3. 使用Apache mod_jk方式.

DNS轮询的缺点是,当集群中某台服务器停止之后,用户由于dns缓存的缘故,便无法访问服务,

必 须等到dns解析更新,或者这台服务器重新启动。

还有就是必须把集群中的所有服务端口暴露给外界,没有用apache做前置代理的方式安全,

并 且占用大量公网IP地址,而且tomcat还要负责处理静态网页资源,影响效率。

优点是集群配置最简单,dns设置也非常简单。

R- proxy的缺点是,当其中一台tomcat停止运行的时候,apache仍然会转发请求过去,导致502网关错误。

但是只要服务器再启动就不存 在这个问题。

mod_jk方式的优点是,Apache 会自动检测到停止掉的tomcat,然后不再发请求过去。

缺点就是,当停 止掉的tomcat服务器再次启动的时候,Apache检测不到,仍然不会转发请求过去。

R-proxy和mod_jk的共同优点是.可 以只将Apache置于公网,节省公网IP地址资源。

可以通过设置来实现Apache专门负责处理静态网页,让Tomcat专门负责处理jsp和 servlet等动态请求。

共同缺点是:如果前置Apache代理服务器停止运行,所有集群服务将无法对外提供。

R-proxy和 mod_jk对静态页面请求的处理,都可以通设置来选取一个尽可能优化的效果。

这三种方式对实现最佳负载均衡都有一定不足,mod_jk相对好 些,可以通过设置lbfactor参数来分配请求任务。

二、配置tomcat集群的方法(Apache mod_jk方式)

环 境 linux redhat 4台,安装tomcat和apache,和jdk配置的过程过于基础,略过,这里主要讲述如何配置

版本: linux redhat server 5.4企业版 tomcat6.0 apache2.2 jdk1.6

1.依次在前三台机器安 装tomcat,jdk并配置环境变量等信息;

2.在第四台机器安装apache

3.配置apache服务器

a:在apache 网站或其他站点下载mod_jk-1.2.26-httpd-2.2.4.so文件(不一定非要这个版本),将该文件复制到apache的modules 目录,并设置读执行权限 用chmod 777 *或其他命令

b:在apache_home目录下的conf/httpd.conf文件中添加

LoadModule jk_module modules/mod_jk-1.2.26-httpd-2.2.4.so

JkWorkersFile conf/workers.properties

JkMount /* lbcontroller

代码解释

LoadModule jk_module modules/mod_jk-1.2.26-httpd-2.2.4.so //表示载入JK模块

JkWorkersFile conf/workers.properties //tomcat实例配置

JkMount /* lbcontroller //设置apache分发器,/*表示apache将所有文件都由分发器lbcontroller 进行分发,你可以自行设置*.jsp,*.do等

c: 配置 workers.properties文件

在apache_home下conf目录中新建workers.properties文 件,输入以下内容

worker.list=lbcontroller

#Tomcat1实例配置

worker.tomcat80.host=10.71.144.80

worker.tomcat80.port=8009

worker.tomcat80.type=ajp13

# 分发权重 值越大负载越大

worker.tomcat1.lbfactor = 1

#Tomcat2实例配置

worker.tomcat81.host=10.71.144.81

worker.tomcat81.port=8009

worker.tomcat81.type=ajp13

# 分发权重 值越大负载越大

worker.tomcat81.lbfactor = 1

#Tomcat3实例配置 #负载均衡分发控制器

worker.tomcat82.host=10.71.144.82

worker.tomcat82.port=8009

worker.tomcat82.type=ajp13

# 分发权重 值越大负载越大

worker.tomcat82.lbfactor = 1

worker.lbcontroller.type=lb

worker.lbcontroller.balance_workers=tomcat80,tomcat81,tomcat82

worker.lbcontroller.sticky_session=True

代 码解释

worker.list=lbcontroller //内容即为httpd.conf文件中的分发器名称。需要注意的内容 是,tomcat实例名称

worker.tomcat80.host=....

...

worker.tomcat82.host=....

...

//这里就是tomcat80和tomcat82必须与之后tomcat中的server.xml中jvmRoute值一致

4. 配置tomcat集群

配置每个tomcat目录下的server.xml文件,具体修改内容如下

a:Engine配置

修 改前

<Engine name="Catalina" defaultHost="localhost">

修改后

<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat80" >

具 体tomcat中jvmRoute的值根据在workers.properties的配置,注意IP地址、tomcat实例名称和jvmRoute值必须 一一对应,其他的tomcat配置方法一致

b:Cluster配置

<!--

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

-->

修 改后,去掉注释并添加一些内容如下

上述配置跟tomcat官方建议的配置,去掉了

<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"

tempDir="/tmp/war-temp/"

deployDir="/tmp/war-deploy/"

watchDir="/tmp/war-listen/"

watchEnabled="false"/>

如果不去掉这部分,则tomcat启动会报"FarmWarDeployer can only work as host cluster subelement!."

c:session复制配置

tomcat集群中的 session管理,主要有两种方式:

1).粘性session

表示从同一窗口发来的请求都将有集群中的同一个tomcat进行处理。配 置方式是在上面workers.properties文件中

worker.lbcontroller.sticky_session=True

粘性session的好处在不会在不同的tomcat上来回跳动处理请求,但是坏处是如果处理该session的tomcat崩溃,那么之后 的请求将由其他tomcat处理,原有session失效而重新新建一个新的session,这样如果继续从session取值,会抛出 nullpointer的访问异常。

2).session复制

session复制是指tomcat彼此之间通过组播方式将session 发到各个tomcat实例上,如果其中一个访问出错,则另外tomcat仍然具有有效的session内容,从而能正常接管其session。坏处是当 tomcat实例很多,或者用户在session中有大量操作时,组播发送的信息量十分惊人。session复制配置则是在发布的web应用程序中的 web.xml中添加

<distributable/>

此外,session复制所需的JDK必须是JDK 5.0及其以上版本

5.测试配置

新建一个jsp页面,写入如下代码,保存index.jsp,分别在tomcat的webapp目录下建 立ydl文件夹,将写好的index.jsp文件上传到3台服务器的tomcat\webapp\ydl目录下

测试的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>

重 启apache服务器和三个tomcat服务器,到此集群负载均衡已配置完成。测试负载均衡先测试apache,访问

http://10.70.144.480/ydl/index.jsp

看 能够运行,能运行,则已建立负载均衡

关闭和启动任何一个tomcat,另外两个tomcat前台打印相关日志信息并自动复制一份session

a:先启动 apache服务器httpd

b:启动名为tomcat80的服务器

前台启动tomcat输出日志方法

#cd /home/support/tomcat-apache6.0/bin

#./catalin.sh run

在浏览器中输入访 问地址http://10.70.144.480/ydl/index.jsp

可 以看到请求被转发到了tomcat80进行处理

c:启动tomcat81

可以发现,tomcat81启动后搜索到了tomcat2实例, 并进行了session复制,在tomcat2的控制台也可以找到输出打印日志

worker.tomcat81.host=10.71.144.81
worker.tomcat81.port=8009  
worker.tomcat81.type=ajp13


一、首先了解下与集群相关的几个概念
worker.tomcat80.host=10.71.144.80
worker.tomcat80.port=8009  
worker.tomcat80.type=ajp13
<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="4001"     
                   autoBind="100"     
                   selectorTimeout="5000"     
                   maxThreads="6"/>      
         <!-- timeout="60000"-->      
         <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=""/>      
       <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>      
  
       <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>      
       <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>      
     </Cluster>


<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"  
                   tempDir="/tmp/war-temp/"  
                   deployDir="/tmp/war-deploy/"  
                   watchDir="/tmp/war-listen/"  
                   watchEnabled="false"/>


<%@ 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>


关闭tomcat80(ctrl+c)后继续刷新url访问。 tomcat81控制台中输出的session 依然与之前tomcat80中的一致,并且在session中保存的属性值仍然有效。

本文出处 http://www.cnblogs.com/qqzy168/archive/2013/08/03/3197569.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: