参考 :
http://www.raibledesigns.com/tomcat/
http://tomcat.apache.org/connectors-doc-archive/jk2/jk2/vhosthowto.html
http://tomcat.apache.org/tomcat-6.0-doc/cluster-howto.html
环境:
操作系统:WindowXP
应用服务器:Tomcat6.0.18 , Apace2.2.15
JDK版本:JDK6
一、 前期准备
从http://www.apache.org官方网站下载下面两款软件
apache 下载地址 http://archive.apache.org/dist/httpd/
tomcat 下载地址 http://archive.apache.org/dist/tomcat/
mod_jk 下载地址 http://www.apache.org/dist/tomcat/tomcat-connectors/jk/
二、Apache 的安装:(采用源码编译安装的方式)
#tar xzvf httpd-2.2.17.tar.gz
#cd httpd-2.2.17
# ./configure --with-ldap --enable-mods-shared="all ssl ldap cache proxy authn_alias mem_cache file_cache authnz_ldap charset_lite dav_lock disk_cache" 【此选项为编译所有的模块】
make
make install
1. 测试
/usr/local/apache2/conf/httpd.conf 中设置
ServerName localhost
#cd /usr/local/apache2/bin
#./apachectl start
访问地址:http://192.168.50.50
It works!
说明已经成功
三、(1)mod_proxy 方式负载均衡配置
httpd.conf 配置 [C:\Program Files\Apache2.2\conf\httpd.conf]
① 加载proxy模块 将以下Module的注释去掉,这里并没有使用mod_jk.so进行apache和tomcat的链接,从2.X以后apache自身已集成了 mod_jk.so的功能。只需简单的把下面几行去掉注释,就相当于以前用mod_jk.so比较繁琐的配置了。这里主要采用了代理的方法,就这么简单。
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
② 配置虚拟主机 proxyblancer 在httpd.conf 尾部添加
# mod_proxy 负载均衡配置
Include conf/mod_proxy.conf
在conf 目录下新建 mod_proxy.conf 内容如下:
Listen 8051 <VirtualHost *:8051> ServerAdmin angel.zhu@99bill.com ServerName localhost ServerAlias localhost ErrorLog "logs/localhost-error.log" CustomLog "logs/localhost-access.log" common ProxyPass / balancer://cluster/ stickysession=JSESSIONID|jsessionid nofailover=Off lbmethod=byrequests timeout=5 maxattempts=3 ProxyPassReverse / balancer://cluster/ ProxyRequests Off ProxyPreserveHost On <proxy balancer://cluster> BalancerMember ajp://192.168.69.69:8009 loadfactor=1 route=jvm1 BalancerMember ajp://192.168.67.143:9009 loadfactor=1 route=jvm2 </proxy> </VirtualHost>
ServerAdmin 指定服务器管理员的E-MAIL地址,服务器自动将错误报告给该地址
ServerName web客户端搜索的主机名
ErrorLog 日志引擎 负责记录错误,
CustomLog 日志引擎 负责记录所有的http访问以及返回状态
ProxyPass 为代理转发Url,即将所有访问 / 的请求转发到群集 balancer://cluster
balancer : 复制会话的方式,包括JSESSIONID或PHPSESSIONID ;
nofailover :On 表示会话在worker出错或停掉时会中断,当服务器不支持会话复制时设为on;
lbmethod:选择负载的调度算法,默认byrequests表示轮询调度(就是1:1),bytraffic表示加权重的调度,需加 loadfactor指定权重值。
ProxyPassReverse / balancer://cluster/
此指令使Apache调整HTTP重定向应答中Location, Content-Location, URI头里的URL。这样可以避免在Apache作为反向代理使用时,后端服务器的HTTP重定向造成的绕过反向代理的问题。
这里balancer://是告诉Apache需要进行负载均衡的代理,这里的"cluster"必须与上面的集群名保持一致。
ProxyRequests Off 告诉Apache需要使用反向代理(利用Apache进行负载均衡必须使用反向代理)
ProxyPreserveHost On 当启用时,此选项将把传入请求的"Host:"行传递给被代理的主机,而不是传递在ProxyPass中指定的主机名。
BalancerMember为群集balancer://cluster的成 员,即群集服务器A或B,负载均衡服务器会根据均衡规则来将请求转发给BalancerMember。
<proxy balancer://cluster> 用于配置工作在tomcat集群中的所有节点,
Apache通过ajp协议与tomcat进行通信,ip地址和端口唯一确定了tomcat节点和配置的ajp接受端口。
loadfactor是负载因子,Apache会按负载因子的比例向后端tomcat节点转发请求,负载因子越大,对应的tomcat服务器就会处理越多的请求,如两个tomcat都是1,Apache就按1:1的比例转发,如果是2和1就按2:1的比例转发。
route参数对应后续tomcat配置中的引擎路径 <Engine jvmRoute="jvm1">对应。
注:
正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。
正向代理还可以使用缓冲特性(由mod_cache提供)减少网络使用率。
反向代理的典型用途是将防火墙后面的服务器提供给Internet用户访问。
反向代理还可以为后端的多台服务器提供负载平衡,或为后端较慢的服务器提供缓冲服务。
另外,还可以启用高级URL策略和管理技术,从而使处于不同web服务器系统的web页面同时存在于同一个URL空间下。
mod_proxy 方式 负载均衡配置 完成
三、(2)mod_jk 方式负载均衡配置
1. 由于mod_jk 为第三方模块,需要到tomcat官网下载,
2. 在Apache Server 上将jk 模块编译进apache中:
# tar xvfz tomcat-connectors-1.2.31-src.tar.gz
# cd tomcat-connectors-1.2.31-src/native/
./configure --with-apxs=/usr/local/apache2/bin/apxs --with-java-home=/usr/local/jdk
make && make install
此时在/usr/local/apache2/modules 下会出现一个mod_jk.so,则已编译成功。
3.配置apache 的配置文件 在httpd.conf 尾部添加
# mod_jk 负载均衡配置
Include conf/mod_jk.conf
在conf目录下新建 mod_jk.conf 内容如下:
LoadModule jk_module modules/mod_jk.so <IfModule jk_module> JkWorkersFile conf/workers.properties JkLogFile logs/mod_jk.log JkLogLevel warn </IfModule> Listen 8052 <VirtualHost *:8052> DocumentRoot "/usr/local/apache2/htdocs" ServerName localhost ServerAdmin app2.Admin@99bill.com ErrorLog "logs/localhost-error.log" TransferLog "logs/localhost-access.log" JkMount /* tomcatbalancer </VirtualHost>
3 创建并配置workers.properties文件
worker 是一个Tomcat 实例 ,用来处理从web server 来的servlet 请求,可以一个worker 或 多个worker,来实现加载平衡或网站分区。 每个worker 都向web server 注册其主机的ip 地址,端口号和通信协议。
conf/workers.properties,添加以下内容:
# environment slash for Windows(反斜杠代表Windows系统) ps=\ worker.retries=2 # 此处定义了一个负载均衡器和状态监视器 worker.list=tomcatbalancer,jkstatus #========tomcat1======== worker.tomcatA.port=8009 worker.tomcatA.host=192.168.1.4 worker.tomcatA.type=ajp13 worker.tomcatA.lbfactor=1 worker.tomcatA.connection_pool_timeout=600 worker.tomcatA.socket_keepalive=true worker.tomcatA.socket_timeout=60 #========tomcat2======== worker.tomcatB.port=9009 worker.tomcatB.host=192.168.1.4 worker.tomcatB.type=ajp13 worker.tomcatB.lbfactor=1 worker.tomcatB.connection_pool_timeout=600 worker.tomcatB.socket_keepalive=true worker.tomcatB.socket_timeout=60 worker.jkstatus.type=status #========controller,负载均衡控制器======== worker.tomcatbalancer.type=lb worker.tomcatbalancer.balance_workers=tomcatA,tomcatB worker.tomcatbalancer.sticky_session=true worker.tomcatbalancer.sticky_session_force=false
上述配置文件中
sticky_session=true表示某个请求始终由 当前Tomcat处理,不会转移到其他Tomcat上。sticky_session_force=false表示,当前Tomcat挂掉的时候,自动将 Session复制到其他Tomcat上。
如果将sticky_session_force设置为true,当你关闭一台Tomcat并刷新网页,将得到 503错误。但设置为false,关闭一台Tomcat并刷新网页,被关闭的那台Tomcat上的Session会被自动复制到其他Tomcat上,系统 继续正常运行。
mod_jk 方式 负载均衡配置 完成
四、配置Tomcat 修改Tomcat安装目录下的conf子目录中的server.xml文件
如果我们需要在一台机器上跑两个不同的 tomcat 特别要注意:不要设置 CATALINA_HOME 环境变量
如果多台机器跳过 a , b 步骤
a.修改http默认访问端口 ,其中tomcatA 用默认值 ,修改tomcatB将
<Connector port="8080" protocol="HTTP/1.1" maxThreads="150" connectionTimeout="20000"
redirectPort="8443" />
改为
<Connector port="9080" protocol="HTTP/1.1" maxThreads="150" connectionTimeout="20000"
redirectPort="9443" />
b. 配置 server 的关闭 修改其中一个tomcat的Shutdown端口号。其中tomcatA用默认值。修改tomcatB
将:<Server port="8005" shutdown="SHUTDOWN">
改为 <Server port="8055" shutdown="SHUTDOWN">
③ 配置 Engine
<Engine name="Catalina" defaultHost="localhost">
将其修改为
<Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">
注意: 这个地方的jvmRoute的名字一定要和apache中的配置中一致.
④ Connector 配置
检查文件中对Connector端口8009配置
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Connector port="9009" protocol="AJP/1.3" redirectPort="9443" />
注意: 这里 port 一定要和apache中 <proxy balancer://cluster> 的配置一致.
这里是apache和tomcat链接的关键,前台apache就是通过AJP协议与tomcat进行通信的,以完成负载均衡的作用。同时也要把redirectPort的值改成唯一
其实就是上述这样的一个架构,下面是原理
1) Apache装有一个模块,这个模块叫mod_jk
2) Apache通过80端口负责解析任何静态web内容
3) 任何不能解析的内容,用表达式告诉mod_jk,让mod_jk派发给相关的app server去解释。
通过上述的文字描述我们可以得知:
1) 我们需要在Apache中先装一个mod_jk
2) 我们需要在httpd.conf中写点表达式
下面来实现。
1) 把mod_jk.so手工copy进我们的Apache安装目录的modules目录下
2) 用ultraedit打开httpd.conf文件,跑到文件最后面加入以下几行:
- ####### Apache整合Tomcat start #######
- #此处mod_jk的文件为你下载的文件
- LoadModule jk_module modules/mod_jk.so
- #指定tomcat监听配置文件地址
- JKWorkersFile conf/workers.properties
- #指定日志存放位置
- JkLogFile logs/mod_jk.log
- JkLogLevel info
- <VirtualHost localhost>
- ServerAdmin localhost
- DocumentRoot "D:\www"
- ServerName localhost
- SetEnv force-proxy-request-1.0.1
- SetEnv proxy-nokeepalive 1
- DirectoryIndex index.html index.htm index.jsp index.action
- ErrorLog logs/shsc-error_log.txt
- CustomLog logs/shsc-access_log.txt common
- JkMount /*WEB-INF ajp13
- JkMount /*j_spring_security_check ajp13
- JkMount /*.action ajp13
- JkMount /servlet/* ajp13
- JkMount /*.jsp ajp13
- JkMount /*.do ajp13
- JkMount /*.action ajp13
- JkMount /*fckeditor/editor/filemanager/connectors/*.* ajp13
- JkMount /fckeditor/editor/filemanager/connectors/* ajp13
- </VirtualHost>
- ####### Apache整合Tomcat end #######
Apache conf目录下 建个 workers.properties 文件 内容如下:
- ps=\
- worker.list=ajp13 #模块版本
- worker.ajp13.port=8009 #工作端口,若没占用则不用修改
- worker.ajp13.host=localhost #本机,若上面的Apache主机不为localhost,作相应修改
- worker.ajp13.type=ajp13 #类型
- #worker.ajp13.lbfactor=1 #代理数,不用修改
⑤ TOMCAT 集群配置 共享Session (每个tomcat中都要修改)
点击(此处)折叠或打开
- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
- channelSendOptions="6">
- <Manager className="org.apache.catalina.ha.session.BackupManager"
- expireSessionsOnShutdown="false"
- notifyListenersOnReplication="true"
- mapSendOptions="6"/>
- <!--
- <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"
- bind="127.0.0.1"
- address="228.0.0.4"
- port="45564"
- frequency="500"
- dropTime="3000"/>
- <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
- address="127.0.0.1"
- port="4001"
- selectorTimeout="100"
- maxThreads="6"/>
- <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=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
- <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
- </Cluster>
第一种,simple tcp cluster
(tomcat5以上版本自带的基于tcp广播技术的集群,这种方法比较简单,只需修改server.xml配置文件即可)
在<Engine></Engine>添加如下配置代码,多台机器,只需修改第二个 address (本机地址)和port 即可。
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6"> <Manager className="org.apache.catalina.ha.session.BackupManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" mapSendOptions="6" /> <!-- <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="192.168.67.143" port="4001" selectorTimeout="100" maxThreads="6" /> <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=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;" /> <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve" /> <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false" /> <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener" /> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" /> </Cluster>
注意:在 Tomcat的集群复制中,分为DeltaManager和BackupManager两种,前者适合于小型系统,任何情况下,均进行Session复 制,消耗大量资源。所以,我们应该采用BackupManager,仅在需要的时候(Tomcat挂掉的时候)进行Session复制。如果是在同一台机器上配置多个tomcat实例来进行集群的测试,那么请一定要注意tomcat实例运行的端口和 集群所监听的端口是否冲突!
⑥ 最后修改web应用WEB-INF目录下的web.xml文件 在</web-app>前加 <distributable />
标签(这个是tomcat进行session复制所必须的,否则session不能进行复制!)
或者 改变Tomcat的content.xml配置文件,修改 <Context distributable="true">
tomcat的集群部署修改动作都比较简单,但实际在运行过程中会出现一系列的问题,我这里列举我在配置后使用过程中出现的一些问题和要点,供大家参考:
1、用户存入SESSION中的数据的问题
使用tomcat集群进行SESSION复制,必须要保证你的session中存放的所有对象都是实现了java.io.Serializable接口 的,因为session复制就是序列化对象到其他WEB应用服务器上的,所以如果没有实现该接口,那么SESSION同步将会失败。另外一点,就是如果要 同步的机器比较多的话,那么要注意保证SESSION中存放的数据比较小,不要什么都存放到SESSION中,因为复制SESSION也是需要开销的,数 据越大开销也越大。
2、Tomcat执行SESSION复制的触发条件
我们在tomcat的server.xml文件中集群部分cluster标签中可以看到属性:useDirtyFlag, 如果这个设置为true(默认的),那么只有当使用setAttribute往session中设置数据的时候才会同步其他WEB服务器的 SESSION,如果为false,那么每一次请求的sesison都会被同步到其他服务器上。因此在操作SESSION的时候要特别注意,避免出现 SESSION无法同步的问题。
举个简单的例子,比如我们在单机应用情况下修改SESSION中用户的某一个数据,那么通常就是:
User user = (User)request.getSession().getAttribute(“user”);
User.setName(“my name”);
这样我们就是直接存取出来,然后进行修改,虽然在单机情况下没有问题,但是在集群条件下,这样就导致了多台WEB服务器上的SESSION不同步的问 题,因为SESSION并没有改变,Tomcat无法监视session中某个数据的值是否发生了变化。因此,我们还需要执行如下操作以保证 SESSION的同步:
request.getSession().setAttribute(“user”, user);
所以,我们在操作SESSION的时候要特别注意!另外的建议就是,我们应该尽可能的不要修改SESSION中的数据。
3、Linux下的组播问题
因为Tomcat的SESSION复制通信是通过组播功能来实现不同服务器之间的交互的,所以需要在服务器上开通组播功能,windows默认情况下是开通组播服务的,而Linux系统下默认是没有开通的,我们需要通过如下命令来开通其组播功能:
route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
如果需要服务器启动时即开通组播
需在/etc/sysconfig/static-routes文件内加入
eht0 net 224.0.0.0 netmask 240.0.0.0
具体组播概念请查阅CCNP相关内容。
可以通过 netstate -g 来查看组播状态,也可以在route -e 命令中看到
第二种,使用memcached共享session
memcached-session-manager 配置
让tomcat 调用memcached 来存储session 早就是一个很成熟的解决方案了,开源的msm 就可以解决这个问题。
官方给出的4 种序列化方案,其中kryo 是效率最高的,具体比较看官方地址:
http://code.google.com/p/memcached-session-manager/wiki/SerializationStrategies
下载地址:
http://code.google.com/p/memcached-session-manager/downloads/list
本次实验用的tomcat版本为6.0.18,以下为我用包,,谁有需要可以联系我,(高版本的自己测试如果不报错,,就可以直接用)
kryo-1.03.jar
reflectasm-0.9.jar
minlog-1.2.jar
kryo-serializers-0.8.jar
memcached-2.5.jar
memcached-session-manager-tc7-1.5.1.jar
msm-kryo-serializer-1.5.1.jar
memcached-session-manager-1.5.1.jar
把以上8个包丢在tomcat的lib文件夹
修 改Tomcat的配置文件context.xml,调整成新的session存储方式,在配置文件中<context>标签内加入一下代码 (如果memcached跟tomcat不在同一台机器,修改127.0.0.1为memcached所在机器的IP):
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:127.0.0.1:11211"
sticky="false"
lockingMode="auto"
sessionBackupAsync="false"
sessionBackupTimeout="1000"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
在tomcat/conf/logging.properties 文件中添加de.javakaffee.web.msm.level=FINE , 就可以在
catalina.out 的日志中看到详细的session 存取情况。
一般前边还有Nginx做转发,分发给不同机器的tomcat上面,
五、启动服务,测试apache和tomcat协作。
测试Session共享用的 index.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ page import="java.util.*"%>
<html>
<head>
<title>Cluster App Test</title>
</head>
<body>
Server Info:
<%
out.println(request.getRemoteAddr() + " : " + request.getRemoteAddr() + "
");
%>
<%
out.println("
ID " + session.getId() + "
");
// 如果有新的 Session 属性设置
String dataName = request.getParameter("dataName");
if (dataName != null && dataName.length() > 0) {
String dataValue = request.getParameter("dataValue");
session.setAttribute(dataName, dataValue);
}
out.println("Session 列表
");
System.out.println("============================");
Enumeration e = session.getAttributeNames();
while (e.hasMoreElements()) {
String name = (String) e.nextElement();
String value = session.getAttribute(name).toString();
out.println(name + " = " + value + "
");
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>
2、测试均衡器
要想看到真正的效果,必须用一些压力测试工具,可用微软Microsoft Web Application Stress Tool进行简单压力测试,不然你靠不停刷新是体现不出来的,你只会在一个tomcat的控制台有输出结果。只用用压力测试工具模拟大量用户同时访问,你 会发现四个tomcat控制台均有打出控制信息,说明均衡器工作正常。
对于大在线量和高访问量的WEB应用系统而言,web集群的部署是必须的,而且也是必要的。针对Tomcat系列的web应用服务器的集群,通常是分为两 个部分,一个是访问负载,一个就是SESSION复制或同步。第二步不是必须的,但是有时候是必要的,关键是要看负载是采用什么样的策略了。比如采用 stick session策略,那么同一个用户的所有请求都由一个Tomcat实例来服务,那么也就不需要session复制了,但是同时也缺少了failover 的能力。我们今天主要讲的就是Tomcat的session复制功能的相关配置,至于访问负载等相关方面请参看LVS的集群配置等文档。