大型的企业应用每天都需要承受巨大的访问量,在着巨大访问量的背后有数台服务器支撑着,如果一台服务器崩溃了,那么其他服务器可以使企业应用继续运行,用户对服务器的运作是透明化的,如何实现这种透明化呢?由如下问题需要解决。
一. Session 的复制
二. 如何将请求发送到正常的服务器
针对以上问题,可以使用群集和负载均衡来解决,整体架构如下:
中间由一台服务器做负载均衡( Load Balancer ),它将所有请求,根据一定的负载均衡规则发送给指定的群集服务器( Cluster ),群集服务器拥有着相同的状态和相同的应用程序,并且他们的 Session 是相互复制的,这样,不管访问哪台服务器都具有相同的结果,即使一台服务器崩溃掉以后,可以由其他集群服务器继续负责应用程序的运行。
Tomcat 中如何配置群集
我们假设有如下场景,一台负载均衡服务器负责请求的均衡,群集服务器 A 和群集服务器 B 组成一个群集,当某个群集服务器崩溃后,另外一台继续负责应用程序的运行。
一. 配置 Tomcat5.5.12 群集服务器 A
修改 Tomcat 配置文件 server.xml
1 .群集服务器 A 的端口号与 B 不冲突,即使 Server Port,Connector,Coyote/JK2 AJP Connecto r 的端口号唯一
2 .在 Host 元素下增加以下内容:
<Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
managerClassName="org.apache.catalina.cluster.session.DeltaManager"
expireSessionsOnShutdown="false"
useDirtyFlag="true"
notifyListenersOnReplication="true">
<!-- 每个群集服务器都需要有相同的 Membership 配置 -->
<Membership
className="org.apache.catalina.cluster.mcast.McastService"
mcastAddr="228.0.0.4"
mcastPort="45564"
mcastFrequency="500"
mcastDropTime="3000"/>
<!--tcpListenAddress :本机 IP 地址 服务器将此地址广播给其他群集服务器 -->
<Receiver
className="org.apache.catalina.cluster.tcp.ReplicationListener"
tcpListenAddress="10.10.13.145"
tcpListenPort="4001"
tcpSelectorTimeout="100"
tcpThreadCount="6"/>
<Sender
className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
replicationMode="pooled"
ackTimeout="15000"
waitForAck="true"/>
<Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
filter=".*/.gif;.*/.js;.*/.jpg;.*/.png;.*/.htm;.*/.html;.*/.css;.*/.txt;"/>
<Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener"/>
</Cluster>
3 .修改 Web 应用程序配置文件 web.xml
在 web.xml 文件中 <web-app> 元素下增加以下内容:
<!-- 此应用将与群集服务器复制 Session-->
<distributable/>
二. 配置 Tomcat5.5.12 群集服务器 B
与群集服务器 A 配置基本相同,唯一不同的地方就是 server.xml 文件中
<Receiver
className="org.apache.catalina.cluster.tcp.ReplicationListener"
tcpListenAddress="10.10.13.145"
tcpListenPort="4002"
tcpSelectorTimeout="100"
tcpThreadCount="6"/>
tcpListenAddress 应为本机地址,如果两台群集服务器在一台机器上,则端口号要不同
注意: B 的其他端口不要与 A 冲突。
三. 群集服务器具体配置结果
配置参数 | 群集服务器 A | 群集服务器B |
Server Port | 9005 | 10005 |
Connector | 9080 | 10080 |
Coyote/JK2 AJP Connector | 9009 | 10009 |
Cluster mcastAddr | 228.0.0.4 | 228.0.0.4 |
Cluster mcastPort | 45564 | 45564 |
tcpListenAddress | 本机IP 地址 | 本机IP 地址 |
Cluster tcpListenPort | 4001 | 4002 |
Mcast* 用于广播,所有群集服务器需要填写相同的配置
tcpListen* 本机的 IP ,群集服务器启动时,会将自己的 IP 和端口号广播出去,其他群集服务器收到后,响应广播发出者。
四. 测试群集
启动群集服务器 A ,再启动群集服务器 B 会显示群集服务器的信息,表示群集服务器配置成功
五. 配置负载均衡服务器 Apache2.2.3
现在虽然群集已经有了相同的状态,但需要不同的 IP 地址才能访问到服务器 A 与 B ,现在我们配置一台负载均衡服务器来实现统一的入口访问,和负载的均衡。
下载 Apache 服务器 2.2.3 。
修改 httpd.conf 文件
将以下 Module 的注释去掉
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_http_module modules/mod_proxy_http.so
并增加以下元素
ProxyRequests Off
ProxyPass /helloworld balancer://mycluster stickysession=jsessionid nofailover=On
<Proxy balancer://mycluster>
BalancerMember http://10.10.13.145:9080
BalancerMember http://10.10.13.145:10080 smax=1 loadfactor=20
</Proxy>
<Location /balancer-manager>
SetHandler balancer-manager
Order Deny,Allow
Deny from all
Allow from all
</Location>
<Location /server-status>
SetHandler server-status
Order Deny,Allow
Deny from all
Allow from all
</Location>
其中
ProxyPass /helloworld balancer://mycluster stickysession=jsessionid nofailover=On
<Proxy balancer://mycluster>
BalancerMember http://10.10.13.145:9080
BalancerMember http://10.10.13.145:10080 smax=1 loadfactor=20
</Proxy>
ProxyPass 为代理转发的 Url, 即将所有访问 /helloworld 的请求转发到群集 balancer://mycluster
BalancerMember 为群集的成员,即群集服务器 A 或 B ,负载均衡服务器会根据均衡规则来将请求转发给 BalancerMember 。
配置好后,启动 Apahce 服务器,访问 localhost/hellworld 就会看到群集服务器中应用返回的结果。恭喜你,负载均衡和群集已经配置成功了。