Балансировка нагрузки и кластеризация с использованием mod_proxy_ajp на Apache HTTP Server 2.2.21 и Tomcat 7.0.23

Я изо всех сил пытался заставить балансировку нагрузки и кластеризацию работать, используя эти комбинации:

  • HTTP-сервер Apache 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 бит
  • Весна 3.1

Некоторые ссылки, которые я прочитал:

Это моя конфигурация:

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> 

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 Server
  • 80xx -> Порт выключения сервера Tomcat
  • 81xx -> порт подключения Tomcat (HTTP)
  • 82xx -> Порт перенаправления SSL Tomcat
  • 83xx -> Порт Tomcat AJP
  • 40xx -> tcp порт приема Tomcat для NioReceiver

Spring Controller

@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>

Пока часть балансировки нагрузки работает, но репликация сеанса - нет.
В основном, что я хочу, если я продолжаю нажимать кнопку "Обновить" на странице входа, переменная "tambah" будет увеличиваться и сохраняться в сеансе. И если текущий узел tomcat не работает, сеанс будет реплицирован на следующий узел tomcat, и данные не пропадут. Но это то, что происходит:

Экран входа в систему:

Tambah = 39 
ID = C1D59C8CA5D10EB98C1DE08AC618204D.s1 

Я снимаю tomcat1 и поддерживаю работоспособность tomcat2 и tomcat3, вот экран входа в систему:

Tambah = 1
ID = A83KJFO38FK30FJDL40FLREI39FKDKGD.s2

Кажется, что отказоустойчивость не работает, сеанс не реплицируется, и приложение создает новый сеанс. Может ли кто-нибудь помочь указать мне правильное направление?

Спасибо

РЕДАКТИРОВАТЬ: Я решил вопрос, благодаря @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 и т. Д.

2 ответа

Решение

Благодаря комментариям @Shane Madden, я перечитал документы кластера tomcat в http://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html, особенно в этой части -> "Если ваши экземпляры Tomcat Работая на той же машине, убедитесь, что атрибут tcpListenPort уникален для каждого экземпляра, в большинстве случаев Tomcat достаточно умен, чтобы решить эту проблему самостоятельно, автоматически определяя доступные порты в диапазоне 4000-4100".

Внесенные мной изменения внесены в каждый файл server.xml экземпляра Tomcat, и я уверен, что каждый порт отличается (например, 4001, 4002, 4003):

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

И вуаля! балансировка нагрузки и кластеризация работают (конечно, с самым базовым конфигом). Я надеюсь, что этот пост может помочь другим на начальных настройках.

У меня похожий программный стек (apache 2.2.15 и tomcat 7.0.65), но все linux и я столкнулись со следующей проблемой со страницей состояния балансировщика: вместо того, чтобы попасть на страницу состояния, директива ProxyPass

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

перенаправлял запрос /balancer-manager одному из котов (и, таким образом, получал страницу с ошибкой томата). Я обошел проблему, установив ProxyPass что-то более ограничительное, чем просто /

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

Не уверен, что это правильный путь?

Другие вопросы по тегам