6

在我的项目中,我使用 ehcache 来存储登录的用户详细信息和其他一些信息(哪个应用程序将在运行时使用它而不是从数据库中获取)。以下是我的ehcache配置:

<cache 
    name="normalCache"
    maxElementsInMemory="50000" 
    eternal="false"
    timeToIdleSeconds="1800" 
    timeToLiveSeconds="0"
    overflowToDisk="false"
    memoryStoreEvictionPolicy="LRU"
/>

但问题是大部分时间会话超时发生(即使用户不是非活动状态超过 30)。有时它会持续 10 分钟,...

所有操作都将尝试从 ehcache 中检索每个请求的用户对象。

我不确定 ehcache 将如何确定到期时间。

4

3 回答 3

5

当满足以下条件之一时,Ehcache 会从缓存中驱逐对象:

  1. 超过timeToIdle几秒钟没有从 ehcache 访问对象(读取或更新)。timeToIdle如果未设置,则此规则不适用。换句话说,一个对象有资格无限期地保留在缓存中,即使它在timeToIdle未设置时从未从缓存中访问(读取或更新)。

  2. 对象已在缓存中超过timeToLive几秒钟。timeToLive如果未设置,则此规则不适用。换句话说,一个对象有资格无限期地保留在缓存中。

  3. 缓存中的项目数已达到maxElementsInMemory限制。在这种情况下memoryStoreEvictionPolicy,开始行动并删除匹配驱逐策略的元素,直到缓存中的元素数量小于maxElementsInMemory限制,即使这些项目根据条件 1 和 2 有资格在缓存中。

希望澄清一下!

于 2014-02-15T17:23:23.767 回答
1

ehcache 不保证将所有元素保留 30 分钟。

在您的配置中,您的 maxElementsInMemory 为 50000。也许您曾一度达到 50000,因此当您将 overflowToDisk 设置为 false 时,最近最少使用的条目将被驱逐。

于 2014-02-12T13:44:47.387 回答
0

前言

我计划使用 ehCache 作为会话管理实现首先检查,如果你不能使用已经提供的,并且可能更适合会话实现。如果您使用的是 Web 容器或完整的 jee 服务器,您真的应该先尝试一下


为什么

好的。你肯定不会用正确的简单方法来做这件事。这里有一些提示,为什么您可能希望使用 ehCache 进行会话

  1. 您的服务不是 jee 服务器/Web 容器的一部分。
  2. 您的服务是无状态的,但有时您需要状态(框架代码)。
  3. 由于您和可区分客户端之间的代理,您无法区分调用,例如,您是某种服务/服务的中间件,默认情况下不提供可区分数据,但有条件地使用 userId 或 sessionId 等参数,但不是组成性的。
  4. 您只是没有 RTFM,而是想按照自己的方式来做。

对于 1,请检查是否可以选择像码头这样的网络容器。你当然会使用整个会话的网络访问,这不会为你弹出。

对于 2,请检查,如果Apache Shiro不会做你想做的事。如果没有,ehCache 可能是你的朋友。

3 ... 欢迎来到俱乐部。

对于 4... 好吧,我想如果您没有阅读手册,您也不会阅读此内容。


如何

如果您想使用 ehCache 实现会话管理,请确保您的数据是可序列化的。这将减少问题并让您使用 ehCache 的敏感功能。即持久化到磁盘、缓存节点、从中恢复等等。

不要为每个会话使用一个缓存,而是所有会话使用一个缓存。是缓存上的键,值将转到. 不要忘记并发(想想 ajax 调用)。最好使用from 。但也许你是Heinz M. Kabutz 博士,并找到一种更酷的方法来做到这一点。sessionIdMapConcurrentHashMapjava.util.concurrent

我发现使用大小而不是存储元素的数量非常有帮助。您可能不知道以后会存储哪些数据/对象。不要忘记设置持久性策略。我在这里使用存储到临时文件夹。

<?xml version="1.0" encoding="UTF-8"?>
<ehcache
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd"
    updateCheck="true"
    monitoring="autodetect"
    dynamicConfig="true">

    <diskStore path="java.io.tmpdir"/>

    <cache name="vocCache"
        eternal="false"
        maxElementsInMemory="100MB"
        maxElementsOnDisk="1GB"
    timeToIdleSeconds="3600"
    timeToLiveSeconds="0"
    memoryStoreEvictionPolicy="LRU"
    diskExpiryThreadIntervalSeconds="60">
    <persistence strategy="localTempSwap" />
</cache>

因为我们想实现一个会话管理器,所以我们不关心timeToLiveSeconds. 会话在一定的空闲时间后超时。因此,我们不将元素限制为最大 ttl,而是使用timeToIdleSeconds让元素超时。不要打扰timeToIdleSecondsandtimeToLiveSeconds因为您可以为元素设置特定值以便以后添加。

驱逐

关于到期时间的注释。内存中的元素永远不会因为配置的时间而被驱逐。内存将累积,直到达到定义的内存约束。因此,如果您定义 100 个元素,如果添加了 101 个元素,memoryStoreEvictionPolicy将触发下注并且一个元素将 - 在此配置中 - 刷新到磁盘 (ehCache 2.2)。对于磁盘存储,将有一个线程检查到期时间(diskExpiryThreadIntervalSeconds)。请参阅文档。因此,您必须检查从缓存中检索到的元素,isExpired()以确保它没有过期。


所以最后,你会得到这样的结果:

得到

Cache cache = CacheManager.getInstance().getCache(CACHE_NAME);
Element elem = cache.get(identifier);
if (elem == null) 
{
   throw new SessionNotFoundException(identifier);
}
if (elem.isExpired())
{
   throw new SessionExpiredException(identifier);  
}

return elem.getObjectValue();

Cache cache = CacheManager.getInstance().getCache(CACHE_NAME);
// We use ttl = 0 and tti=<ttlInMinutes>, because session timeout is based on session idle timout.
element = new Element(identifier, new SessionElement(), Boolean.FALSE, (int) (timeToLive / VALUE_MS), 0);
cache.put(element);
于 2014-02-17T08:00:34.230 回答