4

今天上班遇到一个问题:

想象一下,我有很多并发用户访问我的网站,每个用户都将自己的数据存储在用户会话中。考虑到我的 JVM 中可用的内存量有限,当并发活动会话达到容器 JVM 内存不足的点时会发生什么或应该发生什么?

我试图在 servlet 规范中找到关于应该发生什么的内容,但其中没有任何确定性,它只是说开发人员将有权访问会话对象等。这让我认为它必须是特定于提供者的。

以Tomcat为例,webserver是不是刚开始扔OutOfMemoryExceptions?或者它处理这个问题的方式更聪明,例如将会话分页到另一个缓存?或者其他方式一起?

4

2 回答 2

4

servlet 规范没有说明任何有关内存考虑的内容,因此您不会得到任何帮助。

除非特别配置,否则 Tomcat 将允许您使用 HttpSession 对象(实际上是它们的内容)用尽所有可用内存,最终 JVM 将开始抛出OutOfMemoryErrors,可能会使您的服务器停机(尽管 JVM 将继续运行,许多事情都会表现得......不可预测且不幸的是)。

如果单个请求开始在局部变量等中使用大量内存,则请求处理线程将受到影响OutOfMemoryError并停止处理当前请求。(我相信在这种情况下,请求处理线程实际上会被Tomcat请求处理线程池回收)。垃圾收集器可能会在此后不久运行并重新声明该请求使用的内存,并且您的服务器将稳定下来。

另一方面,如果你用完大量内存并将这些对象存储到用户的 sHttpSession中,那么 GC 将无法释放任何内存,并且您的服务器将不断遭受OutOfMemoryErrors 的影响。虽然 Tomcat 会在指定的时间表上过期会话(默认是在 30 分钟不活动之后),但会话清理线程可能会遇到一个OutOfMemoryErrorduring operation 并因此无法执行其职责,从而使整个情况更加复杂(因为实际上,HttpSessions 永远不会到期)。

有几种方法可以缓解上述不幸的情况。哪一个对您有意义取决于您的要求和环境。

  1. 增加堆大小。这显然只会让你到目前为止。如果您正在用相关对象填充 16GiB 堆HttpSession,那么您将达到商品硬件的极限,您不能简单地购买更大的盒子。

  2. 减少会话过期时间(默认为 30 分钟)。如果会话没有显式终止(例如,通过注销功能),则HttpSession对象及其所有内容会一直存在,直到过期间隔过去。如果您在大量废弃会话中拥有大量数据,则减少会话到期时间可能会给您一些喘息的空间。

  3. 停止将这么多数据放入用户的HttpSession. 虽然这似乎是一个令人讨厌的建议(“停止这样做”),但它确实是一个有效的建议:你真的需要在会话本身中存储这么多东西吗?使用某种数据存储(关系数据库、非关系数据库如 Cassandra、webcache 等)怎么样?也许将数据存储在磁盘上的文件中?虽然这些建议肯定会限制您快速访问数据的能力,但它们肯定是比让您的服务器在会话中大量内容的重压下崩溃更好的选择。

  4. 使用 Tomcat 的PersistentManager,它是一个会话管理器,能够将活动(但空闲)会话交换到某些外部存储(默认情况下可以使用基于文件和基于 JDBC 的存储机制)。当您找到其他地方将您推送的所有数据放入用户会话时,这可以让您走得很远。

除了 #4 之外的所有内容都适用于任何 servlet 容器。#4 应该对 JBoss 用户可用,因为 JBoss 在内部使用 Tomcat。对于其他容器,您可能会发现存在类似的功能。

于 2012-08-14T20:11:47.683 回答
0

通常,这取决于供应商。然而,容器经常可以自行决定将会话序列化到磁盘(如果会话数据可以序列化)。

如果容器可以做到这一点,它可以在需要时推出非活动会话,并在需要时再次恢复它们,更好地使用内存,从而推迟任何 OutOfMemoryExceptions。

于 2012-08-14T20:16:30.017 回答