我一直在努力使用这些组合来实现负载平衡和集群工作:
- Apache HTTP Server 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 位
- Spring 3.1
我读过的一些链接:
这是我的配置:
httpd配置文件
# 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>
每个 tomcat 的 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 "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
端口编号(如果部署在同一台服务器中,请确保没有实例使用相同的端口)
- 80 -> Apache HTTP 服务器端口
- 80xx -> Tomcat 服务器关闭端口
- 81xx -> Tomcat 连接器端口 (HTTP)
- 82xx -> Tomcat SSL 重定向端口
- 83xx -> Tomcat AJP 端口
- 40xx -> NioReceiver 的 Tomcat tcp 接收端口
Spring 控制器
@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";
}
}
登录页面
<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 等。
答案1
感谢@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" />
瞧!负载平衡和集群正在工作(当然,使用最基本的配置)。我希望这篇文章可以帮助其他人完成初始设置。
答案2
我有一个类似的软件堆栈(apache 2.2.15 和 tomcat 7.0.65),但所有 linux 和我都遇到了平衡器状态页面的以下问题:ProxyPass 指令没有进入状态页面
ProxyPass / balancer://mybalancer/ stickysession=JSESSIONID|jsessionid
将 /balancer-manager 请求重定向到其中一个 tomcat(因此收到 tomvat 错误页面)。我通过将 ProxyPass 设置为比 / 更严格的内容来解决了这个问题
ProxyPass /myapp balancer://mybalancer/myapp stickysession=JSESSIONID|jsessionid
但不确定这是否是正确的解决方法?