2

我们在 Tomcat 5.5 中运行供应商提供的 web 应用程序,使用 StandardManager 进行会话(在内存中)。由于会话可能会变得非常大(20M+),堆空间不足是一个严重的问题。如果可能,用户希望将会话保留几个小时,但宁愿驱逐会话也不愿耗尽堆空间。供应商似乎没有在会话对象中正确实现 Serializable,因此切换到持久会话管理器实现不是一种选择。

Tomcat 允许设置一个 maxActiveSessions 属性,该属性将限制管理器中的会话总数。但是,当达到该限制时,在某些现有会话到期之前,不会创建新会话。我们想首先破坏最近最少使用的会话。

理想情况下,我们希望在堆使用量接近“Xmx”设置时使一些最近未使用的会话过期,即使它们还不够老而无法无条件过期。一个非常古老的 Tomcat 开发人员邮件列表线程建议这可能允许拒绝服务攻击*,但是,由于此应用程序仅在公司网络中可用,我们并不担心。

我考虑过扩展 StandardManager 以覆盖 processExpires() 并在堆使用量大于最大值的 85% 时破坏额外的会话。但是,这在实践中似乎有点问题。如果堆的大部分未被引用,并且垃圾收集器将能够收集大量对象(如果它不想运行)以将堆减少到最大值的 50%,该怎么办?我会不必要地过期会话。我想我们可以通过一些激进的垃圾收集设置来减轻这种风险。另外,我怎么知道会话过期节省了多少内存?我必须等待几个 GC 周期才能确定。也许我可以采取保守的方法,在每个后台进程周期中最多删除 N 个会话,直到内存降至可接受的阈值以下。

有没有人解决过这个问题?作为短期解决方案,我们正在增加堆大小,但这种创可贴也有其缺点。

  • 他们指的是一个公共站点,其中将在登录前创建会话。有人可能会导致创建许多新会话并挤出实际使用的会话。

更新:我们对系统架构确实没有太多控制权,而且我们特别不能减少会话使用。但是,我们可以随心所欲地使用容器。然而,Tomcat 是唯一受供应商支持的开源 servlet 容器。

4

4 回答 4

4

您的选择似乎是:

  1. 减少空闲会话超时,
  2. 使会话持久化(可能仅在用户登录后),
  3. 减少每个会话对象使用的内存,
  4. 增加 Tomcat 实例的内存,
  5. 运行您的服务的多个实例,并在它/它们前面放置一个负载均衡器。

从技术角度来看,3 是最好的解决方案……如果可行的话。其他人都有缺点。

用记忆做聪明的事情只是一个创可贴。从用户的角度来看,它使您网站的行为更难理解。此外,如果您的用户群/流量呈上升趋势,您只是在推迟寻找可持续解决方案的问题。

于 2009-07-29T01:23:05.617 回答
1

您是否尝试过增加 JVM 的最大堆大小?

默认值(如果未指定)仅为 64mb - 我想说这对于大多数密集/成熟的 Web 应用程序来说偏小。

使用 Tomcat 执行此操作的最佳方法是将以下内容添加到setenv.bat/ .sh

export CATALINA_OPTS=-Xmx128m

(如果您想要大于 128mb,则用您想要的任何值替换 128。还要更改为 Windows / 您的 shell 的正确语法)

Tomcat的startupcatalinashell 脚本具有内置逻辑来调用此文件(如果存在)。这是指定您需要为 Tomcat 安装设置的任何自定义环境属性的“最佳实践”方式 - 将属性放在此文件中比编辑startup.shcatalina.sh直接更好,因为此文件可以在 Tomcat 安装/版本之间移植。

您可能还对此链接感兴趣:设置 Java 堆大小中的 6 个常见错误(最后还有一节关于如何在 Tomcat 中设置 Java 堆大小?)。

于 2009-07-29T01:19:19.113 回答
0

我同意 Stephen C 的观点,即您需要解决问题的是您的供应商——正如他所说,甚至更换供应商。没有人在这里提到的一件事(令人惊讶)是供应商还应该考虑清理未使用的会话对象。

除非您一直牢记,否则很容易让会话大小膨胀——让对象的大小膨胀而不被注意到——然后当我们拥有这些对象的列表时拥有大量会话属性——然后永远不要清理它们——如果应用程序很大,其中对象 A、B、C、D、E、F 的列表显示在应用程序的某些部分,但从未清理过,那么这是供应商尚未解决的基本内务管理问题。

例如,webapp 中是否有一个“中央屏幕”,您可以在其中导航到应用程序的其他部分?如果是这样,则供应商应在进入此屏幕时清理所有已收集并填充到可从中央页面/屏幕/门户访问的屏幕上的会话的对象

编辑并使用分页,不加载符合标准的整个列表(分页是标准的一部分时除外)

我希望该评论对您和其他人有所帮助。

于 2013-03-27T10:20:26.793 回答
0

我建议使用 apache 将多个 tomcat 实例放在前面,然后使用 mod_jk 在它们之间进行负载平衡。

您可以在没有任何真正集群的情况下执行此操作,因此会话共享不会成为问题。

Mod_jk 坚如磐石,甚至提供了一个简单的 gui 来将实例标记为未使用等。

这也会在弹性等方面带来许多其他好处。我个人在一个非常大规模的面向公众的网站上使用了这个设置,它很有魅力。

理想的情况是设置真正的会话共享,但在某些情况下,这太过分了。

看这里:

http://tomcat.apache.org/connectors-doc/generic_howto/quick.html

于 2009-07-29T10:54:14.030 回答