dcsimg
December 11, 2016
Hot Topics:

What Is Hazelcast?

  • July 25, 2016
  • By Leonard Anghel
  • Send Email »
  • More Articles »

Introduction

Hazelcast is the Leading Open Source In-Memory Data Grid: Distributed Computing, Simplified.

The main areas where Hazelcast can do really wonders are: in-memory data grid, caching, in-memory NoSQL, messaging, application scaling, and clustering.

In this article, we will have a brief introduction into the Hazelcast world, and we start with some configuration aspects.

Hazelcast Configurations

To start, Hazelcast needs a set of configurations, such as the port number of the first node, activate/deactivate multicast support, and so forth. Besides the set of default configurations that are stored in the hazelcast-default.xml file that comes with the Hazelcast JAR, we can provide a custom set of configurations via XML or programmatically.

Hazelcast XML Configurations

Hazelcast supports declarative and programmatic configurations. Further, we will examine each of these cases via the most common usage cases.

Working with hazelcast.xml

When Hazelcast starts, it first checks the value of the hazelcast.config system property. Basically, via this system property, you specify the path where Hazelcast should look for the hazlecast.xml file (the path can be a normal one or a classpath reference with the prefix CLASSPATH). The hazelcast.xml file contains the custom configurations for Hazelcast. By default, this file should be located in the current working directory or the classpath. A simple hazelcast.xml file can look like this:

<?xml version="1.0" encoding="UTF-8"?>
<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config
      hazelcast-config-3.6.xsd"
      xmlns="http://www.hazelcast.com/schema/config"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <network>
      <port auto-increment="true"
            port-count="100">6005</port>
         <join>
            <multicast enabled="true"/>
         </join>
   </network>
</hazelcast>

To start a Hazelcast instance with the default configurations, we can simply write two lines of code, as follows:

Config cfg = new Config();
HazelcastInstance instance =
   Hazelcast.newHazelcastInstance(cfg);

Notice that the above approach will ignore a potential existing hazlecast.xml! The Config object represents all the configurations to start a HazelcastInstance, and because we pass an "unused" cfg, it will contain the default configurations for Hazelcast. Most probably, you will use the preceding approach when you want to programmatically alter the default configurations.

In some examples, you may also see the following approach:

HazelcastInstance instance = Hazelcast.newHazelcastInstance();

Notice that the above approach will start with default configurations ONLY if there is no hazlecast.xml found! You can see such an application in the code that is delivered with this article, under the name HazelcastXML. Please refer to the download link at the end of this article. This application uses the above hazelcast.xml. When you will run this application ONCE, notice that the first node is started on port 6005, instead of the default one, 5701:

Hazel1
Figure 1: The first node in the cluster started at custom port 6005

If you run this code once more, a second node starts and these two nodes will form a cluster; this is possible because Hazelcast allows more than one instance (node) to be created on the same JVM. Check out Figure 2:

Hazel2
Figure 2: Two nodes of a cluster

The source code necessary for this is embarrassingly simple:

public class StartHazelcast {
   public static void main(String[] args) {
      HazelcastInstance instance =
         Hazelcast.newHazelcastInstance();
   }
}

Working with XmlConfigBuilder

Another approach to configuring Hazelcast consists of using the XmlConfigBuilder class. Via this class, we can load the configurations from an XML file that can be referenced via a URL, file path, or input stream. For example, we can point to a location on disk (file path) as shown below:

public static void main(String[] args) {
   try {
      XmlConfigBuilder cfg = new
         XmlConfigBuilder("./hazelcast/myconfigs.xml");
      HazelcastInstance instance =
         Hazelcast.newHazelcastInstance(cfg.build());
   } catch (FileNotFoundException ex) {
      Logger.getLogger(StartHazelcast.class.getName())
         .log(Level.SEVERE, null, ex);
   }
}

The complete example is named HazelcastXmlConfigBuilder.

Working with Config

As was said earlier, the Config class can be used to provide a programmatic configuration approach. For example, we may want to programmatically provide the same configurations as we did above via hazelcast.xml. This can be accomplished as demonstrated below:

public static void main(String[] args) {

   Config cfg = new Config();

   // set some network configurations
   NetworkConfig networkConfig = new NetworkConfig();
   networkConfig.setPort(6005);
   networkConfig.setPortAutoIncrement(true);
   networkConfig.setPortCount(100);

   MulticastConfig multicastConfig = new MulticastConfig();
   multicastConfig.setEnabled(true);

   JoinConfig joinConfig = new JoinConfig();
   joinConfig.setMulticastConfig(multicastConfig);

   networkConfig.setJoin(joinConfig);
   cfg.setNetworkConfig(networkConfig);

   HazelcastInstance instance =
      Hazelcast.newHazelcastInstance(cfg);
}

The complete example is named HazelcastConfig.

Load an XML Configuration File and Add Programmatic Modifications

We can combine declarative and programmatic configurations. For example, let's suppose that we have a an XML configuration file, myconfigs.xml:

<?xml version="1.0" encoding="UTF-8"?>
<hazelcast xsi:schemaLocation="http://www.hazelcast.com
      schema/config hazelcast-config-3.6.xsd"
      xmlns="http://www.hazelcast.com/schema/config"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <network>
      <port auto-increment="true" port-count="100">6005</port>
      <!-- programmatically, we will add the join here -->
   </network>
</hazelcast>

We load this file via XmlConfigBuilder and add the join configuration programmatically. Here it is the relevant code:

