Apache+tomcat集群和负载均衡

1前言
    本文讲述了如何在Windows和Linux下进行Apahce+Tomcat集群的安装配置。
    Windows下Tomcat 集群的安装配置与Linux下稍有区别,本文分别进行了讲解。采用的例子为使用Apache作为集群的代理服务器,同时负责负载均衡,然后在两台机器上分别安装两一个Tomcat。如果在一台机器上安装多个Tomcat,需要对端口进行修改,以避免冲突。
    Apache接受用户的请求,并根据一定规则将请求转发到两台Tomcat中的一台。Tomcat执行请求后,将结果返回给Apache ,Apache再将结果返回给用户。

2 准备工作
2.1 需要的软件
2.1.1 Apache2.2

本文采用的版本为Apache HTTP Server (httpd) 2.2.19 ,即目前最好用的版本。下载地址http://httpd.apache.org/download.cgi,请分别下载windows和linux版本。
使用Apache2.0或者更低版本时,需要单独安装mod_jk,且配置起来比较繁琐。本文采用的Apache2.2版本已经内置了安装集群所必须的模块,配置更简单。
2.1.2 Tomcat6
本文使用的Tomcat版本,Windows是apache-tomcat-6.0.18,linux是apache-tomcat-6.0.32。
2.2 准备机器
实际应用中,每个Tomcat实例一般部署在单独的机器上,且这些机器需要在同一网段。
本文中两台机器情况如下:第一台机器操作系统Windows,IP为192.168.106.57,安装一个Tomcat,第二台机器操作系统linux,IP为192.168.106.14,安装一个Tomcat和 Apahce。
为了实现session复制,需要注意以下两点:
1. 各tomcat实例需在同一网段下。
2. 所有的session attributes必须实例java.io.Serializable接口。
3 安装软件
3.1 Apache安装
3.1.1 Windows下安装

把Apache安装为运行在80端口的Windows服务,安装成功后在系统服务列表中可以看到Apache2.2服务。服务启动后在浏览器中输入http://localhost进行测试,如果能看到"It works!"的页面就代表Apache已经正常工作了。
3.1.2 Linux下安装
1. 解压文件:
文件 httpd-2.2.18.tar.gz放置在/home/tools/下,我们首先解压它。

[root@localhost ~]#cd /home/tools/ 
[root@localhost tools]#tar xzvf httpd-2.2.19.tar.gz

2. 配置安装文件:
安装文件我们想把 apache安装到/opt/apache2目录下,让apache启用DSO ,同时启用“proxy proxy_http proxy_ftp proxy_connect proxy_balancer headers”这六个模块。其中 headers不是集群必须的,但是对今后 apache 的应用有好处。

[root@localhost tools]#cd httpd-2.2.18 
[root@localhost httpd-2.2.18]#./configure --prefix=/opt/apache2 --enable-so --enable-mods-shared="proxy proxy_http proxy_ftp proxy_connect proxy_balancer headers"

3. 编译安装:

[root@localhost httpd-2.2.18]#make 
[root@localhost httpd-2.2.18]#make install 

make命令读取配置文件进行编译,编译需要花费不短的时间。make install负责安装。
4. 测试一下:
通过命令启动:

Apache[root@localhost httpd-2.2.18]#cd /opt/apache2/bin 
[root@localhost bin]#./apachectl -k start

在浏览器中输入http://192.168.106.41,如果能看到"It works!"的页面就代表Apache已经正常工作了。
停止命令:[root@localhost bin]#./apachectl -k stop
3.2 Tomcat安装
3.2.1 Windows安装

解压apache-tomcat-6.0.18.zip即可。
3.2.2 Linux安装
首先,将文件 apache-tomcat-6.0.32.tar.gz 拷贝到/opt下:

[root@localhost opt]#cp /home/tools/apache-tomcat-6.0.32.tar.gz /opt 

解压:

[root@localhost opt]#tar xzvf apache-tomcat-6.0.32.tar.gz

4 配置过程
4.1 Apache配置

Apahce的配置包含两个方面:虚拟主机和集群配置。
4.1.1 虚拟主机
1. 在Apache安装目录下找到conf/httpd.conf文件,去掉以下文本的注释,以便让Apache在启动时自动加载代理(proxy)模块

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.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
在linux环境中,此配置在Apache安装过程的第二步已经配置好。
2. 找到Include conf/extra/httpd-vhosts.conf,去掉前面的注释符
3. 打开conf/extra/httpd-vhosts.conf,配置虚拟站点,在最下面加上如下内容:
<VirtualHost *:80>   
ServerAdmin 邮箱地址
ServerName 服务器名称
ServerAlias localhost
ProxyPass / balancer://cluster/ stickysession=jsessionid nofailover=On   
ProxyPassReverse / balancer://cluster/   
ErrorLog "logs/clustertest-error.log"  
CustomLog "logs/clustertest-access.log" common  
</VirtualHost>
其中的的virtualHost*:80为HttpServer监听端口。
ServerAdmin:管理员邮箱
ServerName: 服务器名称
ServerAlias: 配置服务器域名或IP,如果有多个域名或者域名和IP同时使用,则使用空格隔开。
ProxyPass / balancer:// 是告诉Apache需要进行负载均衡的代理,后面的cluster是集群名,可以随意取,转发时带上session的名称。
ProxyPassReverse这行配置的含义是,使Apache调整HTTP重定向应答中Location, Content-Location, URI头里的URL。这样可以避免在Apache作为反向代理使用时,后端服务器的HTTP重定向造成的绕过反向代理的问题。
两个日志引擎日志名可以自己取
ErrorLog负责记录错误日志
CustomLog负责记录所有的http访问以及返回状态
4.1.2 集群配置
在conf/httpd.conf文件最下面加上
ProxyRequests Off
<proxy balancer://cluster> 
  BalancerMember ajp://192.168.24.87:8009 loadfactor=1 route=jvm1 
  BalancerMember ajp://192.168.106.14:8009 loadfactor=1 route=jvm2 
