`

Apache + Tomcat集群配置

 
阅读更多
Tomcat服务器集群与负载均衡实现  http://my.oschina.net/xianggao/blog/87469


关于Session
使用Apache搭建Sticky模式的Tomcat集群 http://ajita.iteye.com/blog/1848665
Apache配置tomcat负载和session粘连(stickysession) http://wwwcomy.iteye.com/blog/1909211


ProxyPass: 硬编码配置方式
ProxyPassMatch: 正则表达式配置方式



奇葩的Permission denied问题
在centos7或者fedora22里面,如果Selinux打开,并且负载均衡的时候,修改了8009端口,tail -f -n200 /etc/httpd/logs/lbtest-access.log​​,那么会碰到
[Mon Sep 14 20:54:35.873664 2015] [proxy:error] [pid 2618] (13)Permission denied: AH00957: AJP: attempt to connect to 192.168.0.198:8681 (192.168.0.198) failed
[Mon Sep 14 20:54:35.873773 2015] [proxy:error] [pid 2618] AH00959: ap_proxy_connect_backend disabling worker for (192.168.0.198) for 60s
[Mon Sep 14 20:54:35.873790 2015] [proxy_ajp:error] [pid 2618] [client 127.0.0.1:40870] AH00896: failed to make connection to backend: 192.168.0.198

找了一个晚上,终于发现http://sysadminsjourney.com/content/2010/02/01/apache-modproxy-error-13permission-denied-error-rhel/,执行setsebool -P httpd_can_network_connect 1,就能改变了Selinux的配置了,就解决问题了.


Apache 2.2
以下是Apache 2.2集群方法
Apache和Tomcat 配置负载均衡(mod-proxy方式) http://blog.csdn.net/wangjunjun2008/article/details/38268483
Apache + Tomcat集群配置详解 (1) http://zyycaesar.iteye.com/blog/294089
Apache + Tomcat集群配置详解 (2) http://zyycaesar.iteye.com/blog/295227
Tomcat 集群 http://publib.boulder.ibm.com/wasce/V2.1/zh_CN/configuring-tomcat-native-clusters.html
配置过程:
apache 2.x版本, 参考:http://blog.csdn.net/wangjunjun2008/article/details/38268483 
#######################################################
上传集群测试工程:test到webapp下面
vim /home/tomcat/server/tomcat7/webapps/test/index.jsp   修改标记title等信息.  方便测试

1. 配置Apache[位置于IP1]:
vim /etc/httpd/conf/httpd.conf
#---------------------start------------------------ 
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

#----------------------end---------------------

如果你想看到小猫页面
DirectoryIndex index.html index.jsp index.html.var

在文件末尾加反向代理配置文件
Include conf/httpd-vhosts.conf

在文件末尾加文档最下面加上
ProxyRequests Off 
<proxy balancer://cluster> 
    BalancerMember ajp://ip1:8009 loadfactor=1 route=jvm1
    BalancerMember ajp://ip2:8009 loadfactor=1 route=jvm2
    ProxySet stickysession=ROUTEID
</proxy>


创建虚拟主机文件:
vim /etc/httpd/conf/httpd-vhosts.conf
<VirtualHost *:80> 
    Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
    ServerAdmin panyongzheng@163.com
    ServerName httpd.rh.com# apache的域名或者IP
    ServerAlias localhost 
    ProxyPass / balancer://cluster/ stickysession=JSESSIONID|jsessionid nofailover=On
    ProxyPassReverse / balancer://cluster/ 
    ErrorLog "logs/lbtest-error.log"
    CustomLog "logs/lbtest-access.log" common
</VirtualHost>


重启apache:
service httpd restart
tail -f -n200 /etc/httpd/logs/error_log
tail -f -n200 /etc/httpd/logs/lbtest-error.log
tail -f -n200 /etc/httpd/logs/lbtest-access.log

修改tomcat配置: 202.105.182.130 --> jvm1, 202.105.182.144 --> jvm2,
vim /home/tomcat/server/tomcat7/conf/server.xml  第一个用jvm1, 第二个jvm2
--------------------------
    <!-- You should set jvmRoute to support load-balancing via AJP ie :-->
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">    
    <!-- <Engine name="Catalina" defaultHost="localhost">-->
    ......
    ......
    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
    

http://ip2:8080/test/
http://ip1:8080/test/
http://ip1/test/   
重启Tomcat:
sh /home/tomcat/server/tomcat7/bin/shutdown.sh && rm -rf /home/tomcat/server/tomcat7/logs/catalina.out && sh /home/tomcat/server/tomcat7/bin/startup.sh && tail -f -n200 /home/tomcat/server/tomcat7/logs/catalina.out
启动Tomcat碰到的错误:
Caused by: java.net.UnknownHostException: auto: 未知的名称或服务
java.net.UnknownHostException: idcw009: idcw009: 未知的名称或服务
vi /etc/hosts
-----------
127.0.0.1 追加 auto idcw009
127.0.0.1 追加 auto idcw088

当两个机子做集群的时候, 后台数据拿到null异常信息: 单服务器多个tomcat的问题????????????=============>stickysession方式不起作用
解决方式:http://motech-project.readthedocs.org/en/latest/deployment/sticky_session_apache.html












Apache 2.4
Apache 2.4 + Tomcat7集群配置
Apache2.4 proxy model文档http://httpd.apache.org/docs/current/mod/mod_proxy.html
Apache 2.4 + Tomcat7集群配置http://blog.csdn.net/shaozengwei/article/details/40861447
win7 : Apache-2.4.4 + tomcat-7.0.41 集群的配置 http://blog.csdn.net/u011296170/article/details/9266495

先总结的坑坑洼洼
1.找不到包, 尤其版本相对应的问题. 见http://www.cnblogs.com/lengfo/p/4260363.html
2.权限问题, Redis没有使用root权限启动, 会出现无法访问Redis问题.
3.apache的session问题,用Redis的session的时候, 不需要stickysession=jsessionid, 否则可能出现死循环(只出现很卡, 让后电脑几乎动不了).


做了一些修改
1. 准备工作
首先下载Tomcat7 和Apache2.4
然后安装Apache,安装完成后在IE中输入localhost访问,如果出现It Works则表示Apache安装好了,然后解压缩到Tomcat1和Tomcat2两个目录中。
分别启动Tomcat1和Tomcat2看是否可以正常启动。
准备测试工程
同时准备一个应用, 分别存放到两个tomcat的webapps下面, 源码如下
集群服务器里面的应用,其实两个工程的源码应该是一模一样, 我只是为了测试到底有没有集群, 所以特意在index.jsp的第一行标注是哪个服务器的代码
Tomcat1的test工程源码
在webapps下面添加test目录,添加index.jsp
<%@ page contentType="text/html; charset=UTF-8" %> 
<%@ page import="java.util.*" %> 
<html><head><title>Cluster App Test</title></head> 
<body> 
第<label style='color:red;'><b>1</b></label>个集群服务器的Tomcat
<hr/>
Server Info: 
<% 
out.println(request.getLocalAddr() + " : " + request.getLocalPort()+"<br>");%> 
<% 
  out.println("<br> ID " + session.getId()+"<br>"); 
  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="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> 

创建WEB-INF目录,创建web.xml
<?xml version="1.0" encoding="UTF-8"?> 
<web-app version="3.0" 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_3_0.xsd">    
    <distributable />
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Tomcat2的test工程源码
在webapps下面添加test目录,添加index.jsp
<%@ page contentType="text/html; charset=UTF-8" %> 
<%@ page import="java.util.*" %> 
<html><head><title>Cluster App Test</title></head> 
<body> 
第<label style='color:red;'><b>2</b></label>个集群服务器的Tomcat
<hr/>
Server Info: 
<% 
out.println(request.getLocalAddr() + " : " + request.getLocalPort()+"<br>");%> 
<% 
  out.println("<br> ID " + session.getId()+"<br>"); 
  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="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> 

创建WEB-INF目录,创建web.xml
<?xml version="1.0" encoding="UTF-8"?> 
<web-app version="3.0" 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_3_0.xsd">    
    <distributable />
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>


2. 配置Apache2.4
   ①打开conf/httpd.conf文件,加载以下模块。 在LoadModule的地方, 增加一下代码
#---------------------start------------------------
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule rewrite_module modules/mod_rewrite.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
LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
LoadModule speling_module modules/mod_speling.so
#LoadModule ssl_module modules/mod_ssl.so
#----------------------end---------------------

② 如果你想看到小猫页面,
<IfModule dir_module>
    DirectoryIndex index.html index.jsp
</IfModule>

在上面的index.html下面添加index.jsp就可以了

③在文件末尾加反向代理
纵向集群
ProxyRequests Off 
<proxy balancer://cluster>
     BalancerMember ajp://127.0.0.1:8009 loadfactor=1 route=jvm1 
     BalancerMember ajp://127.0.0.1:9009 loadfactor=1 route=jvm2 
</proxy>

横向集群
ProxyRequests Off 
<proxy balancer://cluster>
     BalancerMember ajp://192.168.0.11:8009 loadfactor=1 route=jvm1
     BalancerMember ajp://192.168.0.12:8009 loadfactor=1 route=jvm2
</proxy>



④去掉Include conf/extra/httpd-vhosts.conf的注释标记#。
改成:增加Include conf/httpd-vhosts.conf, 因为配置文件不存在, 所以增加, 并增加到httpd.conf同一个级别的文件夹.
⑤修改conf/extra/httpd-vhosts.conf文件。没有这个文件呀, 难道直接一个空文件,然后追加?,看④步.
注释掉所有的dummy-host,添加以下内容
<VirtualHost *:80> 
         ServerAdmin zengwei.shao@samsung.com 
         ServerName localhost 
         ServerAlias localhost 
         ProxyPass / balancer://cluster/ stickysession=JSESSIONID|jsessionid nofailover=On #使用Redis的session的时候, 不需要stickysession=jsessionid, 否则可能出现死循环
         ProxyPassReverse / balancer://cluster/ 
         ErrorLog "logs/lbtest-error.log" 
         CustomLog "logs/lbtest-access.log" common 
</VirtualHost>
这个配置文件会做负载,但sessionid不一致
<VirtualHost *:80>
    ErrorLog "logs/acooly.org-error_log"
    LogFormat "%{Host}i %h %l %u %t \"%r\" %s %b" vcommon
    CustomLog logs/access_log vcommon

    ProxyRequests Off
    ProxyPreserveHost on
    # apache+tomcat cluster
    ProxyPass / balancer://tomcat-cluster/ stickysession=JSESSIONID|jsessionid nofailover=Off
    ProxyPassReverse / balancer://tomcat-cluster/
    <Proxy balancer://tomcat-cluster/>
      BalancerMember ajp://192.168.0.11:8009 loadfactor=1 route=jvm1
      BalancerMember ajp://192.168.0.12:8009 loadfactor=1 route=jvm2
      ProxySet lbmethod=bybusyness
    </Proxy>
</VirtualHost>


说明
ProxyRequests Off 表示启用反向代理,必须开启;
ProxyPass为代理转发的Url,即将所有访问/的请求转发到群集balancer://cluster
BalancerMember为群集的成员,即群集服务器1或2,负载均衡服务器会根据均衡规则来将请求转发给BalancerMember
loadfactor=1 即为均衡规则的权重
stickysession=jsessionid  -- 用于处理session发送问题


2.配置Tomcat
两个方向集群共同修改
server.xml, 第1个改为jvm1, 第二个改为jvm2
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm${n}">

取消注释
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

或者改为
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
        <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
</Cluster>


纵向集群
tomcat1保持配置不变, 第二个tomcat2的server.xml里面涉及到的端口, 第一个数字改为9, 比如:9080,9443......
横向集群
端口一律不变

配置完成之后,启动两个Tomcat测试一下Tomcat是否可以正常启动
如果可以正常启动,则进行下面步骤
最后启动Apache2.4,在页面中输入
到此, 直接启动的时候, 好像已经集群好了.

测试
http://192.168.2.100/test/(apache服务器地址),不断刷新, 不断看到调用不同的服务器. , 会看到seession输出类似7F401A91D1BB932EB482B9819A13233D.jvm1, 注意, 点的后面是服务器标识.
纵向集群:session一直改变!!,要使用session共享来解决问题.
横向集群:session保持不变,VM和docker都测试成功.
注意:如果纵向只要Redis的session共享方式, 横向不使用的话, 那么纵向和横向个子的session不变, 但是从两个方向切换的时候, 就会改变. 所以, 一旦使用session共享, 那么横向和纵向都需要配置.


session共享
这是因为没有做Session处理, 它包含两种方式:
I: Session Sticky,把同一个用户的Session一直发送到同一个逻辑单元处理,指定负载的分发组件(如Apache),把请求中包含特定属性的请求发到同一个连接,如指定jsessionid一致的请求到同一个请求,或者在负载组件中给每个响应增加一个头部属性,指定下次的分发目的地. 配置见: http://ajita.iteye.com/blog/1848665,测试成功

II: 通过数据库来实现tomcat集群, 例子1: http://mushme.iteye.com/blog/1147960, 例子2:http://tangmingjie2009.iteye.com/blog/1772169, 不测试

II: mod_jk方式 apache + tomcat + mod_jk 集群部署及Session共享和遇到的问题 http://bbs.vpigirl.com/forum.php?mod=viewthread&tid=562, 不测试

IV: Redis的Session共享, 所有的后端处理逻辑单元共享Session或者Session更新时通知其它逻辑单元(1. 各自维护Session,当请求处理结束后,通知其它组件单元更新Session,包括异步和同步模式; 2. 统一维护Session,如把Session放在memcached或者共享文件系统中,可以在容器级别或者应用级别做这个事情; 3.利用cache server),
使用 Redis 来存储 Apache Tomcat 7 的 Sessionhttp://www.open-open.com/lib/view/1378430065687
tomcat7和redis的sessoin共享问题处理,tomcat7sessoinhttp://www.bkjia.com/ASPjc/930346.html
获得集群的包: http://www.cnblogs.com/lengfo/p/4260363.html,配置见后面,附件是我自己打包得到的.
安装Redis, 网上找教程,注意: 安装Redis后, 要使用root权限启动.
su root
redis-server /etc/redis/redis.conf

两个tomcat都需要配置context.xml
<Context>
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
    <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
	      host="localhost" <!-- 这里是redis服务器IP -->
	      port="6379"
	      database="0"
	      maxInactiveInterval="60" />
</Context>

-------------------
配置纵向的时候没问题, 但是配置横向(两个虚拟机, 非docker方式)的时候碰到问题:
1. Could not get a resource from the pool
原来是服务器没有开放Redis的6379端口, 晕死了............













获得包的代码
=====================================================================
build.gradle文件, 注意版本, 得到包后, 其实只需要几个包:commons-pool2-2.2.jar,jedis-2.5.2.jar,tomcat-juli-7.0.61.jar,tomcat-redis-session-manager-master-2.0.0.jar.
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'signing'

group = 'com.orangefunction'
version = '2.0.0'

repositories {
  mavenCentral()
}

compileJava {
  sourceCompatibility = 1.7
  targetCompatibility = 1.7
}

dependencies {
  compile group: 'org.apache.tomcat', name: 'tomcat-catalina', version: '7.0.61'
  compile group: 'redis.clients', name: 'jedis', version: '2.5.2'
  compile group: 'org.apache.commons', name: 'commons-pool2', version: '2.2'
  //compile group: 'commons-codec', name: 'commons-codec', version: '1.9'

  testCompile group: 'junit', name: 'junit', version: '4.+'
  testCompile 'org.hamcrest:hamcrest-core:1.3'
  testCompile 'org.hamcrest:hamcrest-library:1.3'
  testCompile 'org.mockito:mockito-all:1.9.5'
  testCompile group: 'org.apache.tomcat', name: 'tomcat-coyote', version: '7.0.61'
}

task javadocJar(type: Jar, dependsOn: javadoc) {
  classifier = 'javadoc'
  from 'build/docs/javadoc'
}

task sourcesJar(type: Jar) {
  from sourceSets.main.allSource
  classifier = 'sources'
}

artifacts {
  archives jar

  archives javadocJar
  archives sourcesJar
}

//signing {
//  sign configurations.archives
//}

task copyJars(type: Copy) {
  from configurations.runtime
  into 'dist'  
}

uploadArchives {
  repositories {
    mavenDeployer {
      beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

      //repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
      //  authentication(userName: sonatypeUsername, password: sonatypePassword)
      //}
      //repository(url: "https://oss.sonatype.org/content/repositories/snapshots") {
      //  authentication(userName: sonatypeUsername, password: sonatypePassword)
      //}

      pom.project {
        name 'tomcat-redis-session-manager'
        packaging 'jar'
        description 'Tomcat Redis Session Manager is a Tomcat extension to store sessions in Redis'
        url 'https://github.com/jcoleman/tomcat-redis-session-manager'

        issueManagement {
          url 'https://github.com:jcoleman/tomcat-redis-session-manager/issues'
          system 'GitHub Issues'
        }

        scm {
          url 'https://github.com:jcoleman/tomcat-redis-session-manager'
          connection 'scm:git:git://github.com/jcoleman/tomcat-redis-session-manager.git'
          developerConnection 'scm:git:git@github.com:jcoleman/tomcat-redis-session-manager.git'
        }

        licenses {
          license {
            name 'MIT'
            url 'http://opensource.org/licenses/MIT'
            distribution 'repo'
          }
        }

        developers {
          developer {
            id 'jcoleman'
            name 'James Coleman'
            email 'jtc331@gmail.com'
            url 'https://github.com/jcoleman'
          }
        }
      }
    }
  }
}

构建命令: gradle build -x test  copyJars
得到所有包, 放到tomcat/lib下面, 注意版本.
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics