Назад | Перейти на главную страницу

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

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

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

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

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>

нумерация портов (убедитесь, что ни один из экземпляров не использует один и тот же порт, если они развернуты на одном сервере)

Пружинный контроллер

@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 и т. Д.

Благодаря комментариям @Shane Madden я перечитал документы кластера tomcat в http://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html, особенно в этой части -> «Если ваши экземпляры 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" />

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

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

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

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

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

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