</proxy>
ProxyRequests: Off告诉Apache关闭正向代理,使用反向代理,用于配置工作在tomcat集群中的所有节点。
这里的"cluster"必须与上面的集群名保持一致。
BalancerMember: Apache通过ajp协议与tomcat进行通信,ip地址和端口唯一确定了tomcat节点和配置的ajp接受端口。loadfactor是负载因子,Apache会按负载因子的比例向后端tomcat节点转发请求,负载因子越大,对应的tomcat服务器就会处理越多的请求,如两个tomcat都是1,Apache就按1:1的比例转发,如果是2和1就按2:1的比例转发。route参数对应后续tomcat配置中的引擎路径(jvmRoute)。
重启Apache服务,如果此时访问http://localhost/将会返回503错误,打开刚才配置的错误日志logs/lbtest-error.log,可以看到错误原因是因为后台服务器没有响应,因为此时tomcat尚未配置和启动。
4.2 Tomcat配置
修改每个Tomcat实例的配置文件。Tomcat/conf/server.xml
1. 配置Engine。Tomcat默认的Engine配置为
<Engine name="Catalina" defaultHost="localhost">
将其注释掉,并使用默认被注释的
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
这里jvmRoute="jvm1"对应前面Apache集群配置里的route=jvm1,这是192.168.106.57的Tomcat配置,192.168.106.14中的配置为:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm2">
2. 配置AJP Connector,这里是Apache和Tomcat链接的关键,前台的apache就是通过AJP协议与Tomcat进行通信的,以完成负载均衡作用。
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
port="8009"和在前面Apache里面配置的AJP端口一样。
3. 配置Cluster,默认Cluster配置被注释掉了,去掉注释:
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" />
这里的配置可以在集群中的所有Tomcat节点间通过复制session共享会话(Session)。但是经过测试session复制不稳定,压力较大的情况下出现了session丢失的情况。其实以上是tomcat6的简化配置,它相当于以下配置的简写:
<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="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      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"/>
          </Channel>

          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=""/>
          <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>
其中的两个配置需要去掉:
1) 阀
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
2) Listener
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
以上两个配置是在使用mod_jk 并且没有用sticky sessions或者sticky sessions无法正常工作时的解决方案,我们没有用mod_jk,也就出了现压力较大时session复制失败的情况。因此,我们需要将上面的详细配置替换tomcat6中简化配置,并将上述两条配置去掉。
4. 注意,如果Tomcat在同一台机子上,需要修改Tomcat的启动端口、关闭端口、AJP Connector端口,以避免端口冲突。
4.3 Web工程配置
在Web工程的web.xml里面加入<distributable/>,这样可以通知Tomcat服务器,当前应用需要在集群中的所有节点间实现Session共享。
5 注意
1. 所有Tomcat实例必须在同一个网段。
2. 在同一台机子的Tomcat需要注意以下端口避免冲突。
a) Server port
b) Http的connector port
c) AJP的Connector port
d) Receiver的port
3. Session的attribute中的对象应实现java.io.Serializable接口,否则无法实现同步。
4. Linux中应打开组播功能
6 验证一下
新建Web应用cluster-demo,在WBE-INF下新建web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

  <distributable/>
  
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>
新建index.jsp:
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <head>
    <title>cluster测试</title>
</head>

<body>
<%
	out.println("this is tomcat1");//在另一台机子上为”this is tomcat2”
	
	String sessionid = session.getId();
	out.println("sessionid = " + sessionid);
%>
</body>
</html>

在浏览器地址栏中输入http://localhost/cluster-demo,查看“tomcat1”和“tomcat2”是否按照1:1的比例切换,即是否实现了负载均衡,两个tomcat的sessionid是否一致。
7 参考资料

在写本文的时候,在参考了一下两个地方:
Tomcat关于集群文档http://tomcat.apache.org/tomcat-6.0-doc/cluster-howto.html
Apache2.2中文文档http://ajava.org/online/apacheMenu2.2/index.html

同时,我上网查询了大量的文章博客,非常感谢你们提供的资料。

你可能感兴趣的:(apache,tomcat)