Distributed software with JGroups

2009-03-11 09:59:48 +0100

JGroups

A distributed application, where nodes of the application communicate with each other over a LAN using UDP. Each nodes discovers other nodes automatically, when a node crashes or shuts down, all nodes give notice automatically. And this is all possible without any application server, complicated configuration or what-ever-else with JGroups!

There are quite some tutorials, so I just list the basic steps to get started, most notably the maven dependencies.

Download JGroups

First download JGroups. You can get the latest version from the website JGroups. Alternatively, you can use Maven. First set up a maven-project, which is beyond the scope of this tutorial.

Add the JBoss repository, by adding the following entry to the repositories section of the maven project file (pom.xml):

<repository>

<id>maven.jboss.org</id>

<name>JBoss Maven Repository</name>

<url>http://repository.jboss.com/maven2</url>

</repository>

After that add the following dependencies to the Maven for the jgroups artifact (I use the current latest versions):

<dependency>

<groupId>jgroups</groupId>

<artifactId>jgroups</artifactId>

<version>2.7.0.GA</version>
</dependency>
<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.15</version>

</dependency>

Setting up a channel

To start using JGroups, no configuration or application server is necessary. In this posting very briefly a class will be that uses JGroups to transmit messages over nodes:

First import the necessary classes:

import org.jgroups.*;

Now set up a channel:

JChannel ch = new JChannel();

The code below you can put in a constructor of your class, so the JChannel is initalized only once. That's all there is! When you run the application multiple times inside the network (or on your own machine, for testing), JGroups will automatically detect other nodes.

Now you can add a receiver to channel, to start receiving messages and being updated of new nodes.

This is possible by implementing the Receiver interface, as demonstrated below:

public class JGroupStart implements Receiver {

	private final static String CLUSTERNAME = "JGroups tutorial cluster";

	public JGroupStart() throws Exception {

		JChannel ch = new JChannel();
		ch.setReceiver(this);

		ch.connect(CLUSTERNAME);

        System.out.println("JGroups cluster is gestart");

        Thread.sleep(10000);

        Message m = new Message();
		m.setObject(new String("Hello world from node "+ch.getLocalAddressAsString()));
        ch.send(m);
	}

	public byte[] getState() {
        return null;
	}

	public void receive(Message message) {
		System.out.println("Messsage received: " + message.getObject());
	}

	public void setState(byte[] state) {

	}

	public void block() {
	}

	public void suspect(Address address) {
	}

	public void viewAccepted(View view) {
		System.out.println("A node has appeared or disappeared, got a new view: " + view);
		for (Address a : view.getMembers()) {
			System.out.println("Member address " + a);
		}
	}

	public static void main(String [] args) throws Exception {
		JGroupStart app=new JGroupStart();
	}
}

The class contains a main method so we can start it. After starting, a JGroups server - a node - in our network:

-------------------------------------------------------
GMS: address is 172.168.11.109:1999
-------------------------------------------------------
A node has appeared or disappeared, got a new view: [172.168.11.109:1999|0] [172.168.11.109:1999]
Member address 172.168.11.109:1999
JGroups cluster is gestart

To send a message over a channel, you can use the following code:

Message m = new Message();
		m.setObject("Hello world");
ch.send(m);

The setObject method accepts any Serializable class, in this case I just sent a simple String. All other nodes will receive this message:

Messsage received: Hello world

Allthough simple as that seems, the concept is powerful. As said, nodes discover eachother automatically. When a node crashes or disappears, other nodes are notified automatically. Naturally there are much more advanced examples then what I listed above. On the JGroups site there's a article how to set up A simple clustered task distribution system.
Furthermore, JBoss 5.0GA contains a Cache: JBoss Cache. The distributed cache is built on top of JGroups. Using the JBoss Cache, JBoss can run distributed on multiple servers - this means if one server crashes or goes down for maintaince, another server takes over. Users or visitors of your site won't even notice - except that the whole site might be a bit slower.
Of course the cache can be used outsite JBoss too. JBoss cache can be used standalone, allowing any Java application - standalone or not - to take advantage of this nice powerful open source technology.


