Search code examples
hazelcast

How to configure replicated cache in Hazelcast cluster?


My Spring application consists of dozen microservices. Each microservice provides data, which does not change very often. In the order to reduce communication between microservices I am considering to start using Hazelcast.

My idea is that every microservice would have embedded Hazelcast. Microservices are running in same network and I suppose that Hazelcasts would form a cluster. Every microservice will put its data into local Hazelcast on startup and data will be copied to every other Hazelcast in the cluster. When a microservice would need to load data from other microservice, it would first look into local Hazelcast and only if data are missed from local cache, it would make network call.

Is it possible to configure something like this with Hazelcast? I already made a try, but data from a microservice happened to be distributed across all Hazelcast nodes in cluster.

I used very trivial configuration:

@Configuration
@EnableCaching
@Profile("hazelcast")
public class HazelcastCacheConfiguration {
    @Bean
    public Config hazelcastConfig() {
        return new Config()
                .setInstanceName("routes-cache")
                .addMapConfig(
                        new MapConfig()
                                .setName("ports-cache")
                                .setEvictionPolicy(EvictionPolicy.LRU)
                ).addMapConfig(
                        new MapConfig()
                                .setName("routes-cache")
                                .setEvictionPolicy(EvictionPolicy.LRU)
                ).setProperty("hazelcast.logging.type", "slf4j");
    }
}

I checked data replication across the cluster in Hazelcast Management Center. My sample set of data has only 13 records. The microservice has pushed 13 records on startup into local Hazelcast and in Management Center I have seen that there are 2 nodes in the cluster with 9 records on one node and 4 records on the node of other microservice.

Thank you in advance!


Solution

  • Hazelcast IMap is a partitioned data structure: each entry is mapped to a partition (based on hashing its key) and each member is designated as owner or backup of some partitions. What you describe can be accomplished by configuring a near cache on your IMap like this:

    @Bean public Config hazelcastConfig() { NearCacheConfig routesNearCache = new NearCacheConfig("routes-near-cache") .setInMemoryFormat(InMemoryFormat.OBJECT); return new Config() .setInstanceName("routes-cache") .addMapConfig( new MapConfig() .setName("routes-cache") .setEvictionPolicy(EvictionPolicy.LRU) .setNearCacheConfig(routesNearCache) ); // continue with the rest of config here }

    The near cache is a local cache of entries and works transparently on top of the IMap. First time you do a routesCache.get(K), the entry will be fetched from the (possibly remote) member that owns the partition to which K is mapped. The value is then cached in the local near cache and each subsequent routesCache.get(K) will be served locally. Near cache works with invalidation events (for example when a put happens on a particular key, that key's entry is removed from each near cache) to ensure values are maintained up-to-date.

    Another alternative you may consider is using a ReplicatedMap: in this case, each member maintains a full copy of all the data in the map, so reads are always local. You may consider this data structure if your dataset fits in each member's memory and your use case is mostly reads.