【发布时间】:2010-10-25 17:53:17
【问题描述】:
有负载平衡的 Tomcat Web 服务器。每个请求都可以由不同的 tomcat 服务器提供服务。
在为基于 j2ee (struts) 的 Web 应用程序编写代码时,我们如何处理这个问题?
【问题讨论】:
标签: java tomcat load-balancing
有负载平衡的 Tomcat Web 服务器。每个请求都可以由不同的 tomcat 服务器提供服务。
在为基于 j2ee (struts) 的 Web 应用程序编写代码时,我们如何处理这个问题?
【问题讨论】:
标签: java tomcat load-balancing
首先,您需要为会话关联/粘性会话设置负载平衡器,以便它继续根据 JSESSIONID 将所有请求转发到同一个 Tomcat(只要它启动)。
The Tomcat clustering doc 说明了应用程序成功复制其会话的两个重要要求:
java.io.Serializable
<distributable/> 元素或设置在您的 <Context distributable="true" />
如果您开始将未实现 Serializable 的对象放入 Session 中(或具有未实现 Serializable 的属性/字段),那么您将遇到问题。
(实际上,无论您使用哪个 servlet 容器,我相信这些点都适用。)
更新:为了解决 cmets 中关于为什么在多台服务器之间平衡负载时使用粘性会话的一些问题,我认为用一个例子来解释这一点是最简单的。
首先,这只有在您的应用程序在会话中保留某种数据时才真正重要,这可能不是每个应用程序(尽管可能是大多数)。如果您不在会话中保留数据,那么您可能不会关心这些,您可以在此处停止阅读。
拥有一个在会话中保存数据但您确实没有有粘性会话的环境会打开一个令人头疼的世界。
假设first.jsp 更新了特定会话属性中的某个值,而second.jsp 恰好读取了相同的会话属性。您可以设置 Tomcat 将会话数据复制到集群中的所有服务器,但这种复制不会立即发生。如果first.jsp 的初始请求由server1 处理,并且在完成后一纳秒,同一访问者向second.jsp 发出请求,在您的非粘性环境中由server2 处理会怎样。由于复制不是即时的,您是否有任何方法知道您是否正在读取最新的会话数据?您是否必须添加某种逻辑来同步集群中的读取?这将成为巨大的痛苦。
设置会话亲和性/粘性会话消除了这个令人头疼的问题;通过使来自同一客户端服务器的所有请求由同一节点发出,您不必担心“该节点在处理请求时是否是最新的?”当节点发生故障时,客户端仍然可以故障转移到集群中的另一个节点,该节点具有其会话数据的副本,但对于粘性会话,这将成为罕见的情况,而不是常态。
需要粘性会话还有另一个原因:在集群中的节点之间加载。如果会话中的请求可以由任何节点处理,那么这意味着您在集群中设置了全对全复制(意味着节点1的会话数据被复制到节点2、节点3、...、节点N, node2 的会话数据被复制到 node1, node3, ... none N, etc)。当集群变大时,全对全会话复制可能会占用带宽和资源,因为集群中的每个添加都意味着另一个节点需要与集群中的每个其他单个节点进行通信。
对此的替代方法是将节点的数据复制到集群中的几个“伙伴”,以便在节点发生故障时,它的数据可以在其他地方使用,但无需每个节点都必须有副本。在这种情况下,您将配置集群,以便节点 1 将其数据复制到节点 2 和 3,节点 2 将其数据复制到节点 3 和 4,依此类推,形成一个链。在这种情况下,向集群添加额外的节点不会导致节点之间的通信量像在 all-to-all 方案中那样迅速增加。
【讨论】: