Tomcat会话驱逐以避免OutOfMemoryError

时间:2009-07-29 00:43:52

标签: java memory session tomcat session-timeout

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

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

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

我考虑过扩展StandardManager来覆盖processExpires(),并且如果堆使用量大于最大值的85%,则会破坏其他会话。然而,这在实践中似乎有点问题。如果堆没有被引用,并且垃圾收集器能够收集大量的对象(如果它们不愿意运行)以将堆减少到最大值的50%,该怎么办?我会不必要地过期。我想我们可以通过一些积极的垃圾收集设置来缓解这种风险。另外,我怎么知道会话到期后我节省了多少内存?我必须等待几个GC周期才能确定。也许我可以采取保守的方法,每个后台进程周期最多删除N个会话,直到内存低于可接受的阈值。我可以将会话序列化,以估计GC的数量,但这取决于供应商实现Serializable并将实例变量标记为瞬态。

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

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

更新:我们实际上对系统架构没有多少控制权,我们特别无法减少会话使用。但是,我们可以根据自己的需要配备容器。但是,Tomcat是供应商支持的唯一开源servlet容器。

4 个答案:

答案 0 :(得分:4)

您的选择似乎是:

  1. 减少空闲会话超时,
  2. 使会话持久(可能仅在用户登录后),
  3. 减少每个会话对象使用的内存,
  4. 增加Tomcat实例的内存,
  5. 运行多个服务实例,并在其前面放置一个负载均衡器。
  6. 从技术角度来看,3是最佳解决方案......如果有效的话。其他人都有不利的一面。

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

答案 1 :(得分:1)

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

默认情况下,如果没有指定,只有64mb - 对于大多数密集型/成熟的Web应用程序,我认为这个版本很小。

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

export CATALINA_OPTS=-Xmx128m

(如果您想要大于128mb,请替换您想要的任何值128.同时更改为Windows /您的shell的正确语法)

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

您可能也对此链接感兴趣:6 Common Errors in Setting Java Heap Size(在如何在Tomcat中设置Java堆大小?的最后还有一节)。

答案 2 :(得分:0)

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

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

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

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

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

见这里:

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

答案 3 :(得分:0)

我同意Stephen C的说法,你需要解决这个问题 - 正如他所说甚至是交换机供应商。 这里没有人提到的一件事(令人惊讶的是)供应商也应该考虑清理未使用的会话对象。

这很容易,除非你一直记住这一点,让会话大小膨胀 - 让对象的大小不被注意 - 然后在我们有这些对象的列表时有大量的会话属性 - 然后从不清理他们出去 - 如果应用程序很大,对象A,B,C,D,E,F的列表显示在应用程序的某些部分,但从未清除,那么这是供应商尚未解决的基本内务管理问题。

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

编辑并使用分页,而不是加载符合条件的整个列表(除非分页是条件的一部分)

我希望评论可以帮助您和其他人。