Apache+Tomcat集群配置

来源:互联网 发布:java 2ee与java ee 编辑:程序博客网 时间:2024/04/28 04:44

一、    技术基础

 

Apache和Tomcat同是Apache基金会下面的两个项目。一个是HTTP WEB服务器,另一个是servlet容器(servlet container),最新的5.5.X系列实现Servlet 2.4/JSP 2.0Spec,一般也可以把Tomcat看做是应用服务器。

 

Apache是目前比较受欢迎的网站服务器软件,它不但功能强大,而且完全免费,并且支持市场上流行的各种操作系统(Windows,Linux,Mac os)。

 

Tomcat也是Apache出品的,应用于对Java Servlet/JSP的支持的应用服务器。Tomcat除了支持Java Servlet/JSP之外,也可以当做网站服务器使用。

 

但是在对于静态的html文件、图片文件等的解析效率上不如Apache的执行效率高。例如应用tomcat的服务器如果网站的访问量较大,系统资源占用会明显升高,服务器负担会加重,从而导致系统或服务器崩溃。


  因此在实际应用中,常常把Tomcat与Apache集成。当Tomcat与Apache集成时,Apache负责静态资源处理,tomcat负责jsp和javaservlet等动态资源的处理。在我们生产的环境中,往往需要Apache做前端服务器,Tomcat做后端服务器。此时我们就需要一个连接器,这个连接器的作用就是把所有Servlet/JSP的请求转给Tomcat来处理。Tomcat服务器的工作模式通常为进程外的Servlet容器,Tomcat服务器与Apache之间通过专门的插件来通信。

 

利用apache来解析*.html  *.htm *.jpg  *.gif  *.js等静态网页与内容

当遇到*.jsp,* servlet和*.do时,通过一个apache中的module把这些内容抛给Tomcat来处理。

 

第一个连接器监听8080端口,负责建立HTTP连接。在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器。
  
  第二个连接器监听8009端口,负责和其他的HTTP服务器建立连接。在把Tomcat与其他HTTP服务器集成时,就需要用到这个连接器。
  
 

 Web客户访问Tomcat服务器上JSP组件的两种方式如图所示:

 

 

 

二、    环境说明

       Apache:  apache_2.2.2    

       Tomcat: apache-tomcat-5.5.17 (zip版)    

mod_jk:  mod_jk-apache-2.2.4.so(Apache与Tomcat通信的插件)

      操作系统:windows XP或windows 2K

 

 

三、    具体步骤

 

第一部分:负载均衡

  负载均衡,就是apache将客户请求均衡的分给tomcat1,tomcat2....等多个服务器的多个不同的Tomcat去处理!如此就把单个Tomcat的负担降到最低了!

1. 安装apche,tomcat

注意:安装apache时必须写明主机地址或域名,邮箱随便填

假设有两台机器负载,那么各装1个tomcat

2.在apache安装目录下conf目录中找到http.conf

在文件最后加上下面一句话就可以了(假设我的apache在E:\ide\apache目录下)

      include"E:\ide\apache\conf\mod_jk.conf"

       作用:加入这句话指定mod_jk配置文件路径。

              3.  http.conf 同目录下新建mod_jk.conf文件,内容如下

  

#加载mod_jk Module(把mod_jk-apache-2.2.4.so拷贝到E:\ide\apache\modules文件夹)
LoadModule jk_module modules/mod_jk-apache-2.2.4.so

#指定 workers.properties文件路径
JkWorkersFile conf/workers.properties

#指定把哪些请求交给tomcat处理,"controller"为在workers.propertise里指定的负载分配控制器

