Tomcat服务器集群与负载均衡


                         Tomcat服务器集群与负载均衡




一、前言


在单一的服务器上执行WEB应用程序有一些重大的问题,当网站成功建成并开始接受大量请求时,单一服务器终究无法满足需要处理的负荷量,所以就有点显得有 点力不从心了。另外一个常见的问题是会产生单点故障,如果该服务器坏掉,那么网站就立刻无法运作了。不论是因为要有较佳的扩充性还是容错能力,我们都会想 在一台以上的服务器计算机上执行WEB应用程序。所以,这时候我们就需要用到集群这一门技术了。


在进入集群系统架构探讨之前,先定义一些专门术语:

1. 集群(Cluster):是一组独立的计算机系统构成一个松耦合的多处理器系统,它们之间通过网络实现进程间的通信。应用程序可以通过网络共享内存进行消息传送,实现分布式计算机。

2. 负载均衡(Load Balance):先得从集群讲起,集群就是一组连在一起的计算机,从外部看它是一个系统,各节点可以是不同的操作系统或不同硬件构成的计算机。如一个提供Web服务的集群,对外界来看是一个大Web服务器。不过集群的节点也可以单独提供服务。

3. 特点:在现有网络结构之上,负载均衡提供了一种廉价有效的方法扩展服务器带宽和增加吞吐量,加强网络数据处理能力,提高网络的灵活性和可用性。集群系统(Cluster)主要解决下面几个问题: 
高可靠性(HA):利用集群管理软件,当主服务器故障时,备份服务器能够自动接管主服务器的工作,并及时切换过去,以实现对用户的不间断服务。 
高性能计算(HP):即充分利用集群中的每一台计算机的资源,实现复杂运算的并行处理,通常用于科学计算领域,比如基因分析,化学分析等。 
负载平衡:即把负载压力根据某种算法合理分配到集群中的每一台计算机上,以减轻主服务器的压力,降低对主服务器的硬件和软件要求。

总体来说,在负载均衡的思路下,多台服务器为对等方式,每台服务器都具有同等的地位,可以单独对外提供服务而无须其他服务器的辅助。通过负载分担技术,将外部发送来的请求按一定规则分配到对称结构中的某一台服务器上,而接收到请求的服务器都独立回应客户机的请求。

提供服务的一组服务器组成了一个应用服务器集群(cluster),集群下的对等多机环境可以增加系统的并发处理能力,和单台机器出现故障系统的错误冗余能力;同时实现了负载均衡和系统高可靠性。


二、常用负载均衡技术



1. 基于DNS的负载均衡

通过DNS服务中的随机名字解析来实现负载均衡,在DNS服务器中,可以为多个不同的地址配置同一个名字,而最终查询这个名字的客户机将在解析这个名字时 得到其中一个地址。因此,对于同一个名字,不同的客户机会得到不同的地址,他们也就访问不同地址上的Web服务器,从而达到负载均衡的目的。

2. 反向代理负载均衡 (如Apache+JK2+Tomcat这种组合)

使用代理服务器可以将请求转发给内部的Web服务器,让代理服务器将请求均匀地转发给多台内部Web服务器之一上,从而达到负载均衡的目的。这种代理方式 与普通的代理方式有所不同,标准代理方式是客户使用代理访问多个外部Web服务器,而这种代理方式是多个客户使用它访问内部Web服务器,因此也被称为反 向代理模式。

3. 基于NAT(Network Address Translation)的负载均衡技术 (如Linux Virtual Server,简称LVS)

网络地址转换为在内部地址和外部地址之间进行转换,以便具备内部地址的计算机能访问外部网络,而当外部网络中的计算机访问地址转换网关拥有的某一外部地址 时,地址转换网关能将其转发到一个映射的内部地址上。因此如果地址转换网关能将每个连接均匀转换为不同的内部服务器地址,此后外部网络中的计算机就各自与 自己转换得到的地址上服务器进行通信,从而达到负载分担的目的。

三、Apache+JK2实现Tomcat集群与负载均衡


客户系统一般采用Apache httpd作为web服务器,即作为Tomcat的前端处理器,根据具体情况而定,有些情况下是不需要Apache httpd作为 web 服务器的,如系统展现没有静态页面那就不需要Apache httpd,那时可以直接使用Tomcat作为web 服务器来使用。使用Apache httpd主要是它在处理静态页面方面的能力比Tomcat强多了。

                                            


为了实现这个原理我们就需要解决两个问题:
1:如何实现多应用服务器间的session共享:(一台服务器崩溃,另外一台服务器可以继续支持)
2:如何分发请求到各个应用服务器实现压力分解:(这里的解决方案是用apache做 web服务器)
下面我们就是实际行动来看看如何实现这种实现。
环境配置:
App应用服务器apache-tomcat-7.0.52-1 
web服务器:apache的apache 2.0.55
Java环境:jdk1.6及以上


