我们有一个用例,我们想要一个内存缓存,它可以存储具有不同TTL的密钥和值的能力。我们知道一些像Guava,Hazelcast和Ehcache这样的内存缓存。我们尝试使用Guava,但它遇到了使用expireAfterAccess和expireAfterWrite方法决定TTL的问题。这些将具有缓存中所有行的常量值。所以,这就是问题所在。因此,此处所有数据将在写入X小时后过期。虽然TTL会有所不同。但是我想要一些东西,其中当设置键,值对时,我也可以在那时设置TTL。
另外,我们正在使用dropwizard框架,因此内存缓存很容易与DropWizard Framework集成。
请在内存缓存中建议一些我们应该用于我们的用例。
由于
答案 0 :(得分:1)
前段时间我处于同样的情况,并没有发现Guava的缓存对我的用例非常有用;它看起来有点太复杂了。我在 .NET 中寻找像HttpRuntime.Cache这样的东西。由于它不是一个如此重要的功能,我决定自己快速实现它,然后再回到它。它可能是错误的或不是最优化的。
我使用SHA256(256符合FIPS合规性)来保留它们的哈希值,以便我可以快速找到它们;但是你的用例可能有更好的方法。此外,我的对象中包含过期时间,因此您可能需要修改代码以在某处存储过期时间。
private final ExecutorService executorService;
private final ConcurrentHashMap<String, MyObject> objectCache = new ConcurrentHashMap<>();
private Instant lastObjectCacheCleanupTime = Instant.now();
private static final TemporalAmount cacheCleanupFrequency = Duration.ofHours(1);
private void cacheObject(String encodedObject, MyObject object) {
executorService.submit(() -> {
objectCache.put(DigestUtils.sha256Hex(encodedObject), object);
synchronized (objectCache) {
if (Instant.now().isAfter(lastObjectCacheCleanupTime.plus(cacheCleanupFrequency))) {
lastObjectCacheCleanupTime = Instant.now();
objectCacheCleanup();
}
}
});
}
private Optional<MyObject> getObjectFromCache(String encodedObject){
String digest = DigestUtils.sha256Hex(encodedObject);
if (!objectCache.containsKey(digest)) {
return Optional.empty();
}
MyObject myObject = objectCache.get(digest);
if (myObject.isExpired())
objectCache.remove(digest);
return Optional.empty();
}
return Optional.of(myObject);
}
private void objectCacheCleanup() {
for (Map.Entry<String, MyObject> digestObjectEntry : objectCache.entrySet()) {
if (digestObjectEntry.getValue().isExpired()) {
objectCache.remove(digestObjectEntry.getKey());
}
}
}
答案 1 :(得分:1)
您可以使用 Memcached 。 Java有不同的memcached客户端 https://code.google.com/p/memcached/wiki/Clients#Java
我使用过spymemcached客户端。 示例来自:https://code.google.com/p/spymemcached/wiki/Examples
//获取连接到多个服务器的memcached客户端
MemcachedClient c=new MemcachedClient(
AddrUtil.getAddresses("server1:11211 server2:11211"));
//尝试获取一个值,最多5秒,如果没有返回则取消
Object myObj=null;
Future<Object> f=c.asyncGet("someKey");
try {
myObj=f.get(5, TimeUnit.SECONDS);
} catch(TimeoutException e) {
// Since we don't need this, go ahead and cancel the operation. This
// is not strictly necessary, but it'll save some work on the server.
f.cancel(false);
// Do other timeout related stuff
}
同样,您可以使用不同的ttl
设置值Future<Object> f=c.set(key, ttl, data);
在dropwizard中,您可以实现托管接口以初始化和停止memchached客户端 http://dropwizard.github.io/dropwizard/manual/core.html#managed-objects
public class MemcachedManger implements Managed {
private MemcachedClient client;
public MemcachedManger() {
// write a constructor for initializing custom dependencies of this class
}
@Override
public void start() throws Exception {
// create new object of memcachedClient
this.client=new MemcachedClient(AddrUtil.getAddresses("server1:11211 server2:11211"));
}
@Override
public void stop() throws Exception {
client.shutdown();
}
// define get and put and any other custom methods using functionality provided by spymemchached client
}
答案 2 :(得分:1)
您可以使用Hazelcast。他们有一个方法来放置一个TTL值的条目。参见http://docs.hazelcast.org/docs/3.4/javadoc/com/hazelcast/core/IMap.html#put(K,V,long,java.util.concurrent.TimeUnit)
来自Javadoc:
使用给定的ttl(生存时间)值将条目放入此地图。进入将在ttl之后到期并被逐出。如果ttl为0,那么该条目将永远存在。
答案 3 :(得分:0)