Hazelcast: Initiation
Today we are going to see how to implement Hazelcast, an in-memory data grid a.k.a. IMDG, one of the most known and used today. But, what is an IMDG? According to the definition of Hazelcast itself, it is a set of nodes connected in a network that allow sharing of their in-memory data among the applications that are part of the network. These nodes or their own clients are also known as Hazelcast instances.
The choice of Hazelcast for use in a project came in my case because of the need to have a single instance of an object to be shared, not only between different applications and clustered servers also. But sharing the hazelcast instance between different applications on the same server. This will be the scheme:
The example is focused only on the Hazelcast feature that allows us to share objects, avoiding duplication and significantly reducing execution times. And therefore obviating other important features such as the processing of large amounts of data, which are beyond the scope of this post/example.
Let’s start as always indicating the library needed for the operation of our example. In this case, with a single library, we will have everything we need: hazelcast-all. And here comes one of the important points of the example. If we indicate the library as a dependency of type compile in each of the projects. When creating the instance programmatically, as each application has its own classloader, the same number of hazelcast instances will be generated in the server. Therefore the library must be placed with provided scope and included inside the server itself, controlling better the creation of instances.
The next step will be to create a ServletContextListener in our application that is launched when it is started and that allows us to obtain the hazelcast instance. Whether we create a node of the Hazelcast cluster or connect as clients to one of the existing nodes, we will obtain an object of type HazelcastInstance that will allow us to manage the information of the same one.
The static class has several methods that allow you to create or obtain the instance of Hazelcast. When creating the instance programmatically we can indicate the different configuration options through the Config class that we can pass to the constructor. If we do not do it, it will be configured with the default values or those indicated in the hazelcast.xml file in the classpath.
Hazelcast allows the detection of nodes automatically and through various methods. But the best way is to configure it through the IP addresses of the member nodes or, as in this case, with the DNS names. Moreover, if we configure the connection in another way, once they recognize each other, they will communicate through this method.
Besides we will also indicate the name of the instance. Which as we saw in the previous Java code, will be used to obtain the instance of the node. In the example, we will use a characteristic of the configuration files, and it is the possibility of indicating certain values according to system properties.
The deployment of the servers will be done through a docker compose where we can see the configuration indicated above.
The application as we see in the docker compose we will be duplicated it in the server and it will allow us to check through a simple API the operation of hazelcast. We will have a resource that will store the value of a property and another resource that will allow us to obtain the value of the property.
Therefore when starting we will be able to see how the instances are created:
To store the values we will have different types of objects of type Collection such as Set, Queue, List or utilities that improve concurrencies such as FencedLock, ISemaphore, or AtomicReference.
Now we can invoke any of the APIs to store a value and any of the others to retrieve the stored value.
#curl --request POST 'http://localhost:8082/RestEasyService/rest/info/property/value'
{"machine":"tomcat-server2","property":"property","value":null}
#curl --request GET 'http://localhost:8080/DuplicateService/rest/info/property'
{"machine":"tomcat-server1","property":"property","value":"value"}
Finally, a few tips:
- The cluster should consist of at least three nodes.
- In case we use one of the concurrency utilities we must configure and CP subsystem.
- The nodes should be started as Docker containers or running the binaries they provide. And in the Java code using the API through a client.
As always, you can see all the code, here.