public static void main(String[] args) {

   try {
      Config cfg = new XmlConfigBuilder
         ("./hazelcast/myconfigs.xml").build();

      NetworkConfig networkConfig = cfg.getNetworkConfig();

      MulticastConfig multicastConfig = new MulticastConfig();
      multicastConfig.setEnabled(true);

      JoinConfig joinConfig = new JoinConfig();
      joinConfig.setMulticastConfig(multicastConfig);

      networkConfig.setJoin(joinConfig);
      cfg.setNetworkConfig(networkConfig);

      HazelcastInstance instance =
         Hazelcast.newHazelcastInstance(cfg);
   } catch (FileNotFoundException ex) {
      Logger.getLogger(StartHazelcast.class.getName())
         .log(Level.SEVERE, null, ex);
   }
}

The complete example is named HazelcastMixt.

Config Notes

The Config instances can be shared between threads, but should not be modified after they are used to create HazelcastInstances. Hazelcast does not copy configurations to each node. So, if one wants to share a data structure, it needs to be defined in every node exactly the same.

Hazelcast Structures to Store Data

Hazelcast comes with several data structures to store data, such as IList, IMap, MultiMap, and ISet. In this section, we will talk about IMap.

The concurrent, distributed, observable, and queryable map is the Hazelcast IMap. Here it is a simple usage of it: We declare a IMap and pre-populate it with some random data. Moreover, we don't explicitly specify keys; we use the Hazecast key generator (IdGenerator), which is capable of generating random keys across nodes:

public static void main(String[] args) {

   HazelcastInstance instance =
      Hazelcast.newHazelcastInstance();

   // create and populate an IMap
   IMap products = instance.getMap("products");
   IdGenerator gen = instance.getIdGenerator("gen");

   products.put(gen.newId(), new Random().nextInt(100));
   products.put(gen.newId(), new Random().nextInt(100));

   products.entrySet().stream().forEach((entry) -> {
      System.out.printf("entry: " + entry + "\n");
   });
}

If the map products exists (for example, it was configured and initialized in XML), Hazelcast will use that ma. Otherwise, it will create it as an empty map (as above).

The data stored in this map will be available for all nodes in the cluster. For example, on a single node, you may see something like in Figure 3, left side, while on two nodes, you will see something like in Figure 3, right side:

Hazel3
Figure 3: Hazelcast distributed map

The complete example is named HazelcastIMap.

Hazelcast Messaging

When we talk about Hazelcast messaging, we are talking about the mighty IQueue and ITopic. The IQueue is a concurrent, blocking, distributed, observable queue, and a simple example looks like the following:

First, we have the producer that puts entries in the queue:

public static void main(String[] args) {

   HazelcastInstance instance = Hazelcast.newHazelcastInstance();

   String[] players = {"Rafael Nadal", "Roger Federer",
                       "David Ferer", "Andy Murray",
                       "Fernando Verdasco"};

   IQueue<String> queue = instance.getQueue("queue");
   try {
      for (int i = 0; i < players.length; i++) {
         queue.put(players[i]);
         System.out.println("Putting player " + players[i]);
         Thread.sleep(4000);
      }

      queue.put("done");
      System.out.println("Done!");
   } catch (InterruptedException ex) {
      Logger.getLogger(IQueueProducer.class.
      getName()).log(Level.SEVERE, null, ex);
   }
}

Second, we have a consumer for our queue:

public static void main(String[] args) {

   HazelcastInstance instance =
      Hazelcast.newHazelcastInstance();

   IQueue<String> queue = instance.getQueue("queue");
   try {
      while (true) {
         String player;

         player = queue.take();

         System.out.println("Take from queue the player: "
            + player);
         if (player.equals("done")) {
            queue.put("done");
            break;
         }
      }

      System.out.println("Done!");
   } catch (InterruptedException ex) {
      Logger.getLogger(IQueueConsumer.class.getName()).
      log(Level.SEVERE, null, ex);
   }
}

The complete example is named HazelcastBlockingQueue.

The ITopic is a publisher/subscriber distribution mechanism. Subscribers will process the messages in the order they are actually published. Check out a publisher implementation:

public static void main(String[] args) {

   HazelcastInstance instance = Hazelcast.newHazelcastInstance();

   String[] players = {"Rafael Nadal", "Roger Federer",
                       "David Ferer", "Andy Murray",
                       "Fernando Verdasco"};

   ITopic<String> topic = instance.getTopic("topic");
   try {
      for (int i = 0; i < players.length; i++) {
         topic.publish(players[i]);
         System.out.println("Putting player " + players[i]);
         Thread.sleep(4000);
      }
      topic.publish("done");
      System.out.println("Done!");
   } catch (InterruptedException ex) {
      Logger.getLogger(ITopicPublisher.class.getName())
      .log(Level.SEVERE, null, ex);
   }
}

And, the subscriber:

public static void main(String[] args) {

   HazelcastInstance instance =
      Hazelcast.newHazelcastInstance();

   ITopic<String> topic = instance.getTopic("topic");
   topic.addMessageListener(new MessageListenerImpl());

   System.out.println("Subscribed");
}

private static class MessageListenerImpl implements
      MessageListener<String> {
   @Override
   public void onMessage(Message<String> m) {
      System.out.println("Received player: " +
         m.getMessageObject());
   }
}

Figure 4 demonstrates an output with one publisher and three subscribers:

Hazel4
Figure 4: One publisher and three subscribers

The complete example is named HazelcastTopic.

What to Read Further

Well, if the preceding examples look impressive, you must know that this is just the beginning. Next, you should try to explore more about the amazing power of Hazelcast and read about Hazelcast locking, transactions, JCache support, interacting with a RDBMS, and so on.

Download the Code

You can download all code samples for this article here.


Tags: XML, JAR, messaging, consumer, node, subscribers, hazelcast, Queue




Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date
Rocket Fuel