应该使用哪种内存缓存?

时间:2015-04-15 05:42:24

标签: java guava ehcache hazelcast dropwizard

我们有一个用例,我们想要一个内存缓存,它可以存储具有不同TTL的密钥和值的能力。我们知道一些像Guava,Hazelcast和Ehcache这样的内存缓存。我们尝试使用Guava,但它遇到了使用expireAfterAccess和expireAfterWrite方法决定TTL的问题。这些将具有缓存中所有行的常量值。所以,这就是问题所在。因此,此处所有数据将在写入X小时后过期。虽然TTL会有所不同。但是我想要一些东西,其中当设置键,值对时,我也可以在那时设置TTL。

另外,我们正在使用dropwizard框架,因此内存缓存很容易与DropWizard Framework集成。

请在内存缓存中建议一些我们应该用于我们的用例。

由于

4 个答案:

答案 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)

免责声明:我为Terracotta(Software AG)工作

Ehcache提供此功能。

创建Element后,可以在将其放入缓存之前在其上设置TTL和TTI。