Read more

Lessons learnt using JBoss 5 clustering

2009-03-04 22:55:56 +0100

Last week I spent some time getting clustering to work using JBoss 5.0.0 GA. I made a few mistakes and I thought I share them - even though they were rather obvious:

  1. In JBoss you have have a few standard configurations - limited, default, all . I tried to get clustering to work on the default configuration. I installed the pojocache, but then I had I had some problems getting @Replicated annotation to work (see also the posting below). After some Google'ing jboss errors something like AOP seemed have to be enabled.The Pojocache I got working, by downloading and adding the libraries myself. Then I found these libraries were already included in the all configuration.
    Still, the @Replicateble tag didn't work. Just recently someone replied at my (slightly too frustrated) post at JBoss forum.
    The following options still need to be added to the run.sh or run.bat in the bin directory:

    set JAVA_OPTS=-Dsun.rmi.dgc.server.gcInterval=3600000 -Dsun.lang.ClassLoader.allowArraySyntax=true -Djboss.platform.mbeanserver  -javaagent:%JBOSS_HOME%/server/all/deployers/jboss-aop-jboss5.deployer/pluggable-instrumentor.jar %JAVA_OPTS%

    I haven't tried the above option yet - I used the Serializable interface, although that's a whole lot less powerful of course.
    Note you can use multiple java agents, so in case you use another agent like javarebel, that shouldn't be a problem.

  2. A nice thing in JBoss seemed the PojoCache. To get it to work, you'll have to create a pojocache-service.xml (see PojoCache manual) and put the file in the serveralldeploy directory of your jboss-directory. After that you can reference the PojoCache using the following code:
    MBeanServer server = MBeanServerLocator.locateJBoss();
    
    ObjectName on = null;
    
    try {
    
    on = new ObjectName("jboss.cache:service=PojoCache");
    
    } catch (MalformedObjectNameException e) {
    
    throw new ContinuAansturingException("Cache service niet correct geconfigureerd.", e);
    
    }
    
    PojoCacheJmxWrapperMBean cacheWrapper = (PojoCacheJmxWrapperMBean)
    
    MBeanServerInvocationHandler.newProxyInstance(server, on,
    
    PojoCacheJmxWrapperMBean.class, false);
    
    PojoCache cache = cacheWrapper.getPojoCache();
    
  3. Clustering Session beans -I needed a share state, for the time the application was running (no need for persistence). Using a clustered cache seemed perfect for that. I decided to use the @Clustered annotation, that works out-of-the-box, I do not have to configure the pojocache. Due to my lack of EJB-knowledge and hindsight, I thought to annotate a Stateful bean - seemed reasonable to get a shared state. As people with slightly more EJB experience known - a Stateful bean isn't meant for that! The state is only kept inside a (user) transaction. As soon as the transaction is commit'ed or rolled back, the state is lost.
    Cost my some time before I figured that out, after a few null references.
  4. Setting up the right node id and listening to right network interface - For nodes to discover each other, they have to listen to a network interface that connects them to eachother. By default JBoss will listen to localhost, so only nodes running on the same server will be detected. Naturally, you normally don't nodes to discover eachother. This is possible by adding the following command-line arguments: –b 10.0.0.53 (where you can replace 10.0.0.53 with the correct network -address)
    Furthermore, all nodes in the network have to have a unique nodeid. This can be set by the following command-line argument: -Djboss.messaging.ServerPeerID=2 where you can replace the 2 with any unique identifier.
    As listed above, you need the 'all' configuration, or a copy there of. So an example of complete command to run jboss on windows would be:

    run -c all –b 10.0.0.53 -Djboss.messaging.ServerPeerID=2

All in all, having a good book sooner would have saved me quite some time before. I now have the very recently released JBoss in Action. The book helps a lot in understanding and using JBoss because the JBoss site is seriously lacking in good documentation. Maybe that's the price you pay for using open-source: the only way Redhat can make money on JBoss is on support.


Bol.com
Jboss in Action
Jboss in Action
Javid Jamae & Peter Johnson

Read more

Archive

subscribe via RSS