JkMount /*.jsp controller

JKMount /*.do controller

JKMount /*servlet controller(注:为了配置方便,务必使servlet都以servlet结尾)

 

---备注:这里也可以设置是否把*.jpg,*.js,*.html,*.htm,*.txt,*.gif, *.xml, *.dtd……等静态内容的请求交给tomcat处理(最好不这样处理),一般都是静态内容给apache而动态内容给tomcat,那么只要在这里分配*.jsp,*.do,*servlet等这些动态内容给tomcat即可,其他静态内容给apache处理,具体的配置路径请见注意事项2。

      

      

作用:配置插件与属性文件并且处理各种请求格式的分配

 

4. 在http.conf同目录下新建 workers.properties文件,内容如下:

 

worker.list = controller,tomcat1,tomcat2  #server 列表,命名controller与mod_jk.conf文件中的controller相对应

#========tomcat1========

worker.tomcat1.port=8009        #ajp13 端口号,在tomcat下server.xml配置,默认8009,ajp为tomcat与apache通讯协议
worker.tomcat1.host=localhost  #tomcat所在主机地址,如不为本机,请填写ip地址


worker.tomcat1.type=ajp13    #使用ajp13协议
worker.tomcat1.lbfactor = 1  
#server的加权比重,值越高,分得的请求越多,都为1时为平均分配

 

 

 

#========tomcat2========

worker.tomcat2.port=8009      #ajp13 端口号,在tomcat下server.xml配置,默认8009,ajp为tomcat与apache通讯协议

(ps:若有端口冲突,请在tomcat/conf/server.xml文件中的<connector port=”8009”

enableLookups=”false” redirectPort="8443"protocol="AJP/1.3" />改为

<connectorport=”9009”  enableLookups=”false”  redirectPort="8443"protocol="AJP/1.3" />然后把worker.tomcat2.port=8009改为worker.tomcat2.port=9009)

worker.tomcat2.host=localhost  #tomcat所在主机地址,如不为本机,请填写ip地址
worker.tomcat2.type=ajp13   #使用ajp13协议
worker.tomcat2.lbfactor = 1  
#server的加权比重,值越高,分得的请求越多,都为1时为平均分配


#========controller负载均衡控制器========
worker.controller.type=lb
worker.controller.balanced_workers=tomcat1,tomcat2  
#指定分担请求的tomcat
worker.controller.sticky_session=1#允许负载均衡控制器复制session

   5. 编写一个测试jsp

       建立一个目录test.里面新建一个test.jsp,内容为

<%
   System.out.println("===========================");
%>

把test放到tomcat1,tomcat2的webapps下

 

   6. 启动apache,tomcat1,tomcat2,进行测试

       通过 http://(apache配置时候的主机地址)/test/test.jsp 访问,查看tomcat1的窗口,可以看到打印了一行"=========="

再刷新一次,tomcat2也打印了一条,再刷新,可以看到请求会被tomcat1,tomcat2轮流处理,实现了负载均衡!

 

 

第二部分,配置集群

只配置负载均衡还不行,还要session复制,也就是说其中任何一个tomcat的添加的session,是要同步复制到其它tomcat, 集群内的tomcat都有相同的session

1. 修改tomcat1, tomcat2的server.xml

将集群部分配置的在注释符删掉即可.

集群部分的配置如下:(只要把此部分的注释符去掉即可)

<ClusterclassName="org.apache.catalina.cluster.tcp.SimpleTcpCluster"

                managerClassName="org.apache.catalina.cluster.session.DeltaManager"

                 expireSessionsOnShutdown="false"

                 useDirtyFlag="true"

                notifyListenersOnReplication="true">

 

            <Membership

               className="org.apache.catalina.cluster.mcast.McastService"

                mcastAddr="228.0.0.4"

                mcastPort="45564"

                mcastFrequency="500"

               mcastDropTime="3000"/>

 

            <Receiver

               className="org.apache.catalina.cluster.tcp.ReplicationListener"

               tcpListenAddress="auto"

                tcpListenPort="4001"

               tcpSelectorTimeout="100"

               tcpThreadCount="6"/>

 

            <Sender

               className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"

               replicationMode="pooled"

                ackTimeout="15000"

               waitForAck="true"/>

 

            <ValveclassName="org.apache.catalina.cluster.tcp.ReplicationValve"

                  filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>

                  

            <DeployerclassName="org.apache.catalina.cluster.deploy.FarmWarDeployer"

                     tempDir="/tmp/war-temp/"

                     deployDir="/tmp/war-deploy/"

                     watchDir="/tmp/war-listen/"

                      watchEnabled="false"/>

                     

            <ClusterListenerclassName="org.apache.catalina.cluster.session.ClusterSessionListener"/>

        </Cluster>

如图所示:

注:这种集群配置方法会使得多个不同的tomcat每步操作都轮流执行命令,而session也会共享,且互相不影响执行效果!

另外,可以关注一下如果想要一个tomcat始终负责一个session到其生命周期结束或网页关闭,然后另一个tomcat负责下一个session到其生命周期结束或网页关闭。这也是一种轮流操作,只不过这种操作是轮流session操作,要想得到这种效果,必须设置jvmRoute(给控制器设置序列),方法如下:

在tomcat的conf中的server.xml文件中修改如下:

<Enginename="Catalina" defaultHost="localhost"jvmRoute="tomcat2">

 

 

如图所示:

2.修改测试项目test

修改刚才的test/test.jsp,内容如下

  <%@ page contentType="text/html;charset=GBK" %>
<%@ page import="java.util.*" %>
<html><head><title>Cluster AppTest</title></head>
<body>
Server Info:
<%
out.println(request.getLocalAddr() + " : " +request.getLocalPort()+"<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>");

  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">
    名称:<inputtype=text size=20 name="dataName">
     <br>
    值:<input type=text size=20name="dataValue">
     <br>
    <input type=submit>
   </form>
</body>
</html>

然后在test目录 新建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/j2eehttp://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"version="2.4">
      <display-name>TomcatDemo</display-name>
      <distributable/>
</web-app>

注意:如果是你自己的应用程序的话,那么在你的应用程序的web.xml加入  <distributable/>就是表示此工程会被允许让tomcat复制session!(重点,如果忘记加distributable那么会造成session无法复制的问题!)

ok,重启apache,tomcat1,tomcat2,

输入网址 http://(apache配置时候的主机地址)/test/test.jsp  

3.测试结果

先输入一个session提交,然后不输直接提交,只要可以在后台看到两边的tomcat会都有同一个session的信息显示,那么session复制就成功了!

四、    注意事项

 

以下针对本公司的upload工程做进一步的注意事项介绍:

 

1.  配置apache时要注意配置好apache机器的网络地址或域名

 

2.  为了直接打网址就可以打开工程主页可以把Tomcat中webapps\ROOT文件全部删除后把自己工程目录内的文件复制进ROOT文件夹—就是把tomcat中绑定的upload工程目录下的所有文件和文件夹放进ROOT目录内即可,即把ROOT目录看作是upload工程目录。

 

 

把Apache中的htdocs文件夹原来的文件删除掉,然后把自己的工程目录内的静态文件夹以及文件复制进htdocs文件夹即可:

 

 

 

以upload为例,具体目录结构如下所示:

htdocs(相当于eclipse中upload工程的主目录upload)

      

pages(upload工程目录中的pages文件夹以及此文件夹中所有静态内容)

          upload(upload工程目录中的upload文件夹以及此文件夹中所有静态内容)

 

       其次还要进行一项配置:在apache/conf/httpd.conf中修改如下:

       <IfModule dir_module>

        DirectoryIndexindex.html,192.168.1.112/upload/index.jsp

</IfModule>

即添加一个upload工程内的index.jsp首页,那么你在地址栏打192.168.1.112即可显示整个工程页面了!

3.  由于某些servlet没有以servlet结尾,那么必须把每个servlet的全名写进mod_jk.conf的指定请求处理中,否则不会识别servlet,具体如下:

JkMount /*checkUserName controller

JkMount /*UploadServlet controller

JkMount /*getUploadInfo controller

JkMount /*getAppendUploadInfocontroller

JkMount /*getFileInfo controller

JkMount /*insertFileInfo controller

JkMount /*getGroupUploadInfo controller

JkMount /*getGroupAppendUploadInfocontroller

JkMount /*insertGroupFileInfocontroller

JkMount /*updateFileInfo controller

JkMount /*initUid controller

JkMount /*userAction.zip controller

JkMount /*UploadFileNormal controller

 

 

4.由于本项目使用了url改写,导致mod_jk.conf中无法识别改写后的页面,

解决方法:把WEB-ROOT下的urlrewrite.xml具体如下修改(以.shtml为后缀)

/user/(.*)/([0-9]+).shtml$

/user/(.*)\.shtml

/group/(.*)\.shtml

为了匹配后缀为.shtml必须修改一些使用过url改写的页面,具体需要修改的页面统计如下:

Tomcat中的jsp页面中:

upload/pages/registerSuccess.jsp

upload/pages/loginsuccess.jsp

upload/pages/space/spacefiles.jsp

upload/pages/index2.jsp

upload/pages/main2.0/navi.jsp(有两层)

以上jsp中均把改写的url地址后面加上后缀.shtml。

Apache中的js文件中:

upload/pages/main2.0/js/navi_control.js修改uid后加.shtml。

 

5.图片上传的问题:由于网页上传图片后原先是存储在tomcat中某个文件夹中,而集群配置后会有两个问题,一:图片不应该存放在tomcat中而应该存放在apache中某文件夹中,因为图片是静态内容 二:即使是存放在apache中当tomcat与apache不在同一机器上时上传图片也会很困难。

解决方法:使用socket通信编程,当上传图片读图片时就把图片通过socket传送给apache的服务器中的另外一个tomcat工程ImageServer,此工程会根据配置情况把图片写入apache中固定的存放图片的月份目录中,并且在上传图片同时把图片的存放相对路径存入数据库中,按月份定义图片目录。

 

 

注意:

1:在userAction中注意给文件目录加月份

2:由于此tomcat工程ImageServer是使用另外一个tomcat,因此注意此tomcat必须改下端口,比如9080

目前有两处图片上传:

1:个人头像图片上传

2:个人收藏图片上传

 

五、    优化建议

 

Tomcat优化方法

第一部分:---线程

Tomcat当线程加到150时服务端就会抛出socket资源用尽的错误,根本没法再往上加,响应的速度也是相当的慢,在server.xml中修改一部分,增加节点数目,可以很好的提高性能:

  <Connector port="8080"maxHttpHeaderSize="8192" maxThreads="150"
   minSpareThreads="30"maxSpareThreads="75"enableLookups="false"
   redirectPort="8443" acceptCount="100" connectionTimeout="20000"
   disableUploadTimeout="true" />
  以上为默认配置,适当修改红色字体部分的值,几个参数意义分别为:

maxThreads:Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数。
acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。
connnectionTimeout:网络连接超时,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。通常可设置为30000毫秒。
minSpareThreads:Tomcat初始化时创建的线程数。
maxSpareThreads:一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程

 

第二部分:---内存

Tomcat默认可以使用的内存为128MB,在较大型的应用项目中,这点内存是不够的,需要调大。

Windows下,在文件{tomcat_home}/bin/catalina.bat,第一行加上:

set JAVA_OPTS='-Xms
【初始化内存大小】 -Xmx【可以使用的最大内存】'

  需要把这个两个参数值调大。例如:

set JAVA_OPTS=-Xms256m -Xmx512m

  表示初始化内存为256MB,可以使用的最大内存为512MB

  另外相关JVM堆大小的调整,需要考虑的是Java提供的垃圾回收机制。虚拟机的堆大小决定了虚拟机花费在收集垃圾上的时间和频度。收集垃圾可以接受的速度与应用有关,应该通过分析实际的垃圾收集的时间和频率来调整。如果堆的大小很大,那么完全垃圾收集就会很慢,但是频度会降低。如果你把堆的大小和内存的需要一致,完全收集就很快,但是会更加频繁。调整堆大小的目的是最小化垃圾收集的时间,以在特定的时间内最大化处理客户的请求。在基准测试的时候,为保证最好的性能,要把堆的大小设大,保证垃圾收集不在整个基准测试的过程中出现。

  如果系统花费很多的时间收集垃圾,请减小堆大小。一次完全的垃圾收集应该不超过 3-5秒。如果垃圾收集成为瓶颈,那么需要指定代的大小,检查垃圾收集的详细输出,研究垃圾收集参数对性能的影响。一般说来,你应该使用物理内存的 80%作为堆大小。当增加处理器时,记得增加内存,因为分配可以并行进行,而垃圾收集不是并行的。

       一般来说设置为256m-512m就可以优化JVM堆。

 

Apache的优化方法

在apache1.3版本,大家常用mod_gzip对输出内容进行压缩,现在主流的浏览器都支持gzip解压缩。在apache2下,这个模块换名为mod_deflate,对应的模块文件名是mod_deflate.so。下面描述一下在Apache2下如何启用并配置mod_deflate模块。默认安装的Apache不管是Windows还是Linux/Unix,都是不启用该模块的, Linux/Unix下甚至不带该模块,你需要手工编译这个模块。

下面我们分别介绍在Windows操作系统下如何启用并配置mod_deflate模块。

在Windows下采用安装程序安装的Apache服务器已经带有deflate所需要的模块 mod_deflate.so和mod_headers.so,我们只需要在httpd.conf配置文件中启用并进行相关的配置即可,配置如下:

LoadModule deflate_module modules/mod_deflate.so
LoadModule headers_module modules/mod_headers.so

# Insert filter
SetOutputFilter DEFLATE
# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html
# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4\.0[678] no-gzip
# MSIE masquerades as Netscape, but it is fine
# BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
# the above regex won't work. You can use the following
# workaround to get the desired effect:
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
# Don't compress images
SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary
# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary

0 0