StackOverflow 一直是我的生活方式,但这次它是一个问题而不是寻找答案,因为我可能已经用尽了所有的选择。
抱歉,这将是对该问题的长篇描述!
我们在 AWS 上的 Windows 2012 服务器上运行着一个 Spring MVC 应用程序 + Tomcat 7。作为一个分析应用程序,它调用重型过程调用在后台进行统计计算。
由于高可用性要求,我需要设置一个集群。现在 AWS 上没有多播,我只能采用另外两个选项。(我必须说,这是我在生产环境中首次尝试 AWS 和 Tomcat)
1. 使用 DeltaManager 进行会话复制的静态 Tomcat 集群 2. 基于 Redis 的会话复制(使用 Windows 服务器和粘性会话的可能性不大)
从静态 Tomcat 集群开始,我确实没有费什么力气就完成了设置,然后继续配置 Apache Httpd mod_proxy 作为负载均衡器。
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8" channelStartOptions="3"><!--startoption 3 added to disable
multicast ,channel send option 8 is for async replication-->
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4002"
autoBind="9"
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.TcpPingInterceptor"/><!--Added ,This interceptor pings other nodes
sothat all nodes can recognize when other nodes have left the cluster. Without this class, the cluster may appear to work fine, but session
replication can break down when nodes are removed and re-introduced-->
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor">
<Member className="org.apache.catalina.tribes.membership.StaticMember"
port="4000"
host="localhost"
domain="delta-static"
uniqueId="{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0}" />
</Interceptor>
</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>
使用 AJP 连接器的 mod proxy httpd.conf 配置,相关模块取消注释
<Proxy balancer://IOCluster stickysession=JSESSIONID>
BalancerMember ajp://127.0.0.1:8009 route=tcruntime8009 loadfactor=1
BalancerMember ajp://127.0.0.1:8012 route=tcruntime8012 loadfactor=1
</Proxy>
ProxyPreserveHost On
ProxyStatus On
ProxyPass "/IO" "balancer://IOCluster/IO"
ProxyPassReverse "/IO" "balancer://IOCluster/IO"
mod proxy httpd.conf 配置了 HTTP 连接器,相关模块已取消注释
ProxyRequests 关闭 ProxyPass /IO 平衡器://IOCluster stickysession=JSESSIONID ProxyPassReverse /IO 平衡器://IOCluster
BalancerMemberhttp://本地主机:8092/IO路线=tcruntime8092 BalancerMemberhttp://本地主机:8091/IO路线=tcruntime8091
负载平衡器在两种情况下都有效。问题在于会话复制不起作用,而且我在日志中看不到相同的迹象。如果我关闭一个实例,平衡器将重定向到另一个节点,但我会看到登录页面,这是相同的证明。
根据此18835014问题 我将标签添加到应用程序 web.xml 并将增量管理器标签移动到 context.xml
<Context>
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!--<Context distributable="true"></Context>-->
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
</Context>
我可以在控制台上看到会话复制处于活动状态。
现在的问题是,当我登录到应用程序时,尽管在应用程序上触发了查询,但页面仍然无响应!我可以在访问日志中看到 504(网关超时)消息,其中我看到所有 get 请求都成功返回。但是在提交登录页面后,只要触发第一个查询,数据库查询就会触发,但应用程序变得无响应。
如果我将 DeltaManager 移回到 server.xml 内部,应用程序将变得响应,但没有会话复制。
我尝试对 httpd.conf prefork 模块、keepalive、timeout 等进行了一些其他调整,之后我在 apache 服务器的访问日志中看到 500,但没有任何效果。非常感谢任何帮助!
<IfModule mpm_prefork_module>
StartServers 10
MinSpareServers 10
MaxSpareServers 20
MaxClients 50
ServerLimit 50
MaxRequestsPerChild 500
</IfModule>
ProxyRequests On
ProxyTimeout 600
<Proxy *>
AddDefaultCharset Off
Order deny,allow
Allow from all
</Proxy>
<Proxy balancer://IOCluster stickysession=JSESSIONID>
BalancerMember ajp://127.0.0.1:8009 min=10 max=100 route=tcruntime8009 loadfactor=1 keepalive=On timeout=600
BalancerMember ajp://127.0.0.1:8012 min=10 max=100 route=tcruntime8012 loadfactor=1 keepalive=On timeout=600
</Proxy>
ProxyPreserveHost On
ProxyStatus On
ProxyPass "/IO" "balancer://IOCluster/IO"
ProxyPassReverse "/IO" "balancer://IOCluster/IO"