StackOverflow был для меня образом жизни, но на этот раз это вопрос, а не поиск ответа, поскольку я, вероятно, исчерпал все варианты.
Извините, так как это будет подробное описание проблемы!
У нас есть приложение Spring MVC + Tomcat 7, работающее на сервере Windows 2012 на AWS. Будучи приложением Analytics, вызывающим вызовы высокопроизводительных процедур, выполняющие статистические вычисления в резервной копии.
Из-за требований к высокой доступности мне нужно настроить кластер. Теперь без многоадресной рассылки на AWS я прибег к двум другим вариантам (я должен сказать, что это мой первый набег на AWS и Tomcat в производственной среде).
1. Статический кластер Tomcat с DeltaManager для репликации сеанса 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>
Конфигурация прокси мода httpd.conf с коннектором AJP с соответствующими модулями без комментариев
<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"
Конфигурация мода прокси httpd.conf с HTTP-коннектором с соответствующими модулями без комментариев
ProxyRequests Off ProxyPass / Балансировщик ввода-вывода: // IOCluster stickysession = JSESSIONID ProxyPassReverse / Балансировщик ввода-вывода: // IOCluster
БалансирЧлен http: // локальный: 8092 / IO route = tcruntime8092 BalancerMember http: // локальный: 8091 / IO route = 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 (время ожидания шлюза истекло) в журналах доступа, где я вижу, что все запросы на получение успешно возвращаются. Но как только поскольку первые запросы запускаются после отправки страницы входа, запросы к базе данных запускаются, но приложение перестает отвечать.
Если я верну DeltaManager обратно внутрь server.xml, приложение станет отзывчивым, но без репликации сеанса.
Некоторые другие настройки, которые я пробовал с модулем prefork httpd.conf, keepalive, timeout и т.д., после чего я вижу 500 в журнале доступа на сервере apache, ничего не работает. Был бы очень признателен за любую помощь!
<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"