实战Apache+Tomcat集群和负载均衡html
目录java
1. 什么是J2EE集群... 3web
1.1. 序言... 3apache
1.2. 基本术语... 3浏览器
伸缩性(Scalability):... 4tomcat
高可用性(High availability):... 4服务器
负载均衡(Load balancing):... 4网络
容错(Fault tolerance):... 5session
失效转移(Failover):... 5架构
等幂方法(Idempotent methods):... 5
1.3. 什么是J2EE集群... 5
2. J2EE集群给咱们带来了什么... 9
3. 实战准备... 9
4. 首战失败... 9
5. 详细配置... 9
6. 负载均衡... 9
7. 失败转移... 9
愈来愈多的关键应用运行在J2EE(Java 2, Enterprise Edition)中,这些诸如银行系统和帐单处理系统须要高的可用性(High Availability, HA),同时像Google和Yahoo这种大系统须要大的伸缩性。高可用性和伸缩性在今天高速增加的互链接的世界的重要性已经证明了。eBay于1999年6月停机22小时的事故,中断了约230万的拍卖,使eBay的股票降低了9.2个百分点。
J2EE集群是用来提供高可用性和伸缩性服务,同时支持容错处理的一种流行的技术。可是,因为J2EE规范缺少对集群的支持,J2EE供应商实现集群的方法也各异。这给J2EE架构师和开发人员带来了不少困难。如下是几个常见的问题:
l 为何带集群功能的商业J2EE服务器产品如此昂贵?(10倍于不带集群功能的产品)
l 为何基于单服务器环境构建的应用不能在集群中运行?
l 为何应用在集群环境中运行得很慢,但在非集群环境中却快得多?
l 为何集群的应用移植到其余服务器中失败?
l 理解这些限制和要素的最佳方法是学习他们的实现方式。
在咱们讨论不一样的集群实现以前,先谈谈几个概念。这有助于理解不一样的J2EE集群产品不一样的设计结果和概念:
在一些大的系统中,预测最终用户的数量和行为是很是困难的,伸缩性是指系统适应不断增加的用户数的能力。提升这种并发会话能力的一种最直观的方式就增长资源(CPU,内存,硬盘等),集群是解决这个问题的另外一种方式,它容许一组服务器组在一块儿,像单个服务器同样分担处理一个繁重的任务。
单一服务器的解决方案并非一个健壮方式,由于容易出现单点失效。像银行、帐单处理这样一些关键的应用程序是不能容忍哪怕是几分钟的死机。它们须要这样一些服务在任什么时候间均可以访问并在可预期的合理的时间周期内有响应。集群方案经过在集群中增长的冗余的服务器,使得在其中一台服务器失效后仍能提供服务,从而得到高的可用性。
负载均衡是集群的一项关键技术,经过把请求分发给不一样的服务器,从而得到高可用性和较好的性能。一个负载均衡器能够是从一个简单的Servlet或Plug-Ins(例如一个Linux box利用ipchains来实现),到昂贵的内置SSL加速器的硬件。除此以外,负载均衡器还需执行一些其余的重要任务,如“会话胶粘”让一个用户会话始终存在一个服务器上,“健康检查”用于防止将请求分发到已失效的服务器上。有些负载均衡器也会参与咱们下面将要谈到“失效转移”过程。
高可用性意味着对数据正确性的要求不那么高。在J2EE集群中,当一个服务器实例失效后,服务仍然是有效的,这是由于新的请求将被冗余服务器处理。可是,当一个请求在一个正在失效的服务器中处理时,可能获得不正确的结果。无论有多少个错误,容错的服务应当能确保有严格的正确的行为。
失效转移是集群中用来获取容错能力的另外一项关键的技术。当一个结点失效后,经过选择集群中的另外一个结点,处理将会继续而不会终止。转移到另外一个结点能够被显式的编码,或是经过底层平台自动地透明地路由到另外一个服务器。
等幂方法是指这样一些方法:重复用相同的参数调用都能获得相同的结果。这些方法不会影响系统状态,能够重复调用而不用担忧改变系统。例如:getUsername()就是等幂的,而deleteFile就不是。当咱们讨论HTTP Session失效转移和EJB失效转移时,它是一个重要的概念。
一个天真的问题,不是吗?但我仍要用几句话和图来回答它。一般,J2EE集群技术包括"负载均衡"和"失效转移"。
如图1所示,负载均衡意味着有许多客户端向目标对象同时发出请求。负载均衡器在调用者和被调用者之间,分发请求到与原始对象相同的冗余对象中。伸缩性和高可用性就是这样获得的。
如图2所示,失效转移与负载均衡不一样。有时客户端会连续发请求到目标对象,若是请求中间目标对象失效了,失效转移系统将检测到此次失败,并将请求重定向到另外一个可用的对象。经过这种方式能够得到容错能力。
若是你想知道更多的有关J2EE集群的知识,你就会问到一个基本的问题,“什么对象能够集群?”和“在个人J2EE代码中哪里会发生负载均衡和失效转移呢?”。这些都是用来理解J2EE集群的很是好的问题。实际上,并非全部的对象都能被集群的,而且负载均衡和失效转移并非在J2EE代码全部地方都能发生。看看下面的例子代码:
在Class A的bussiness()方法中,instance1能够负载均衡吗?或是当其失效,能够失效转移到其余B的实例上吗?我想是不行的!对负载均衡和失效转移来讲,必需要有个拦截器在调用者和被调用者之间分发或重定向请求到不一样的对象上。Class A和Class B的实例是运行在一个JVM中紧密耦合的,在方法调用间加入分发逻辑很是困难。
什么类型对象能够被集群?——只有那些能够被部署到分布式拓朴结构中的组件。
在个人J2EE代码中,什么地方会有负载均衡和失效转移?——只在你调用分布式组件的方法时。
在如图4所示的分布式环境中,调用者和被调用者被分离在有明显边界的不一样的运行容器中,这个边界能够是JVM,进程和机器。
当目标对象被客户端调用时,目标对象的功能是在容器中运行的(这就是为何咱们说它是分布式的缘由)。客户端和目标对象经过标准的网络协议通讯。这些特性就为一些机制提供了机会能够介入到方法调用之间实现负载均衡和失效转移。
如图4,浏览器经过HTTP协议调用JSP对象,JSP运行在WEB服务器中,浏览器只须要返回结果而不关心它是怎么运行的。在上述场景中,一些东西就能够在浏览器与WEB服务器之间实现负载均衡和失效转移的功能。在J2EE平台,分布式技术包括:JSP(Servlet),JDBC,EJB,JNDI,JMS,WEB Service等。负载均衡和失效转移就发生在这些分布式方法被调用时。在后续部分咱们将详细讨论这些技术。
apache 2.0.55 (由http://httpd.apache.org/进入下载)
Tomcat 5.5.25 (由http://tomcat.apache.org/进入下载)
在页面 http://tomcat.apache.org/ Download 标题下找到 Tomcat Connectors 连接进入( 点击下载mod_jk-apache-2.0.55.so),看起来像是个Unix/Linux下的动态库,实际应是个Win32 的 DLL 动态库,大概是为保持不一样平台配置的一致性,才用了这个扩展名。
用Apache进行分流,把请求按照权重以及当时负荷分tomcat1,tomcat2...去处理
我把Apache安装在F:\ZQ\apache2.0.55\Apache2
解压两分Tomcat, 分别在 F:\ZQ\apache-tomcat-5.5.1,F:\ZQ\apache-tomcat-5.5.2
在apache安装目录下conf目录中找到http.conf,在文件最后加上下面一句话就能够了
include 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
内容以下(可能要去除 # 不在行首的注释)
worker.list = controller,tomcat1,tomcat2 #server 列表
#========tomcat1========
worker.tomcat1.port=8009
#ajp13 端口号,在tomcat下server.xml配置,默认8009
worker.tomcat1.host=localhost
#tomcat的主机地址,如不为本机,请填写ip地址
worker.tomcat1.type=ajp13
worker.tomcat1.lbfactor = 1
#server的加权比重,值越高,分得的请求越多
#========tomcat2========
worker.tomcat2.port=8109
#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
若是你是水平集群,即在不一样电脑上安装tomcat,tomcat的安装数量为一个,能够没必要修改tomcat配置文件.我这里是在同一台电脑上安装两个tomcat,实现的是垂直集群方式,因此必须修改其中一个的设置,以免端口冲突,按照参考文章是把原来以9开头的端口号改成以9开头端口号,可是在我机器上若是以9开头的端口号,例如9080、9082会与个人WebSphere Application Server配置冲突,因此我这里采起的策略是把原来端口号的第三位改成1,如8080改成8180。
打开tomcat2/conf/server.xml文件
1) 将关闭Tomcat的监听端口改为由8005改成8105
即把
<Server port="8005" shutdown="SHUTDOWN">
改成
<Server port="8105" shutdown="SHUTDOWN">
2) 把http服务端口号由8080改成8180
找到
<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<CONNECTOR port="8080"
把这里的8080改成8180
3) 把AJP端口号由8009改成8109
找到
<!-- Define an AJP 1.3 Connector on port 8009 -->
<CONNECTOR port="8009"
把这里的8009改成8109
4) 把 HTTP 代理端口从8082改成8182(这个配置默认是被注释掉的,可跳过这一步)
找到
<CONNECTOR port="8082"
把这里的8082改成8182
5) 编写一个测试 jsp
创建一个目录TestCluster,里面新建一个test.jsp,内容为
<% System.out.println("==========================="); %> |
把TestCluster放到tomcat1,tomcat2的webapps下
6) 启动apache,tomcat1,tomcat2,进行测试
经过 http://localhost/TestCluster/test.jsp 访问,多刷新几回页面,查看Tomcat1和Tomcat2的窗口,你将能够看到打印了一行行"===========================",而且从统计上来讲,大约在tomcat2打印的数量是在Tomcat1中的两倍,能够看到请求会被tomcat1,tomcat2按照不一样的权重分流处理,实现了负载均衡。
做下面的集群配置,请在workers.properties把tomcat1和tomcat2的权重改成同样的,使请求较平均分配,将有便于看到实验的效果。
只配置负载均衡还不行,还要session复制,也就是说其中任何一个tomcat的添加的session,是要同步复制到其它tomcat, 集群内的tomcat都有相同的session
即对<Cluster>节点的在注释符删掉,并将tomcat2的4001端口改成4002,以免与tomcat冲突,固然,若是是两台电脑,是不用改端口的,去掉注释符便可
即取消对以下处
<Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
managerClassName="org.apache.catalina.cluster.session.DeltaManager"
expireSessionsOnShutdown="false"
............
<ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener"/>
</Cluster>
先后的注释标记<!-- -->,启用该项配置,实现服务器间的Session复制。
这里的做用大概是为了在集群的TOMCAT里面,生成全局HTTP会话标识,这样能够保证会话的惟一性,有利于session的复制
(先跳过这一步,有精力能够试验一下)
在 Tomcat1 和 Tomcat2 的 server.xml 文件,找到
<ENGINE name="Catalina" defaultHost="localhost">
分别改成
<ENGINE name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
和
<ENGINE name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
然而实际我配置的时候还不能加jvmRoute属性,配置了反而有问题。
刷新浏览器窗口老是在某一个tomcat控制台输出形如
SessionID:154678FA6D4D0ABD57658B750E7A3532.tomcat1 (在tomcat1窗口)
或者
SessionID:3800571A532AECEA7280F45361861AD4.tomcat2 (在tomcat2窗口)
由控制台打印的结果能够看出,SessionID在哪一个tomcat上产生,那么后续该会话的请求将老是会这个tomcat来处理。
而且注意到SessionID的形式比一般状况多了一个后缀.tomcat1或.tomcat2,还搞不清楚是为何。
配置时请视实际状况而取舍。
修改test.jsp,内容以下
<%@ page contentType="text/html; charset=GBK" %> <%@ page import="java.util.*" %> <html><head><title>Cluster App Test</title></head> <body> <% System.out.println("SessionID:" + session.getId()); %> Server Info: <% out.println(request.getServerName() + " : " + request.getServerPort()+"<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><br>"); 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="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> |
4. 配置Session复制
在TestCluster目录下新建WEB-INF目录,WEB-INF下新建web.xml,内容以下
<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>TomcatClusterDemo</display-name>
<distributable/>
<web-app>
也就是在须要集群的应用的web.xml中加上属性,代表该应用可多应用分流处理,能进行Session的复制
把TestCluster复制到Tomcat一、Tomcat2的webapps目录下,重启apache,tomcat1,tomcat2
5. 测试Session的复制
经过 http://localhost/TestCluster/test.jsp 访问,输入名称为 name, 值为 Unmi,提交查询,多刷新几回浏览器窗口,你将会看到在两个Tomcat窗口都打印出相同的SessionID及其中的值,而且每次刷新后打印的结果都同样的。
若是不为应用的web.xml加上 ,一样测试上面那个test.jsp页面,每次刷新分流到不一样的tomcat上都会产生不同的SessionID,在同一个tomcat上也是间隔出现不一样的sessionID。
更切身的体验是必定要本身动手配置一遍,并仔细观察两个tomcat的控制上的输出。因本文是参考 轻松实现Apache,Tomcat集群和负载均衡 的实践经历,
启动环境后,启动2个浏览器,获得的是2个不一样的session标识,各自提交您输入的key-value后,把一个tomcat2服务关闭掉,再访问页面,发现tomcat2的session会复制到tomcat1中
用 WebSphere Application Server ND 版配置过垂直和水平集群,可是本身试验集群环境下的应用却不想搬弄这个庞然大物。眼下急于想体验的就是 Quartz 如何适应集群环境,问题的焦点就是:Quartz 定时任务随 Web 应用启动,而 Web 应用部署在集群环境中,如何保证同一时刻只有一个同名的任务实例在跑。
因此会考虑用Apache+Tomcat配置一个轻量级的WEB应用集群,通常进行HTTP分流都是使用Apache,包括WAS集群也是,不多用IIS的。虽然单纯的用Tomcat的balancer应用也能配置进行负载分流,但那个性能应该好不到哪儿去。
用Apache+Tomcat配置的Web应用集群就是部署起来麻烦些,老是要保持双份的应用拷贝,WAS集群则不须要,不知道Jboss作WEB应用集群是怎么样一种状况。
好了,下面要进行该作的事情了,最后也但愿能写个工具能完成从下载到安装配置,启动,中止,重启的全自动化,以及界面的人性化。
在准备软件环境的环节中:最开始的时候小弟下载了Apache2.2.21,mod_jk下载的是2.2.X版本,没有按照网上给出的版本,全部配置都弄好后,访问页面,老是提示404错误
后来换回2.0.55版本,此次实战才成功了。
http://blog.csdn.net/kypfos/article/details/3081330
http://www.kuqin.com/java/20080418/6942.html