Apache+Tomcat集群搭建以及负载均衡实现
Apache安装及配置:http://my.oschina.net/lengchuan/blog/731412。
Apache+Tomcat集成的方法有3种:
- jk
- jk_proxy
- http_proxy
我们使用jk的方式。
安装
安装mod_jk
更多关于mod_jk的内容请参考:http://tomcat.apache.org/connectors-doc/。 除了apache和tomcat,我们还需要apache和tomcat的连接器mod_jk,这里就不讲解有关apache和tomcat 的安装过程了,我们看一下mod_jk的安装。
wget http://apache.fayea.com/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.41-src.tar.gz
tar -zxvf tomcat-connectors-1.2.41-src.tar.gz
cd tomcat-connectors-1.2.41-src/native
./configure --with-apxs=/usr/local/apache2/bin/apxs #我的apache安装在/usr/local/apache2/
make
sudo cp apache-2.0/mod_jk.so /usr/local/apache2/modules/
配置
Apache配置
- 因为先安装了mod_jk模块,先配置下Apache,在apache的配置文件目录下添加:
-
新建mod_jk的配置文件:
sudo vi mod_jk.conf
添加下面的内容:
更多配置请参考:http://tomcat.apache.org/connectors-doc/webserver_howto/apache.html。
#指定workers.properties的位置 JkWorkersFile /usr/local/apache2/conf/workers.properties #指定jk的日志输出文件 JkLogFile /usr/local/apache2/logs/mod_jk.log #指定日志级别 JkLogLevel info #指定日志输出的时间戳格式 JkLogStampFormat "[%a %b %d %H:%M:%S %Y]" #指定日志中时间戳后面的内容:%w:工作的tomcat实例 %V:目标ip %T:耗时 JkRequestLogFormat "%w %V %T" #所有的jsp文件都交给worker1处理,我们可以写多个JkMount JkMount /*.jsp worker1 JkMount /*.do worker1
-
新建workers.properties,这是tomcat工作的配置文件:
sudo vi workers.properties
添加下面的内容:
这里只是给出基本的配置,更多配置请参考:http://tomcat.apache.org/connectors-doc/reference/workers.html。
#指定需要工作的tomcat,如多个用“,”分割 worker.list=worker1 #指定worker1使用ajpv13协议与Tomcat进程通讯 worker.worker1.type=ajp13 #指定worker1的位置 worker.worker1.host=localhost #指定worker1的工作端口 worker.worker1.port=8009 #此配置项为当Apache和Tomcat之间有防火墙时,让os每隔多久想未激活的连接发送KEEP_ALIVE信息,防止防火墙切断未激活的网络连接 worker.worker1.socket_keepalive=1 #指定worker1上的连接在未激活的状况下持续多久,Apache将主动切断 worker.worker1.socket_timeout=300
- 修改Apache的主配置文件httpd.conf
sudo vi httpd.conf
找到DirectoryIndex这一项,添加 index.jsp
DirectoryIndex index.html index.jsp
- 修改DocumentRoot
DocumentRoot "/www/lengchuan/test/"
- 修改< Directory >
<Directory "/www/lengchuan/test/">
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
</Directory>
- 加载mod_jk以及配置文件
我们在最后添加:
#加载mod_jk
LoadModule jk_module modules/mod_jk.so
#包含mod_jk的配置文件
Include /usr/local/apache2/conf/mod_jk.conf
- 检查配置文件是否正确
apachectl -t
Tomcat配置
这里我们只做简单的配置,就只是修改server.xml文件。
- 找到< Host >
-
修改为:
<Host name="localhost" appBase="/www/lengchuan/test/" unpackWARs="true" autoDeploy="true">
-
在< Host >后面添加:
<Host name="localhost" appBase="/www/lengchuan/test/" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="test1" reloadable="true" crossContext="true" />
测试
- 添加测试文件
sudo mkdir /www/lengchuan/test/test1
sudo vi /www/lengchuan/test/test1/index.jsp
输入:
Hello world!!! <%= new java.util.Date()%>
- 启动Tomcat和Apache
sh /opt/apache-tomcat-7.0.68/bin/startup.sh
sudo apachectl -k start
- 查看页面
使用ip地址:/tets1/index.jsp,比如我这里是192.168.2.87/test1/index.jsp就可以查看结果了。
负载均衡
现在我们已经把一个tomcat和Apache集成了,接下来我们来看看怎么实现负载均衡。
- 水平集群:在不同的服务器上安装tomcat,而且只安装一个。
- 垂直集群:在同一台服务器上安装多个tomcat。
条件限制,我们就采用垂直集群的方式。
- 先创建几个tomcat
sudo cp -r /opt/apache-tomcat-7.0.68/ /opt/tomcat1
sudo cp -r /opt/apache-tomcat-7.0.68/ /opt/tomcat2
- 修改tomcat AJP端口 我们现在已经有3个tomcat了,默认的ajp端口是8009,我们把tomcat1和tomca2的端口改为8019 和8029
修改tomcat配置文件server.xml,
-
修改监听端口< Server >
<Server port="8005" shutdown="SHUTDOWN">
默认的端口是8005,我这里把tomcat1和tomcat2修改为8105,8205。
-
修改HTTP服务配置
tomcat1:
<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
tomcat2:
<Connector port="8082" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
-
修改ajp协议配置
tomcat1:
<Connector port="8019" protocol="AJP/1.3" redirectPort="8443" />
tomcat2:
<Connector port="8029" protocol="AJP/1.3" redirectPort="8443" />
-
- 配置workers.properties
我们之前已经在workers.properties里面配置了一个tomcat,我们现在把tomcat1和tomcat2也添加进去。
sudo vi /usr/local/apache2/conf/workers.properties
添加下面的内容:
更多配置详情请参考:http://tomcat.apache.org/connectors-doc/reference/workers.html。
#指定需要工作的tomcat,如多个用“,”分割
worker.list=controller,worker1,tomcat1,tomcat2
##-------worker1------##
#worker1是我们之前已经配置好的
#指定worker1使用ajpv13协议与Tomcat进程通讯
worker.worker1.type=ajp13
#指定worker1的位置
worker.worker1.host=localhost
#指定worker1的工作端口
worker.worker1.port=8009
#此配置项为当Apache和Tomcat之间有防火墙时,让os每隔多久想未激活的连接发送KEEP_ALIVE信息,防止防火墙切断未激活的网络连接
worker.worker1.socket_keepalive=1
#指定worker1上的连接在未激活的状况下持续多久,Apache将主动切断
worker.worker1.socket_timeout=300
#负载均衡因子
worker.worker1.lbfactor=1
##-------tomcat1------##
worker.tomcat1.type=ajp13
worker.tomcat1.host=localhost
worker.tomcat1.port=8019
worker.tomcat1.socket_keepalive=1
worker.tomcat1.socket_timeout=300
worker.tomcat1.lbfactor=2
##-------tomcat2------##
worker.tomcat2.type=ajp13
worker.tomcat2.host=localhost
worker.tomcat2.port=8029
worker.tomcat2.socket_keepalive=1
worker.tomcat2.socket_timeout=300
worker.tomcat2.lbfactor=3
##-------controller------##
#controller是作为一个负载均衡控制器
#表明这是一个负载均衡控制器
worker.controller.type=lb
#controller这个负载均衡器需要管理的tomcat列表
#mod_jk1.2.7以前是balanced_workers,多了一个d
worker.controller.balance_workers=worker1,tomcat1,tomcat2
#session管理策略,关于session管理的各种策略,这里不做讨论
worker.controller.sticky_session=true
- 配置mod_jk.conf
修改为:
#指定workers.properties的位置
JkWorkersFile /usr/local/apache2/conf/workers.properties
#指定jk的日志输出文件
JkLogFile /usr/local/apache2/logs/mod_jk.log
#指定日志级别
JkLogLevel info
#指定日志输出的时间戳格式
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
#指定日志中时间戳后面的内容:%w:工作的tomcat实例 %V:目标ip %T:耗时
JkRequestLogFormat "%w %V %T"
#所有的jsp文件都交给controller处理,我们可以写多个JkMount
JkMount /*.jsp controller
JkMount /*.do controller
- 测试负载均衡
现在我们已经搭建好了3个tomcat的负载均衡,我们先来测试下。
我们新建一个session.jsp文件
```
sudo vi /www/lengchuan/test/test1/session.jsp
```
然后添加下面的内容:
```
sessionid: <%=session.getId()%><br>
servername: <%=request.getServerName()%><br>
serverport: <%=request.getServerPort()%>
```
启动tomcat和Apache
```
sudo sh /opt/apache-tomcat-7.0.68/bin/startup.sh
sudo sh /opt/tomcat1/bin/startup.sh
sudo sh /opt/tomcat2/bin/startup.sh
sudo apachectl -k start
```
用浏览器访问ip:/test1/session.jsp,我们发现每次访问的时候sessionid都不尽然相同,下面我们来实现session同步的配置。
### tomcat集群配置
配置了负载均衡,我们还需要解决session同步的问题。我们采用session复制的策略,比如一个用户访问了tomcat1,我们就把这个在tomcat1产生的session复制到其它两个tomcat中去。
- 修改各个tomcat的server.xml,进行集群配置。找到< Cluster >部分。
更多关于tomcat集群的配置请看:<http://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html>。
我们使用默认的配置,
除以之外,我们需要配置jvmRoute,因为我们这里使用的是粘性session(sticky_session),并且jvmRoute必须与worker的名字相同。
- worker1:
```
<Engine name="Catalina" defaultHost="localhost" jvmRoute="worker1">
```
```
<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>
```
- tomcat1:
```
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
```
```
<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="4001"
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>
```
- tomcat2:
```
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
```
```
<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="4002"
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>
```
现在重启tomcat和apache,访问ip:/test1/session.jsp,我们可以看到session已经同步了,因为我们采用的是粘性session的方式, 所以这里我们看不出来什么区别,之后会写一篇关于tomcat集群session共享的博文。
web.xml配置
通常我们的web项目都会有web.xml配置文件,我们需要在web.xml中添加一条配置来让我们的应用支持集群
<distributable/>