在Apache HTTP Server 2.2.21和Tomcat 7.0.23上使用mod_proxy_ajp进行负载平衡和群集

我一直在努力使负载均衡和集群工作使用这些组合:

  • Apache HTTP服务器2.2.21(httpd-2.2.21-win32-x86-openssl-0.9.8r)使用mod_proxy_ajp启用了粘滞会话。
  • Apache Tomcat 7.0.23(apache-tomcat-7.0.23-windows-x64)
  • JDK 7更新2(jdk-7u2-windows-x64)
  • Windows 7 64位
  • Spring 3.1

我读过的一些链接:

  • Tomcat集群 – 一步一步指南
  • 为会话复制设置Tomcat群集
  • 了解Tomcat上下文容器
  • 集群/会话复制如何

这是我的configuration:

httpd.conf文件

# Required Modules 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 status_module modules/mod_status.so # Reverse Proxy <Proxy balancer://mybalancer> BalancerMember ajp://localhost:8301 route=s1 BalancerMember ajp://localhost:8302 route=s2 BalancerMember ajp://localhost:8303 route=s3 </Proxy> ProxyPass / balancer://mybalancer/ stickysession=JSESSIONID|jsessionid # Forward Proxy ProxyRequests Off <Proxy *> Order deny,allow Deny from none Allow from localhost </Proxy> # Balancer-manager, for monitoring <Location /balancer-manager> SetHandler balancer-manager Order deny,allow Deny from none Allow from localhost </Location> 

每个tomcat的server.xml(仅在端口号上有所不同)

 <Server port="8001" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <Listener className="org.apache.catalina.core.JasperListener" /> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <GlobalNamingResources> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <Service name="Catalina"> <Connector port="8101" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8201" /> <Connector port="8301" protocol="AJP/1.3" redirectPort="8201" /> <Engine name="Catalina" defaultHost="localhost" jvmRoute="s1"> <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" /> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" /> </Sender> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="4000" autoBind="100" selectorTimeout="5000" maxThreads="6" /> <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" /> <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener" /> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" /> </Cluster> <Realm className="org.apache.catalina.realm.LockOutRealm"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" /> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> </Host> </Engine> </Service> </Server> 

端口编号(如果部署在同一台服务器上,请确保没有实例使用相同的端口)

  • 80 – > Apache HTTP服务器端口
  • 80xx – > Tomcat服务器SHUTDOWN端口
  • 81xx – > Tomcat连接器端口(HTTP)
  • 82xx – > Tomcat SSLredirect端口
  • 83xx – > Tomcat AJP端口
  • 40xx – > NioReceiver的Tomcat tcp接收端口

弹簧控制器

 @Controller @RequestMapping("/login") public class LoginController { @RequestMapping(method=RequestMethod.GET) public String show(@ModelAttribute("user") User user, HttpServletRequest request) { user.setUsername("YUSUF"); HttpSession session = request.getSession(); Integer tambah = (Integer) session.getAttribute("tambah"); if(tambah == null) tambah = new Integer(1); else tambah = new Integer(tambah.intValue() + 1); session.setAttribute("tambah", tambah); return "login"; } } 

login.jsp的

  <div class="mainFooter"> Tambah = ${sessionScope.tambah} <br> ID = ${pageContext.session.id} </div> 

到目前为止,负载平衡部分正在工作,但会话复制不是。
基本上我想要的是,如果我不断刷新login页面,variables“tambah”将增加并保持在会话中。 如果当前tomcat节点closures,会话将被复制到下一个tomcat节点,并且数据不会消失。 但是这是发生的事情:

login屏幕:

 Tambah = 39 ID = C1D59C8CA5D10EB98C1DE08AC618204D.s1 

我把tomcat1放下,并保持tomcat2和tomcat3运行,这里是login屏幕:

 Tambah = 1 ID = A83KJFO38FK30FJDL40FLREI39FKDKGD.s2 

看来故障转移不起作用,会话不会被复制,应用程序会创build一个新的会话。 有人能帮我指点正确的方向吗?

谢谢

编辑:我已经解决了这个问题,谢谢@Shane Madden,这是我所做的改变:

 <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="4000" autoBind="100" selectorTimeout="5000" maxThreads="6" /> 

对于每个Tomcat,tcp接收端口必须不同(如果在同一台服务器上运行),例如使用4001,4002,4003等。

感谢@Shane Madden的评论,我重新阅读了http://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html中的tomcat集群文档,特别是在这一部&#x5206; – >“如果你的Tomcat实例是运行在同一台机器上,确保每个实例的tcpListenPort属性都是唯一的,在大多数情况下,Tomcat足够聪明,通过自动检测4000-4100范围内的可用端口来解决这个问题。

我所做的更改是在每个Tomcat实例的server.xml中,我确保每个端口都不同(例如4001,4002,4003):

 <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="4001" autoBind="100" selectorTimeout="5000" maxThreads="6" /> 

瞧! 负载平衡和集群正在工作(当然最基本的configuration)。 我希望这篇文章可以帮助他人在初始设置。

我有一个类似的软件堆栈(Apache 2.2.15和tomcat 7.0.65),但所有的Linux和我遇到了平衡器状态页面的以下问题:而不是进入状态页ProxyPass指令

 ProxyPass / balancer://mybalancer/ stickysession=JSESSIONID|jsessionid 

将/ balancer-manager请求redirect到其中一个tomcat(从而得到一个tomvat错误页面)。 我通过将ProxyPass设置为更具限制性的方法解决了这个问题,

 ProxyPass /myapp balancer://mybalancer/myapp stickysession=JSESSIONID|jsessionid 

不知道这是否是正确的方式去呢?