Tuesday, June 8, 2021

Caching using Hazelcast

Caching is one of the important aspect when we do system design as it enhance the performance.

In many of my applications I have used Ehcache as a cache provider with Spring applications. One of the problem with Ehcache is ; the cache resides in Single Node. 

Let's consider the below scenario:

Suppoe, we have an application where we have a method which provides Book details based on isbn provided in input. The method to findBookByIsbn is costly & cache is implemented.

Now, we call findBookByIsbn for isbn 1 & through Load Balancer, it goes to Node 1 & it fetches the data from DataBase & store in cache.

Now, another call is made to findBookByIsbn for isbn 1 & through Load Balancer, it now goes to Node 2. In this case it again fetches the data from DataBase & store in cache.

Hence, for same data (isbn=1) the db call is again made in DataBase as the cache resides in each node seperately. 

The architecture is deplicted in below image



Now, you can solve this problem by creating an Embedded Distributed Cache (aka Replicated Cache). In this case, Cache of Node 1 interacts with Node 2 & replicates the data. The architecture will look like below:





This technique can be implemented using Ehcache with JGroups.


EHCache Replicated Cache Tutorial Links:


As in Ehcache-Jgroups combination, we need to do lot of manual configuration, another good alternative is using Hazelcast. In this note, I am going to give you the steps you required to use HazelCast as cache manager

Pre-requisite:

Requied Java Version: 8

Spring Framework Verion used: 4.3.30.RELEASE

The Cache data type should implement Serializable interface

Step #1: Adding Maven dependency for Hazelcast Spring integration & Spring Context upport

                <dependency>

<groupId>com.hazelcast</groupId>

<artifactId>hazelcast-spring</artifactId>

<version>4.2</version>

</dependency>

        <dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context-support</artifactId>

<version>4.3.30.RELEASE</version>

</dependency>

 Step #2: Defing the method. The method must be defined in a Spring Bean class (Class having annotation Service/Component or defined in XML)

@Cacheable("bookIsbnCache")

public Book findBookByIsbn(String isbn) {

        // DB / Service call goes here 

        }

Step #3: Define the cache in application context xml

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:cache="http://www.springframework.org/schema/cache"

xmlns:hz="http://www.hazelcast.com/schema/spring"

xmlns:mvc="http://www.springframework.org/schema/mvc"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="

        http://www.springframework.org/schema/beans     

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/context 

        http://www.springframework.org/schema/context/spring-context.xsd

        http://www.springframework.org/schema/mvc

        http://www.springframework.org/schema/mvc/spring-mvc.xsd

       http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd

       http://www.hazelcast.com/schema/spring

       http://www.hazelcast.com/schema/spring/hazelcast-spring.xsd">

<!-- Other bean definition-->

<cache:annotation-driven
cache-manager="cacheManager" />

<hz:hazelcast id="instance">
<hz:config>

<hz:cluster-name>TestHzCluster</hz:cluster-name>

<!--  used for clustering.
<hz:network port="5701" port-auto-increment="false">
<hz:join>
<hz:multicast enabled="false" />
<hz:tcp-ip enabled="true">
<hz:members>x.x.x.x, y.y.y.y</hz:members>
</hz:tcp-ip>
</hz:join>
</hz:network>
-->

<hz:map name="bookIsbnCache" time-to-live-seconds="60"
in-memory-format="BINARY">
<hz:eviction eviction-policy="LRU"
max-size-policy="PER_NODE" size="100" />
</hz:map>
</hz:config>
</hz:hazelcast>

<bean id="cacheManager"
class="com.hazelcast.spring.cache.HazelcastCacheManager">
<constructor-arg ref="instance" />
</bean>

</beans>

That' it. You can deploy your code in different ports in localhost & you will be able to see the cache is replicated among differnt nodes.

Below is the link for working demo:

https://github.com/souravdalal/SpringHazelcastCacheDemo

Furthur Reading:

Cache Topologies:




Hazelcast with Spring Boot:



1 comment:

Convert Java Project from Log4j 1 to Log4j2

Many times while working on old Java projects we find Log4j 1.x is used. But as the Log4j2 is the new one; hence to upgrade to Log4j2 we nee...