gpt4 book ai didi

java - 使用 Terracotta 的 EHCache 如何处理分布式堆的逐出?

转载 作者:行者123 更新时间:2023-11-30 11:55:04 25 4
gpt4 key购买 nike

我们最近开始将 EHCache 与 Terracotta 结合使用,为应用程序数据运行分布式数据缓存。假设任何客户端节点都有大约 2gb 的堆,而服务器节点有 8gb。我们生成大量数据,每天大约 1.5GB。

通常,任何一个客户端都会使用特定日期的数据集(大约 1.5gb),但服务器显然必须保存所有这些数据。

当堆变大时,我希望过期的工作方式是基于 LRU。因此,如果任何特定的 L1 客户端缓存变得太大(例如,从第 1 天切换到第 2 天),我希望它从 L1 中逐出所有第 1 天的数据。如果在我们获得第 6 个数据集时 L2 变得太大,那么最旧的数据集将完全过期。对于生存时间或闲置时间值应该是多少,我真的没有任何意见,所以我没有设置它们。

经过几天的研究,我认为它并没有像我预期的那样工作。例如,我运行了一个 L2 最大元素为 4 的测试。我用四个元素填充了它。然后我去放了第五个元素。 Cache.put() 无异常返回,但紧随其后的具有相同键的 Cache.get() 返回 null!

所以我的问题是,如何让 EHCache+Terracotta 做我想做的事,或者至少做一些接近的事?

最佳答案

经过一番折腾后,发现神秘的行为是由 L1 缓存是否知道 L2 缓存中的内容决定的。附加的单元测试意味着成对执行,成对的每个元素在单独的 JVM 中运行以避免 EHCache 单例。

我认为行为良好的 L1->L2 关系应该起作用的方式是,如果你没有错误地执行 .put(),你应该能够在没有错误的情况下立即执行相同键的 get()问题(假设没有其他同时运行的线程在搞乱东西)。但是,对于 Terracotta EHCache,如果 .put() 需要驱逐某些东西,驱逐不会发生,并且 put() 会被静默忽略,除非 L1 客户端“知道”可以驱逐的键。在 *JVM2 测试中,它通过使用 .getAllWithLoader() 找出其他键,然后 *JVM2 测试按预期工作。

因此,我们为解决原始问题所做的工作是让客户端定期执行 .getAllWithLoader()。然后我们可以确定所有驱逐规则都得到遵守。

package com.mine;

import java.io.Serializable;

import junit.framework.TestCase;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.Configuration;
import net.sf.ehcache.config.TerracottaClientConfiguration;
import net.sf.ehcache.config.TerracottaConfiguration;

public class CacheEvictionTest extends TestCase {

private static final String SERVER = "localhost:9510";
private CacheManager cacheManager;
private Cache cache;
private final Serializable keyA = "a";
private final Serializable keyB = "b";
private final Serializable keyC = "c";

@Override
protected void setUp() throws Exception {
Configuration configuration = new Configuration();
TerracottaClientConfiguration terracottaConfig = new TerracottaClientConfiguration();
terracottaConfig.setUrl(SERVER);
configuration.addTerracottaConfig(terracottaConfig);

int maxElementsInMemory = 1;
int maxElementsOnDisk = 2;
long timeToIdleSeconds = 15;
long timeToLiveSeconds = 15;
String cacheName = "TEST_CACHE";
CacheConfiguration amoebaCache = new CacheConfiguration(cacheName, maxElementsInMemory).statistics(true)
.terracotta(new TerracottaConfiguration())
.logging(true)
.maxElementsOnDisk(maxElementsOnDisk)
.timeToIdleSeconds(timeToIdleSeconds)
.timeToLiveSeconds(timeToLiveSeconds);
configuration.addCache(amoebaCache);
configuration.addDefaultCache(new CacheConfiguration("default", 0));

cacheManager = new CacheManager(configuration);
cache = cacheManager.getCache(cacheName);
}

@Override
protected void tearDown() throws Exception {
if (cache != null) {
cache.removeAll();
cache.clearStatistics();
}
}

public void testMaxElementOnDiskEvictionJVM1() throws Exception {
cache.clearStatistics();

cache.put(new Element(keyA, keyA));
cache.put(new Element(keyB, keyB));

cache = null;
}

public void testMaxElementOnDiskEvictionJVM2() throws Exception {
assertEquals(2, cache.getSize());

for (Object key : cache.getKeys()) {
cache.get(key;
}

cache.put(new Element(keyC, keyC));

assertEquals(2, cache.getSize());
assertNotNull(cache.get(keyC));
}

public void testEvictsExpiredElementsFromDiskWhenNotInMemoryAndWeNeverKnewAboutItJVM1() throws Exception {
cache.clearStatistics();
cache.put(new Element(keyA, keyA));

cache = null;
cacheManager = null;
}

public void testEvictsExpiredElementsFromDiskWhenNotInMemoryAndWeNeverKnewAboutItJVM2() throws Exception {
cache.clearStatistics();

for (Object key : cache.getKeys()) {
cache.get(key;
}
assertEquals(0, cache.getStatistics().getEvictionCount());

Thread.sleep(20000);

assertEquals(1, cache.getStatistics().getEvictionCount());
}
}

关于java - 使用 Terracotta 的 EHCache 如何处理分布式堆的逐出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5225080/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com