我们在 Tomcat 5.5 中运行供应商提供的 web 应用程序,使用 StandardManager 进行会话(在内存中)。由于会话可能会变得非常大(20M+),堆空间不足是一个严重的问题。如果可能,用户希望将会话保留几个小时,但宁愿驱逐会话也不愿耗尽堆空间。供应商似乎没有在会话对象中正确实现 Serializable,因此切换到持久会话管理器实现不是一种选择。
Tomcat 允许设置一个 maxActiveSessions 属性,该属性将限制管理器中的会话总数。但是,当达到该限制时,在某些现有会话到期之前,不会创建新会话。我们想首先破坏最近最少使用的会话。
理想情况下,我们希望在堆使用量接近“Xmx”设置时使一些最近未使用的会话过期,即使它们还不够老而无法无条件过期。一个非常古老的 Tomcat 开发人员邮件列表线程建议这可能允许拒绝服务攻击*,但是,由于此应用程序仅在公司网络中可用,我们并不担心。
我考虑过扩展 StandardManager 以覆盖 processExpires() 并在堆使用量大于最大值的 85% 时破坏额外的会话。但是,这在实践中似乎有点问题。如果堆的大部分未被引用,并且垃圾收集器将能够收集大量对象(如果它不想运行)以将堆减少到最大值的 50%,该怎么办?我会不必要地过期会话。我想我们可以通过一些激进的垃圾收集设置来减轻这种风险。另外,我怎么知道会话过期节省了多少内存?我必须等待几个 GC 周期才能确定。也许我可以采取保守的方法,在每个后台进程周期中最多删除 N 个会话,直到内存降至可接受的阈值以下。
有没有人解决过这个问题?作为短期解决方案,我们正在增加堆大小,但这种创可贴也有其缺点。
- 他们指的是一个公共站点,其中将在登录前创建会话。有人可能会导致创建许多新会话并挤出实际使用的会话。
更新:我们对系统架构确实没有太多控制权,而且我们特别不能减少会话使用。但是,我们可以随心所欲地使用容器。然而,Tomcat 是唯一受供应商支持的开源 servlet 容器。