Infinispan 9,复制缓存即将过期,但不允许将它们从 JVM 堆中删除
Infinispan 9, Replicated Cache is Expiring Entries but never allows them to be removed from JVM heap
正在对 infinispan/jgroups 之上的集群解决方案进行一些内部测试,并注意到由于对 expiration-reaper 的引用,过期的条目永远不会符合 GC 的条件,同时有超过 1集群中启用过期/禁用驱逐的节点。
由于一些系统问题,正在使用以下版本:
- JDK 1.8
- Infinispan 9.4.20
- JGroups 4.0.21
在我的示例中,我使用了一个简单的 Java 主场景,放置特定数量的数据,期望它们在特定时间段后过期。过期确实发生了,因为它可以在访问过期条目和相应的事件侦听器(如果已配置)时得到确认,看起来它永远不会从可用内存中删除,即使在显式 GC 之后或 while接近 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 显示相同的行为(有意义的过期
收割者是一样的)
- 启用逐出并不能解决问题,只是保留
“过期”引用计数在最大限制之间。如果这是
达到相当快,实时条目上发生随机驱逐
以及(默认删除策略)!!
- 如果我将缓存条目更改为本机字符串,那么,
infinispan.MortalCacheEntries 正在从堆中删除 space
在下一个 GC 周期中,与自定义对象相比,在过期并被标记为过期收割机时!!
- 仅在一个节点中启用过期收割器没有解决
问题,并可能破坏故障转移机制。
- 已升级到 infinispan 10.1.8 Final ,但遇到同样的问题。
因为似乎没有其他人有同样的问题或使用原始对象作为缓存条目,因此没有注意到这个问题。
在复制并幸运地追踪到根本原因后,出现以下几点:
- 始终为将要通过 replicated/synchronized 缓存传输的自定义对象实施可序列化/
hashCode
/equals
。
- 永远不要放置原始数组,因为
hashcode
/ equals
不会被有效计算 -
- 不要在复制缓存上使用删除策略启用逐出,因为达到最大限制后,条目将被随机删除 - 基于 TinyLFU - 而不是基于过期计时器并且永远不会从JVM 堆。
正在对 infinispan/jgroups 之上的集群解决方案进行一些内部测试,并注意到由于对 expiration-reaper 的引用,过期的条目永远不会符合 GC 的条件,同时有超过 1集群中启用过期/禁用驱逐的节点。 由于一些系统问题,正在使用以下版本:
- JDK 1.8
- Infinispan 9.4.20
- JGroups 4.0.21
在我的示例中,我使用了一个简单的 Java 主场景,放置特定数量的数据,期望它们在特定时间段后过期。过期确实发生了,因为它可以在访问过期条目和相应的事件侦听器(如果已配置)时得到确认,看起来它永远不会从可用内存中删除,即使在显式 GC 之后或 while接近 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 显示相同的行为(有意义的过期 收割者是一样的)
- 启用逐出并不能解决问题,只是保留 “过期”引用计数在最大限制之间。如果这是 达到相当快,实时条目上发生随机驱逐 以及(默认删除策略)!!
- 如果我将缓存条目更改为本机字符串,那么, infinispan.MortalCacheEntries 正在从堆中删除 space 在下一个 GC 周期中,与自定义对象相比,在过期并被标记为过期收割机时!!
- 仅在一个节点中启用过期收割器没有解决 问题,并可能破坏故障转移机制。
- 已升级到 infinispan 10.1.8 Final ,但遇到同样的问题。
因为似乎没有其他人有同样的问题或使用原始对象作为缓存条目,因此没有注意到这个问题。 在复制并幸运地追踪到根本原因后,出现以下几点:
- 始终为将要通过 replicated/synchronized 缓存传输的自定义对象实施可序列化/
hashCode
/equals
。 - 永远不要放置原始数组,因为
hashcode
/equals
不会被有效计算 - - 不要在复制缓存上使用删除策略启用逐出,因为达到最大限制后,条目将被随机删除 - 基于 TinyLFU - 而不是基于过期计时器并且永远不会从JVM 堆。