Apache + Tomcat - 粘性会话和负载平衡的问题

我遇到了一些关于粘性会话的Apache mod_proxy_balancer问题。

我们已经在Java中开发了一个在Tomcat上运行的宁静的Web服务。实际的后端使用Acegi安全性,并具有Auth Basic身份验证。

架构是(对不起,我是新用户,我无法发布图像):

     --------------------
     |Java Reverse Proxy|
     --------------------
            |
     --------------------
     |Apache load balancer|
     --------------------               
            |
    --------|--------
    |               |
--------        --------    
|tomcat1|       |tomcat2|
--------        --------    

我们有这个“Java反向代理”来执行各种业务。它还在Tomcat(Tomcat1,Tomcat2)上进行基本身份验证。

最终用户调用 url,如:http:///a/b?username=foo&password=bar&session=xxx

然后,反向代理将请求代理到 Apache,并将凭据作为基本身份验证令牌发送。

最终用户有三个不同的 URL:

http://<java reverse proxy domain>/service1
http://<java reverse proxy domain>/service2
http://<java reverse proxy domain>/service3

只有 service1 和服务 2 通过 Acegi 受到保护。service3 是匿名访问的(这是一项要求)。

我们在Apache中具有以下配置来执行负载平衡:

<Proxy balancer://cluster>
    Header set Cache-Control no-cache
    Header set Pragma no-cache
    BalancerMember http://xxx:9671 route=server1
    BalancerMember http://xxx:9672 route=server2
</Proxy>

ProxyPreserveHost On
ProxyPass / balancer://cluster/ stickysession=JSESSIONID
ProxyPassReverse / balancer://cluster/ stickysession=JSESSIONID

在第一次调用 service1 时,将 JSESSIONID 返回给用户,然后他将此会话信息作为请求的一部分发送(在查询字符串中,会话参数中)

为了维护后端 tomcats (tomcat1, tomcat2) 中的会话状态,java 反向代理从查询字符串中获取会话,并将其作为 JSESSIONID cookie 发送到代理的 tomcats。

对于受身份验证基本保护的URL,一切都很好。但是,当用户调用第三个URL(公开可用)时,Apache无法正确执行负载平衡。

例如,当我调用服务1或2时,我得到以下Apache日志:

[Wed Feb 22 10:48:52 2012] [debug] mod_proxy_balancer.c(280): proxy: BALANCER: Found value "3FB8F8135173BBBE78E5E4BBD6F5C8FB" for stickysession JSESSIONID
[Wed Feb 22 10:48:52 2012] [debug] mod_proxy_balancer.c(1003): proxy: Entering byrequests for BALANCER (balancer://cluster)
[Wed Feb 22 10:48:52 2012] [debug] mod_proxy_balancer.c(1046): proxy: byrequests selected worker "http://xxx:9672" : busy 0 : lbstatus 1

这完全没问题,因为该请求旨在针对tomcat2。

但是当我调用service3时,我得到:

[Wed Feb 22 10:49:27 2012] [debug] mod_proxy_balancer.c(280): proxy: BALANCER: Found value "3FB8F8135173BBBE78E5E4BBD6F5C8FB" for stickysession JSESSIONID
[Wed Feb 22 10:49:27 2012] [debug] mod_proxy_balancer.c(1003): proxy: Entering byrequests for BALANCER (balancer://cluster)
[Wed Feb 22 10:49:27 2012] [debug] mod_proxy_balancer.c(1046): proxy: byrequests selected worker "http://xxx:9671" : busy 0 : lbstatus 0

正如你所看到的,即使JSESSIONID cookie是相同的,Apache也会将请求发送到错误的tomcat(这里是tomcat1)。

可能是 service3 的 url 不需要身份验证,而 service1 和 service2 需要身份验证?

我很确定我做错了什么,但我已经四处寻找了很长时间,我无法让它发挥作用。

非常感谢您的帮助。

谢谢


答案 1

我没有在你的JSESSIONID上看到jvmRoute后缀。mod_proxy使用 jvmRoute 将粘性会话正确地路由到您的 Tomcat 实例。jvmRoute 是在 tomcat 服务器配置中声明的(其中每个服务器实例都有自己唯一的 jvmRoute 标识符。


答案 2

也许会有所帮助。这是我在Web服务器上的配置:

<Proxy balancer://hybriscluster>
BalancerMember ajp://tomcatServer1:8009 route=tomcat1 keepalive=On ping=5 max=200 ttl=120
BalancerMember ajp://tomcatServer2:8009 route=tomcat2 keepalive=On ping=5 max=200 ttl=120
ProxySet stickysession=JSESSIONID|jsessionid lbmethod=byrequests timeout=60
</Proxy>

在 tomcat Server 1 的服务器.xml中配置:

<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1"}">

推荐