How to Connect Payara to External Hazelcast Grid

Photo of Rudy De Busscher by Rudy De Busscher

The Domain Data Grid feature of the Payara products is powered by the Hazelcast library. It provides the necessary functionality for the Deployment Group (clustering functionality), Cache functionality, CDI cluster singleton, and monitoring data storage within Payara to name just a few features.

Since Hazelcast can cluster multiple instances into a data grid, it is possible to create a Hazelcast grid that comprises the Payara instances and some other instances included in other applications running outside of Payara.

There are some limitations, but we'll explore a few options to exchange data between an application running on a Payara product and an application using Hazelcast outside of Payara.

Connecting to Payara

Let us first try to connect to the Domain Data Grid within Payara from another Java program. First of all, we need the same version of Hazelcast that is running inside Payara. As of Payara version 5.2021.1, Hazelcast 4.1 is included (older versions contains Hazelcast 3.12).  The versions must match due to the synchronization differences that exist within Hazelcast. Otherwise, the creation of the grid will fail and data will not exchange between the instances.

We need the following dependency when using Maven as the build tool:

     <dependency>
         <groupId>com.hazelcast</groupId>
         <artifactId>hazelcast</artifactId>
         <version>4.1</version>
     </dependency>

 

Other required information to make the connection is the IP address and port of the data grid within Payara and the cluster name.  The address can be found in the log when Payara Server and Payara Micro starts up.

[2021-03-12T16:16:49.865+0100] [Payara 5.2021.1] [INFO] [] [fish.payara.nucleus.cluster.PayaraCluster] [tid: _ThreadID=139 _ThreadName=Executor-Service-5] [timeMillis: 1615562209865] [levelValue: 800] [[
Data Grid Status
Payara Data Grid State: DG Version: 4 DG Name: development DG Size: 1
Instances: {
DataGrid: development Name: server Lite: false This: true UUID: a6092531-f957-46b8-a185-d6ac12274606 Address: /192.168.0.174:4900
}]]

It indicates that the Grid address is /192.168.0.174:4900 and in the same log message it also indicates the cluster name and by default this is development.

This cluster name, or Data Grid Group Name as it is called within Payara, can be changed through the configuration if you want to use another name. Have a look at our documentation for how to change this value.

With that information, we can start another Hazelcast instance and link it to the Payara Domain Data Grid. The Java code to do this is:

Config config = new Config();
config.setClusterName("development");

config.getNetworkConfig().getJoin().getTcpIpConfig().setEnabled(true);
config.getNetworkConfig().getJoin().getTcpIpConfig().addMember("192.168.0.174:4900");

PartitionGroupConfig partitionGroupConfig = config.getPartitionGroupConfig();
partitionGroupConfig.setEnabled( true )
.setGroupType( PartitionGroupConfig.MemberGroupType.HOST_AWARE );


HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance(config);

 

In addition to the address and cluster name, we also need to match the Partition Group information from the Payara Data Grid. When running this code, you will see that the log indicates that both Hazelcast instances are joined.

You might also see that there are errors when Hazelcast tries to synchronize the data between the different instances.

com.hazelcast.nio.serialization.HazelcastSerializationException: There is no suitable de-serializer for type 1. This exception is likely caused by differences in the serialization configuration between members or between clients and members.
at com.hazelcast.internal.serialization.impl.AbstractSerializationService.newHazelcastSerializationException(AbstractSerializationService.java:256)
at com.hazelcast.internal.serialization.impl.AbstractSerializationService.readObject(AbstractSerializationService.java:282)
at com.hazelcast.internal.serialization.impl.ByteArrayObjectDataInput.readObject(ByteArrayObjectDataInput.java:567)
at com.hazelcast.config.CacheConfig.readFactories(CacheConfig.java:684)
at com.hazelcast.config.CacheConfig.readData(CacheConfig.java:566)

This is because the Hazelcast grid can contain data that it can't read using the current classpath. In this case, you need to use the second option, using the Hazelcast client described in the next section.

But let us first continue by putting something in the Payara Domain Data Grid and read that data from an application running outside of the Payara runtime.

Within your Payara application, you can use the following construct within any CDI bean:

    @Inject
    private HazelcastInstance hazelcastInstance;

    private void storeInGrid(String data) {

        IMap<Object, Object> simpleMap = hazelcastInstance.getMap("simpleMap");
        
        simpleMap.put(CACHE_KEY, data);
        
    }

 

This will store some data in the Domain Data Grid using the Map functionality of Hazelcast. But of course you can use other constructs of Hazelcast like List, Queue, Set, etc.

Reading it from the application outside of Payara is done similarly: get the Map with the correct name and read the value for the same key.

Using Hazelcast Client

As mentioned above, when data is exchanged between the different Hazelcast instances, you might encounter errors due to the differences in the classpath of the environments. When you use the Hazelcast Client, these can be avoided as you just interact with the grid and don't synchronize the contents to your instance. Of course, this means that you don't have a single grid between the Payara Domain Data Grid and the external Hazelcast Instances.

The following code snippet can be used to connect to the Payara Domain Data Grid or another Hazelcast Grid from within an application running on Payara.

ClientConfig config = new ClientConfig();

config.getNetworkConfig().addAddress("192.168.0.174:4900");
config.setClusterName("development");

HazelcastInstance hzInstance = HazelcastClient.newHazelcastClient(config);

 

We instantiate a ClientConfig this time and define the address and cluster name. Once we have the Hazelcast Instance object, we can again access the Maps, Lists, Sets, Queues, etc ... just as before.

The examples described here are using a programmatic configuration. You can also configure the instances and the client using a configuration file.  For more information about changing the configuration of the Hazelcast instances within the Payara Data Grid, have a look at the documentation page.

Conclusion

As you have seen in the examples, it is possible to connect the Payara Domain Data Grid to another Hazelcast Grid. But due to the serialization mechanism that exchanges the data between the instances, you might encounter an error as some of the classes used by Payara are not available.  An alternative is to use the Hazelcast Client to connect to the other Grid and read and write information in that way. However, you still have many benefits like the possibility to define listeners, but some features can't be used like the Lock functionality since you have two separate grids in that case.

 

Comments