3、web服务器配置
首先安装apache的web服务器:
apache服务器和tomcat的连接方法其实有三种:mod_JK、http_proxy和ajp_proxy。


3.1、软件环境:

   3.1.1、 Apache: apache 2.0.55 (由http://httpd.apache.org/进入下载)(点击下载apache 2.0.55)
   3.1.2、 Tomcat: apache-tomcat-7.0.52-1
   3.1.3、 mod_jk: 在页面 http://tomcat.apache.org/Download 标题下找到 Tomcat Connectors 链接进入(点击下载mod_jk-apache-2.0.55.so),看起来像是个Unix/Linux下的动态库,实际应是个Win32 的 DLL 动态库,大概是为保持不同平台配置的一致性,才用了这个扩展名。


3.2、负载均衡:

   用Apache进行分流,把请求按照权重以及当时负荷分tomcat1,tomcat2...去处理


 3.2.1、 安装apache,tomcat
   我把Apache安装在D:\Program Files\Apache Group\Apache2,Tomcat解压两分Tomcat, 分别在 D:\Program Files\Apache Group\apache-tomcat-7.0.72-1,D:\Program Files\Apache Group\apache-tomcat-7.0.72-1,我的结构如下:

                                        


 3.2.2、修改Apache配置文件http.conf

   在apache安装目录下conf目录中找到http.conf,在文件最后加上下面一句话就可以了:   

include conf/mod_jk.conf

 3.3.3、 http.conf 同目录下新建mod_jk.conf文件,内容如下:

#加载mod_jk Module     
LoadModule jk_module modules/mod_jk-apache-2.0.55.so     
    
#指定 workers.properties文件路径     
JkWorkersFile conf/workers.properties     
    
#指定那些请求交给tomcat处理,"controller"为在workers.propertise里指定的负载分配控制器     
JkMount /*.jsp controller

配置说明:

如果还要指定*.do也进行分流就再加一行
JkMount /*.do controller

如果你想对所有的请求进行分流只需要写成
JkMount /* controller


 3.3.4、 在http.conf同目录下新建 workers.properties文件:

worker.list = controller,tomcat1,tomcat2  #server 列表(tomcat1,tomcat2分别指tomcat的具体路径)      
#========tomcat1========      
worker.tomcat1.port=8019       #ajp13 端口号,在tomcat下server.xml配置,默认8009      
worker.tomcat1.host=localhost  #tomcat的主机地址,如不为本机,请填写ip地址      
worker.tomcat1.type=ajp13      
worker.tomcat1.lbfactor = 1    #server的加权比重,值越高,分得的请求越多      
     
#========tomcat2========      
worker.tomcat2.port=8029       #ajp13 端口号,在tomcat下server.xml配置,默认8009      
worker.tomcat2.host=localhost  #tomcat的主机地址,如不为本机,请填写ip地址      
worker.tomcat2.type=ajp13      
worker.tomcat2.lbfactor = 2    #server的加权比重,值越高,分得的请求越多      
     
#========controller,负载均衡控制器========      
worker.controller.type=lb      
worker.controller.balanced_workers=tomcat1,tomcat2   #指定分担请求的tomcat      
worker.controller.sticky_session=1 

3.3.5、 修改tomcat配置文件server.xml:

如果你是水平集群,即在不同电脑上安装tomcat,tomcat的安装数量为一个,可以不必修改tomcat配置文件。我这里是在同一台电脑上安装两个tomcat,实现的是垂直集群方式,所以必须修改其中一个的设置,以避免端口冲突,按照参考文章是把原来以9开头的端口号改为以9开头端口号,但是在我机器上如果以9开头的端口号,例如9080、9082会与我的WebSphere Application Server配置冲突,所以我这里采取的策略是把原来端口号的第三位改为1,如8080改为8180。

打开tomcat2/conf/server.xml文件


3.3.5.1、将关闭Tomcat的监听端口改成由8005改为8105
即把
 <Server port="8005" shutdown="SHUTDOWN">
改为
 <Server port="8105" shutdown="SHUTDOWN">


3.3.5.2、把http服务端口号由8080改为8180
找到
 <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
    <CONNECTOR port="8080" 
把这里的8080改为8180


3.3.5.3、 把AJP端口号由8009改为8109
找到
 <!-- Define an AJP 1.3 Connector on port 8009 -->
    <CONNECTOR port="8009"
把这里的8009改为8109


3.3.5.4、 把 HTTP 代理端口从8082改为8182(这个配置默认是被注释掉的,可跳过这一步)
找到
<CONNECTOR port="8082"
把这里的8082改为8182


3.3.5.5、 编写一个测试 jsp
建立一个目录TestCluster,里面新建一个test.jsp,内容为:

<%     
    System.out.println("=============hello yangwenxue!!!==============");    
%>

把TestCluster放到tomcat1,tomcat2的webapps下


3.3.5.6、启动apache,tomcat1,tomcat2,进行测试:

通过 http://localhost/TestCluster/test.jsp 访问,多刷新几次页面,查看Tomcat1和Tomcat2的窗口,你将可以看到打印了一行行“=============hello yangwenxue!!!==============”,并且从统计上来说,大约在tomcat2打印的数量是在Tomcat1中的两倍,可以看到请求会被tomcat1,tomcat2按照不同的权重分流处理,实现了负载均衡,如下图:



3.3.6、集群(session复制):

在workers.properties把tomcat1和tomcat2的权重改为一样的,使请求较平均分配,将有便于看到实验的效果。


首先配置web应用服务器配置apache-tomcat-7.0.72-1配置

3.3.6.1、修改tomcat的server.xml文件增加如下内容(在<Engine>或<Host>元素下添加以下内容均可):

<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="15000"
waitForAck="true"/>
<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>

按照apache tomcat官方文档上面的说法,对于tomcat6要做集群的话,只需要将<Engine>元素下的

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

的注释符号去掉,启用这句配制就可以正常使用集群了。不过由于我搭建的测试环境2个tomcat是在同一台机子上面,因此只启用这个<Cluster>的话,这个元素下的默认Receiver port就会冲突。因此必须补全这些配置。
另外,按照官方文档里说明的<Cluster>的默认配置,<Membership>元素下的address属性默认值为228.0.0.4 .  这个配置在我的系统上始终会出现2个tomcat无法交换数据包的问题。需改成224.0.0.1才能正常使用。
需要而外注意的是,2个tomcat里添加到上面这段<Cluster>配置,其<Receiver>下的Port元素必需配置成不同的。如其中一个是4001,一个是4002.(tomcat默认可以检测到4000~4100之间的端口)。


3.3.6.2、修改<Engine>的属性。

将原来的:


改为:


tomcat2对应修改为tomcat2。

2个tomcat, jvmRoute分别配置成tomcat1和tomcat2,即和apache/conf里worker.properites配置文件中配置的worker名称对应。


3.3.6.3、项目集群配置及测试:


a)、用eclipse新建一个web工程,并修改项目的web.xml,添加 <Context distributable="true" />,所有需要集群的web项目,其web.xml中都必须添加

<distributable/>

这个定义,如下图:


b)、在该web工程的WebContext目录下新建一个test.jsp文件,编辑内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ page import="java.util.*"%>
<html>
<head><title>Cluster app test</title></head>
<body>
	Server info:
	<%
		out.print(request.getLocalAddr() + ":" + request.getLocalPort() + "<br>");
	%>
	
	<%
		out.print("<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.print(name + " = " + value + "<br>");
			System.out.println(name + " = " + value);
		}
	%>
	
	<form action="test.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>

c)、打包发布到两个tomcat的webapps下。


d)、启动测试:

启动第一个tomcat,先启动哪个都行:



启动tomcat2:

启动过程和tomcat1一样,值得注意的是,在tomcat2启动的时候,tomcat1会打印出集群中加入member的提示:



e)、打开浏览器,输入地址:http://localhost/Test/test.jsp,该请求分配给了tomcat1;添加几条测试session,浏览器和tomcat的请求情况:



f)、换个浏览器,输入:http://localhost/Test/test.jsp,改请求分配给了tomcat2,添加几条测试session:


以上就是集群中的对tomcat的分流,负载均衡。

现在我们来测试如果一台服务器宕机后session是否能达到共享:

g)、关闭tomcat1,tomcat2会有集群中服务关闭的提示:



tomcat1关闭后,原来在tomcat1的session能否复制到tomcat2呢?

刷新ie浏览器,在tomcat2的请求中确实收到了原来tomcat1的session:


刷新两个浏览器,tomcat2的请求结果:


这样,其中一个tomcat服务宕掉了,原来的session的信息不会丢失,工作交给其他tomcat来工作,这就是集群的好处。


说明:

1、本篇文章参考了几篇tomcat的集群,tomcat的session共享,及官网文档,并亲自搭建成功,总结每个实现步骤。

2、为了尊重前人铺路成果,所以本篇文章标为转载。

3、在此也声明:转载请注明出处:http://blog.csdn.net/yangwenxue_admin/article/details/72845360




已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页