Infinispan 9,复制缓存正在过期,但不允许将它们从 JVM 堆中删除

问题描述

正在对 infinispan/jgroups 之上的集群解决方案进行一些内部测试,并注意到由于过期收割机上的引用,而在集群中有 1 个以上的节点时,过期的条目永远不会符合 GC 的条件启用过期/禁用驱逐。 由于某些系统问题,正在使用以下版本:

  • JDK 1.8
  • Infinispan 9.4.20
  • jgroups 4.0.21

在我的示例中,我使用了一个简单的 Java 主场景,放置了特定数量的数据,期望它们在特定时间段后过期。过期确实发生了,因为它可以在访问过期条目和相应的事件侦听器(如果已配置)时确认,看起来它永远不会从可用内存中删除,即使在显式 GC 或同时接近 OOM 错误

所以问题是:

这真的是认行为吗,或者我缺少集群复制/到期/序列化的关键配置?

示例:

缓存管理器:

return new DefaultCacheManager("infinispan.xml");

infinispan.xml :

  <jgroups>
     <stack-file name="udp" path="jgroups.xml" />
  </jgroups>

  <cache-container default-cache="default">
     <transport stack="udp" node-name="${nodeName}" />
     <replicated-cache name="myLeakyCache" mode="SYNC">
        <expiration interval="30000" lifespan="3000" max-idle="-1"/>
     </replicated-cache>
  </cache-container>

认 UDP jgroups xml,如打包示例中所示:

.....

<UDP
        mcast_addr="${jgroups.udp.mcast_addr:x.x.x.x}"
        mcast_port="${jgroups.udp.mcast_port:46655}"
        bind_addr="${jgroups.bind.addr:y.y.y.y}"
        tos="8"
        ucast_recv_buf_size="200k"
        ucast_send_buf_size="200k"
        mcast_recv_buf_size="200k"
        mcast_send_buf_size="200k"
        max_bundle_size="64000"
        ip_ttl="${jgroups.udp.ip_ttl:2}"
        enable_diagnostics="false"
        bundler_type="old"
        thread_naming_pattern="pl"
        thread_pool.enabled="true"
        thread_pool.max_threads="30"
        />

虚拟缓存条目:

public class CacheMemoryLeak implements Serializable {
    private static final long serialVersionUID = 1L;
    Date date = new Date();
}

来自“服务”的示例用法

Cache<String,Object> cache = cacheManager.getCache("myLeakyCache");
cache.put(key,new CacheMemoryLeak());

一些信息/试用:

  • 当集群中只有一个节点或重启它们时 引用依次被清除。
  • 启用 Max-idle 显示相同的行为(有意义的到期 收割者是一样的)
  • 启用驱逐并不能解决问题,只会保留 “过期”引用计数在最大限制之间。如果这是 达到非常快,实时条目正在发生随机驱逐 还有(删除策略)!!
  • 如果我将 Cache 条目更改为原生字符串,则 infinispan.MortalCacheEntries 正在从堆空间中移除 在下一个 GC 循环中,与自定义对象相比,在过期并被过期收割者标记时!!
  • 仅在一个节点中启用到期收割者并没有解决问题 问题,并且可能会破坏故障转移机制。
  • 升级到 infinispan 10.1.8 Final,但面临同样的问题。

解决方法

因为似乎没有其他人有同样的问题或使用原始对象作为缓存条目,因此没有注意到这个问题。 复制并幸运地追查到根本原因后,出现以下几点:

  • 始终为即将通过复制/同步缓存传输的自定义对象实现 Serializable / hashCode / equals
  • 永远不要放置原始数组,因为 hashcode / equals 不会被有效地计算 -
  • 不要在复制缓存上使用移除策略启用驱逐,因为达到最大限制时,条目将随机移除 - 基于 TinyLFU - 而不是基于过期的计时器,并且永远不会从 JVM 堆中移除.

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...