分布式Hazelcast缓存中的异步值计算

时间:2019-03-06 12:14:52

标签: java caching hazelcast hazelcast-imap

当前设置

我在两个不同的计算机上运行一个应用程序的两个实例。两个应用程序节点共享分布式缓存的Hazelcast配置。高速缓存可以与常规IMap<String, SomeSerializableValue>正常工作。

问题

现在,我遇到了一种情况,可缓存值的计算速度慢且成本高。我想确保给定键的值仅在单个应用程序节点上计算。如果另一个节点获取了密钥的值,但计算仍在进行中,则该节点应等待计算完成。

理想的解决方案是这样的:

IMap<String, CompletableFuture<SomeSerializableValue>>

但是这种方法显然行不通,因为CompletableFuture不可序列化。

问题

Hazelcast中是否有其他解决方案可以满足我的要求?

例如,咖啡因的概念是AsyncLoadingCache。但是,它不是分布式的。 Hazelcast可以缓存异步计算的值吗?

2 个答案:

答案 0 :(得分:1)

Offloadable Entry Processor会工作吗?

这使您可以在边线线程中对Map.Entry.Value应用“长时间运行”的更新。

在运行更新时,读取调用将返回现有值。仅在更新计算完成后,写入才可见。

答案 1 :(得分:0)

我和你有同样的问题。

我试图通过调用传递的回调IF(如果键的值在缓存中不存在),来创建一个通用的kotlin类来读取和填充缓存(作为ConcurrentMap

因此,当我为HazelCast创建实例(用CompletableFuture包装值)

    companion object {

        fun <K, V> create(config: MapConfig, name: String) =
            Hazelcast.newHazelcastInstance()
                .apply {
                    this.config.addMapConfig(config)
                }.getMap<K, CompletableFuture<V>>(name)  //TRYING TO WRAP with CompletableFuture as the AsyncLoad cache does in caffeine
    }

尝试从缓存中读取时出现以下异常:

Failed to serialize 'java.util.concurrent.CompletableFuture'
com.hazelcast.nio.serialization.HazelcastSerializationException: Failed to serialize 'java.util.concurrent.CompletableFuture'
    at com.hazelcast.internal.serialization.impl.SerializationUtil.handleSerializeException(SerializationUtil.java:115)
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toBytes(AbstractSerializationService.java:175)
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toBytes(AbstractSerializationService.java:151)
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toData(AbstractSerializationService.java:136)
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toData(AbstractSerializationService.java:124)
    at com.hazelcast.spi.impl.NodeEngineImpl.toData(NodeEngineImpl.java:341)
    at com.hazelcast.spi.impl.AbstractDistributedObject.toData(AbstractDistributedObject.java:78)
    at com.hazelcast.map.impl.proxy.MapProxyImpl.putIfAbsent(MapProxyImpl.java:172)
    at com.hazelcast.map.impl.proxy.MapProxyImpl.putIfAbsent(MapProxyImpl.java:162)
    at cache.utility.caffeine.SuspendingCache$get$$inlined$read$1.invokeSuspend(

这是HZ API(包括其异步API) https://docs.hazelcast.org/docs/3.8/javadoc/com/hazelcast/core/IMap.html

我得出以下结论:


     (if (cache.containsKey(key)) {  //Read operations are thread-safe and are not blocking
            return cache.getAsync(key).await() // In Kotlin  kotlinx.coroutines.future.await(), in Java you would subscribe from this somehow
        } else {
            val value = callBack.invoke(key)
            cache.setAsync(key,value)
            return value
        }