Tomcat 中的集群原理是通过组播的方式进行节点的查找并使用 TCP 连接进行会话的复制。
实现效果 : 用 apache 分发请求到 tomcat 中的对应的项目
环境说明 :
操作系统 : window xp
Javasdk : 1.7
Apache : 2.2.14 ( 本地安装路径 :D:\Apache2.2\)
Tomcat : 7.0.42 ( http://tomcat.apache.org/download-70.cgi ), 如果在同一台机器上模拟 , 下载 zip 版本 . 实例中展示了 2 个节点
mod_jk : 1.2.37: ( http://tomcat.apache.org/download-connectors.cgi )
安装步骤:
1.安装 jdk
2.安装 Apache2.2, 使用默认设置 , 并且安装路径中不要空格 .
3.解压 tomcat
4.拷贝 mod_jk.so 到 Apache 安装路径的 modules 文件夹下
配置步骤
修改 Apache 配置 :
关于修改涉及到的文件 httpd.conf 和 workers.properties 文件可以下载一份 mod_jk 的源码包参看
1.修改 Apache 配置文件 httpd.conf ( 笔者路径 : D:\Apache2.2\conf\httpd.conf), 在最后一行末尾添加 :
include "D:\Apache2.2\conf\mod_jk.conf"
2. 在httpd.conf 同目录下新建 mod_jk.conf 文件
#加载mod_jk Module
LoadModule jk_module modules/mod_jk.so
#指定 workers.properties文件路径
JkWorkersFile conf/workers.properties
#指定哪些请求交给tomcat处理,"controller"为在workers.propertise里指定的负载分配控制器名
JkMount /* controller
3.在 httpd.conf 同目录下新建 workers.properties 文件
#这里可以配置任意多个Tomcat,此处配置了2个Tomat服务器.
#host和port根据自己实际配置.实例配置的是本机两个tomcat,分别使用不同的端口.避免冲突
#如果Tomcat不再同一机器上,没必要改端口的。
#server 列表
worker.list=controller,tomcat1,tomcat2
#========tomcat1========
worker.tomcat1.port=9988 #ajp13 端口号,在tomcat下server.xml配置,默认8009
worker.tomcat1.host=localhost #tomcat的主机地址,如不为本机,请填写ip地址
worker.tomcat1.type=ajp13
worker.tomcat1.lbfactor=1 #server的加权比重,值越高,分得的请求越多
#========tomcat2========
worker.tomcat2.port=9999 #ajp13 端口号,在tomcat下server.xml配置,默认8009
worker.tomcat2.host=localhost #tomcat的主机地址,如不为本机,请填写ip地址
worker.tomcat2.type=ajp13
worker.tomcat2.lbfactor=1 #server的加权比重,值越高,分得的请求越多
#========controller,负载均衡控制器========
worker.controller.type=lb
#指定此负载平衡器负责的Tomcat应用节点。
worker.controller.balanced_workers=tomcat1,tomcat2 #指定分担请求的tomcat
#此处指定集群是否需要会话复制,如果设为true,则表明为会话粘性,不进行会话复制,当某用户的请求第一次分发到哪台
#Tomcat后,后继的请求会一直分发到此Tomcat服务器上处理;如果设为false,则表明需求会话复制。
worker.controller.sticky_session=false #设为false,则表明需求会话复制。
修改 Tomcat 配置 :
说明 , 如果修改了 tomcat 配置文件 , 最好将文件编码转换成 utf-8 格式 .
因为实例中我们定义了 2 个 tomcat 处理分发 . 所以我们将 tomcat 的解压版本 (zip) 格式复制一份 . 用来分别担当不同的分发处理角色 . 这里因为在一台机器上 , 所以我们使用 zip 版本的 , 当然你某个分发处理机器上只一个 tomcat 服务器的话 , 可以选择安装版本的 . 这里推荐使用解压版的 .tomcat6的配置方式跟 7 一致 .
以 tomcat-node1 为实例
1.修改分发 tomcat 对应的 service.xml 文件 , 保证 Apache 对应的 workers.properties 中的 AJP13 的 connector 的 port.
<!-- 定义一个AJP 1.3 连接端口为9988 ,默认值为8009,这里我们改成我们自己定义的9988端口 -->
<Connector port="9988" protocol="AJP/1.3" redirectPort="8443" />
2.增加 jvmRoute 的值 , 保证同 workers.properties 里边配置的值一致
<!--增加jvmRoute,值为在Apache中配置的list集群结点中的值,这里定义为tomcat1结点-->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
3.去掉默认注释掉的集群配置
<!--取消集群结点相关的注释,该句默认值注释掉的,我们需要配置集群所以去掉注释,让其起作用-->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
如果我们的 tomcat 结点分布在不同的机器上 , 那么我们的集群至此已经配置完成 . 去掉多余注释, 显示做了修改的部位
修改前
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<Engine name="Catalina" defaultHost="localhost">
<!--For clustering-->
<!--
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
-->
修改后的 tomcat-node1
<!-- 定义一个AJP 1.3 连接端口为9988 ,默认值为8009,这里我们改成我们自己定义的9988端口 -->
<Connector port="9988" protocol="AJP/1.3" redirectPort="8443" />
<!--增加jvmRoute,值为在Apache中配置的list集群结点中的值,这里定义为tomcat1结点-->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
<!--取消集群结点相关的注释,该句默认值注释掉的,我们需要配置集群所以去掉注释,让其起作用-->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
修改后的 tomcat-node2
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="9999" protocol="AJP/1.3" redirectPort="8443" />
<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
<!--For clustering-->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
说明 : 这里的 protocol="AJP/1.3", 连接以及 jvmRoute 需要保证同我们在 Apache 服务器中配置的 works.properties 一致 . 修改完后最好将 service.xml 文件的编码设置为 utf-8 格式 . 否则可能 tomcat 启动会出错 .
4.实例中我们的两个 tomcat 结点在同一台机器上 , 所以还需要保证 protocol="HTTP/1.1" 的端口不一致 . 不然本地的两个 tomcat 会起冲突
下面为笔者实例中解决同一台机器上多个 tomcat 服务器之间端口冲突做的修改 .
Tomcat--node1
Tomcat-node2
<Server port="9995" shutdown="SHUTDOWN">
……
<Connector port="9990" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
……
说明 : 这里的 protocol="HTTP/1.1" 配置的相关端口之间不能冲突 , 而且也不能同本机其它应用程序占用的端口冲突 . 否则可能会报错 .
实例测试
1.在 web.xml 文件中增加
<distributable/>
2.编写测试 jsp 代码
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="java.text.SimpleDateFormat"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Tomcat集群测试</title>
</head>
<body>
服务器信息:
<%
String dtm = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
System.out.println("["+request.getLocalAddr()+":"+ request.getLocalPort()+"]" + dtm);
out.println("<br>["+request.getLocalAddr()+":" +request.getLocalPort()+"]" + dtm+"<br>");
%>
session分发:
<%
session.setAttribute("name","dennisit");
System.out.println("[session分发] session id:"+session.getId());
out.println("<br>[session分发] session id: " + session.getId()+"<br>");
%>
</body>
</html>
3.测试负载均衡与 session 分发
将项目部署到每个集群结点中 , 即实例中的 tomcat_node1 和 tomcat_node2, 依次移动 Apache 和 tomcat 服务器 ,tomcat 服务器之间的启动顺序随意 . 这里 Apache 端口使用默认的 80.
上面是在FireFox 中运行项目后刷新 3 次执行的效果 , 可以看到 2 个 tomcat 分发结点之间轮流负载. 而且两台服务器上的 session 值是一样的 . 说明 session 分发成功 .
两台 Tomcat 服务器日志打印输出结果 :
错误解决 问题:发生服务特定错误:1
右键我的电脑 -> 管理 -> 系统工具 -> 时间查看器 -> 应用程序 , 然后对应应用程序的右侧可以查看到错误日志 .
笔者错误 :
The Apache service named reported the following error:
>>> httpd.exe: Syntax error on line 484 of D:/Apache2.2/conf/httpd.conf: Syntax error on line 1 of D:/Apache2.2/conf/mod_jk.conf: Cannot load D:/Apache2.2/modules/mod_jk.so into server: \xd5\xd2\xb2\xbb\xb5\xbd\xd6\xb8\xb6\xa8\xb5\xc4\xb3\xcc\xd0\xf2\xa1\xa3 .
错误原因,这个文件要跟 Apache 版本对应 . 我的 Apache 版本为 2.2 的 , 最初搞的为 tomcat-connectors-1.2.37-windows-i386-httpd-2.0.x 版 本所以错误 .
修复后启动
附录:
Apache 与 Tomcat 的区别:
Apache 是一个 web 服务器环境程序,可以作为 web 服务器使用。不过只支持静态网页,如 (asp,php,cgi,jsp) 等动态网页的就显得无能为力。
如果想让服务器也能处理动态页面,那么就需要 Tomcat 。
当处理静态页面时 ,Tomcat 不如 Apache 迅速。 Tomcat 不象 Apache 一样可配置 ( 如:可以作为一个代理服务器,即 loadbalaner) 。
Tomcat 不象 Apache 一样强壮。
基于以上原因,一个现实的网站使用一个 Apache 作为 Web 服务器,为网站的静态页面请求提供服务;并使用 Tomcat 服务器作为一个 Servlet/JSP 插件,显示网站的动态页面。
Apache,Tomcat 负载均衡和集群 :
对请求的处理又有两种不同的方式:负载平衡、状态复制 ( 即集群 ).
负载平衡:每台服务器都是独立的 , 只是对请求的负载进行平衡,而不对状态( SESSION )进行复制。
状态复制(集群):先进行负载平衡,再在各服务器间复制应用状态。
Apache+Tomcat 构建企业级应用
1.Apache 主要用来解析静态文本 , 如 html , tomcat 也有此功能,但 apache 能大大提高效率,对于并发数较大的企业级应用,能更好的显示 Apache 的高效率;
2.Tomcat 用来解析 jsp,servlet 等 , 所有的客户请求首先会发送到 apache ,如果请求是静态文本则由apache 解析,并把结果返回给 客户端,如果是动态的请求,如 jsp , apache 会把解析工作交给 tomcat ,由 tomcat 进行解析(这首先要两者现实整合), tomcat 解析完 成后,结果仍是通过 apache返回给客户端,这样就可以达到分工合作 , 实现负载均衡,提高系统的性能 !