17

有负载平衡的 Tomcat Web 服务器。每个请求都可以由不同的 tomcat 服务器提供服务。

在为基于 j2ee (struts) 的 Web 应用程序编写代码时,我们如何处理这个问题?

4

1 回答 1

30

首先,您需要为会话关联/粘性会话设置负载均衡器,以便它根据 JSESSIONID 继续将所有请求转发到同一个 Tomcat(只要它启动)。

Tomcat 集群文档说明了应用程序成功复制其会话的两个重要要求:

  • 您的所有会话属性都必须实现java.io.Serializable
  • 确保您的 web.xml 具有<distributable/>元素或设置在您的<Context distributable="true" />

如果您开始将对象放入未实现的 Session 中Serializable(或具有未实现的属性/字段Serializable),那么您将遇到问题。

(实际上,无论您使用哪个 servlet 容器,我相信这些点都适用。)

更新:为了解决评论中关于为什么在平衡多个服务器之间的负载时使用粘性会话的一些问题,我认为用一个例子来解释这一点是最简单的。

首先,这只有在您的应用程序在会话中保留某种数据时才真正重要,这可能不是每个应用程序(尽管可能是大多数)。如果您不在会话中保留数据,那么您可能不会关心这些,您可以在这里停止阅读。

拥有一个将数据保存在会话中但没有粘性会话的环境会打开一个令人头疼的世界。

假设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 方案中那样迅速增加。

于 2009-05-13T03:00:56.160 回答