HttpSession中的信息太多了

时间:2010-01-27 10:08:56

标签: java session servlets

你怎么看待这个问题?

我们在HttpSession中确实有太多信息,因为计算了大量信息,最终需要在请求之间存储一些大的对象图。

使用memcache等任何缓存是否合适?或者它是否与增加JVM的内存相同?

担心在请求之间将其存储在数据库中。如果我们得到你会用什么 OutOfMemory错误?

谢谢。

2 个答案:

答案 0 :(得分:7)

我认为真正的重点是数据的生命周期


考虑一下HttpSession的这两个特征:

  • 当在群集中时,容器负责复制 HttpSession。这很好(你不必自己管理),但如果这会导致过多的交换,那么在性能方面可能会很危险......如果你的应用程序没有集群,那就忘了这一点。
  • HttpSession的生命周期可能是几分钟或几个小时,也就是用户保持活动状态。这非常适合具有生命周期的信息(连接信息,首选项,授权......)。但它不适用于从一个屏幕到下一个屏幕有用的数据,我们称之为瞬态+数据。

如果您有群集需求,数据库会负责处理。但要注意,你不能在内存中缓存任何内容。

在数据库中存储的生命周期更长(在会话之间持续存在,甚至在重新启动之间!),因此问题甚至是值得的(除了因性能问题而交换内存问题)。

我认为这对于预期寿命不会持久的数据来说是错误的方法......


瞬态数据

如果数据仅对一个请求有用,那么它通常存储在HttpRequest中,没问题。

但如果它被用于一些请求(一个屏幕内的交互,或者像助手那样的屏幕序列......),HttpRequest太短而无法存储它,但是HttpSession太长了。需要定期清理数据。

并且 HttpSession中的许多内存问题与此类数据有关,这些数据是暂时的但未清除(完全忘记,或者在异常情况下未清除,或者当用户不尊重时常规流程:点击Back,使用上一个书签,clic在不同的菜单上等等。

缓存库以获得正确的生命周期

为了完全避免这种清理工作(并在出现问题时避免OutOfMemory的风险),您可以将信息存储在具有正确生命周期的数据结构中。由于容器不提供此功能(无论如何它都与应用程序相关),您需要使用缓存库(如上所述;我们使用EhCache)自己实现它。

这个想法是你有一个技术代码(与一个功能页面无关,但是全局实现,例如使用ServletFilter ......),确保在不再需要对象之后始终进行清理。

您可以使用以下策略中的一个(或多个)来清理缓存来设计此缓存。每个政策都与功能寿命相关:

  • 对于仅与一个屏幕相关的数据(但有几个请求:重新加载屏幕,Ajax请求......),缓存一次只能存储一个屏幕的数据(对于每个会话),称之为“currentScreenCache” 。这保证了,如果用户进入另一个屏幕(即使是以非托管方式),新屏幕将覆盖“currentScreenCache”信息,并且可以对先前信息进行垃圾收集。
  

实现思路:每个请求必须携带其screenId,负责清除缓存的技术代码检测当前的HttpSession id当前screenId与缓存中的那个不匹配的时间。然后它清除或重置缓存中的该项。

  • 仅用于一系列连接屏幕(称为功能模块)的数据,同样适用于模块级别。
  

实现:与以前一样,每个请求都必须携带模块ID ...

  • 对于重新计算成本高昂的数据,可以将缓存库配置为存储最后的X个计算值(之前的那些被认为不太可能在不久的将来有用)。在典型的使用中,会定期询问相同的内容,因此您有许多缓存命中。在密集使用时,达到X限制并且内存不会膨胀,从而防止OutOfMemory错误(以下次重新计算为代价)。
  

实现:缓存库原生支持这个限制因素,还有几个......

  • 对于只有几分钟有效的数据,缓存库可以原生配置为在延迟后丢弃它...

  • ......更多信息,请参阅缓存库配置以了解其他想法。

注意:每个缓存可以是应用程序范围的,也可以是特定于用户的,HttpSession ID,公司ID或其他功能值......

答案 1 :(得分:2)

HttpSession确实不能很好地扩展,但这主要与聚类有关。这是一种方便,但在某些时候,你最好使用memcache或Terracotta或EHCache之类的东西来保持请求之间(或用户之间)的数据。