【问题标题】:Why ehcache doesn't propagate expiration events?为什么 ehcache 不传播过期事件?
【发布时间】:2014-10-10 15:26:49
【问题描述】:

为什么 ehcache 不传播过期事件?你是怎么处理的?

这是我的情况。我有两个使用 RMI 相互同步的节点。我的配置如下:

<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
        properties="peerDiscovery=manual, rmiUrls=//localhost:51001/sessionCache|//localhost:51002/sessionCache"/>

<cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
                                 properties="hostName=0.0.0.0, port=51002, socketTimeoutMillis=2000"/>

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

<cache name="sessionCache"
       maxEntriesLocalHeap="20000"
       maxEntriesLocalDisk="100000"
       eternal="false"
       diskSpoolBufferSizeMB="20"
       timeToIdleSeconds="60"
       memoryStoreEvictionPolicy="LRU"
       transactionalMode="off">

    <persistence strategy="localTempSwap"/>
    <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" properties="replicateAsynchronously=true" />
    <bootstrapCacheLoaderFactory
            class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
            properties="bootstrapAsynchronously=false"
            propertySeparator=","/>
</cache>

现在想象以下场景:

  1. 对服务器 A 的登录调用创建了会话,该会话被放入复制缓存中。
  2. 连续调用服务器 A 以从缓存中获取会话对象将为其重置 timeToIdleSeconds 计数器。
  3. 继续调用服务器 A 65 秒以确保服务器 B 上的会话将过期,在步骤 1 中将会话对象放入缓存后从未调用过该会话。
  4. 调用服务器 B。在内部,它将从本地缓存中删除会话对象,并调用 RegisteredEventListeners.internalNotifyElementExpiry,最终调用 RMISynchronousCacheReplicator.notifyElementExpired

在第 4 步中,我希望服务器 B 将 RmiEventType.REMOVE 发送到服务器 A。而 RMISynchronousCacheReplicator.notifyElementExpired 具有以下正文

public final void notifyElementExpired(final Ehcache cache, final Element element) {
    /*do not propagate expiries. The element should expire in the remote cache at the same time, thus
      preseerving coherency.
      */
}

看起来RMICacheReplicatorFactory 的创建者从未考虑过timeToIdleSeconds 驱逐算法。

在每个 cache.get() 之后手动调用 cache.replace() 是否是重置集群中 TTI (timeToIdle) 的唯一方法?

notifyElementExpired 中调用cache.remove() 的附加cacheEventListener 是从集群中删除过期元素的唯一方法吗?

【问题讨论】:

    标签: rmi ehcache


    【解决方案1】:

    好吧,我最终做了 hack。如果有更优雅的解决方案,请告诉我。

    我创建了额外的缓存事件监听器,看起来像这样

    class MyCacheEventListener(properties: Properties) extends CacheEventListener {
    
      override def notifyElementExpired(cache: Ehcache, element: Element): Unit = {
    
        cache.getCacheEventNotificationService.notifyElementRemoved(element, false)
      }
    
      override def notifyElementRemoved(cache: Ehcache, element: Element): Unit = {}
      override def notifyElementEvicted(cache: Ehcache, element: Element): Unit = {}
      override def notifyRemoveAll(cache: Ehcache): Unit = {}
      override def notifyElementPut(cache: Ehcache, element: Element): Unit = {}
      override def notifyElementUpdated(cache: Ehcache, element: Element): Unit = {}
      override def dispose(): Unit = {}
    }
    

    它负责向集群发送假的RmiEventType.REMOVE。它在配置中使用范围local 指定

    <cacheEventListenerFactory class="com.zzzz.MyCacheEventListenerFactory" listenFor="local" />
    

    为了刷新我必须在成功后这样做cache.get()

    cache.getCacheEventNotificationService.notifyElementUpdated(element, false)
    

    这很丑,但不知道我还能做什么。坦率地说,我认为 Terracotta 可以在他们的 RMICacheReplicatorFactory 中轻松实现它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-18
      • 2013-04-23
      • 1970-01-01
      • 2017-06-04
      相关资源
      最近更新 更多