Clustering with Red5

July 28th, 2011 by Paul Gregoire

Once your service out grows its original space, you will most likely look at adding clustering capabilities. While clustering an application may seem daunting, it can be done in a fairly simple manner at first. Whilst at Infrared5, I have created several clustered applications using the methods which will be supplied below and now may be added to your skillset.

For this example you will need the following software (IDE’s not listed):

Herein we will go over clustering a simple chat application; both the client and server code in this example consist of only two to three source files respectively. Code blocks may not contain all of the code or comments to keep the sections short and focused.

Server-side (Java)

The first piece of code we need is the Red5 application adapter, it is used by the server to control the lifecycle of your application. In many cases, the base classes may be configured via Spring so that you don’t even need to write your own for simple applications; as an example, the SOSample demo that comes with the server doesn’t have any code for an application adapter. For this application we will override two lifecycle methods to handle the starting and stopping of the application. When the application starts, we need to start our cluster client class and join the cluster. On stop we disconnect from the cluster and perform any clean up necessary.

private ChatRegistry chatRegistry;
@Override
public boolean appStart(IScope scope) {
try {
chatRegistry = new ChatRegistry(scope);
chatRegistry.start();
} catch (Exception e) {
log.error("Exception during appStart", e);
}
return super.appStart(scope);
}
@Override
public void appStop(IScope scope) {
super.appStop(scope);
if (chatRegistry != null) {
chatRegistry.stop();
}
}

We must also add any methods which will be called by the client, which in this case would be one that accepts a sender name and some text.

public void sendChat(String sender, String text) {
ChatMessage chat = new ChatMessage();
chat.setSender(sender);
chat.setText(text);
chatRegistry.send(chat);
}

Pretty easy looking isn’t it? Being a standard Java method, it could accept these values from anywhere that has access to the method such as a servlet. Next up, on the server-side is the code to send and receive messages on the cluster. This “ChatRegistry” extends the ReceiverAdapter provided by JGroups and is implemented in the most minimal way I could think of.

public class ChatRegistry extends ReceiverAdapter {
    private JChannel channel;
    private IScope scope;
    public ChatRegistry(IScope scope) {
        this.scope = scope;
    }
// creates a channel to the cluster/group and starts the client.
public void start() throws Exception {
channel = new JChannel("./udp.xml");
channel.setReceiver(this);
channel.connect("ChatRegistry");
channel.getState(null, 10000L);
}
// closes the channel, disconnecting from the group.
public void stop() {
channel.close();
}
// sends the messages to the cluster.
public void send(ChatMessage chat) {
// serialize and send the messsage to the cluster
Message msg = new Message(null, null, Util.objectToByteBuffer(chat));
channel.send(msg);
}
// receives messages from the cluster.
public void receive(Message msg) {
// deserialize the messsage from the cluster
ChatMessage chat = (ChatMessage) Util.objectFromByteBuffer(msg.getBuffer());
// call the "receive" method on every connected client and pass
// the chat message to each one.
ServiceUtils.invokeOnAllConnections(scope, "receive", new Object[]{chat});
}
}

You may have noticed we’ll be using UDP for this example, I have found that this is the easiest way to setup JGroups and keep all the nodes communicating on a local network.

Last but not least for the server application we have our model class to hold a creation time, sender name, and the chat text itself.

public class ChatMessage implements Serializable {
private long timestamp = System.currentTimeMillis();
private String sender;
private String text;
public long getTimestamp() {
return timestamp;
}
public String getSender() {
  return sender;
}
public String getText() {
  return text;
}
}

The Actionscript twin for this model will be shown in the next section.

Client-side (ActionScript)

I used FlashBuilder to whip-up a quick chat client, so don’t bash my code too hard. For the example clients I created a Flex Project with MXML and one AS3 class file. In the MXML script block besides the connection handling, we need a method for sending and another to receive.

public function send() : void {
nc.call("sendChat", null, senderName.text, chatText.text);
}
public function receive(chat : ChatMessage) : void {
messages.appendText(chat.sender + ':' + chat.text + '\n');
}

Be aware that the NetConnection.call in the send function must match the signature on the server’s application adapter.
The final class needed on the client is our model, which in Actionscript is a lot less “wordy” than in Java.

package com.infrared5.blog.chatr {
[RemoteClass(alias="com.infrared5.blog.chatr.ChatMessage")]
public class ChatMessage {
public var timestamp:uint;
public var sender:String;
public var text:String;
public function ChatMessage() {}
}
}

I have not included the configuration files and some other things in this post to prevent confusion, but rest assured they are in the source archives at the end.

Running

The quickest way to get up-and-running is to grab the server zip and deploy it to two servers or vmware virtual machines. Everything you need to run the client and server is in the zip.  After Red5 has started up, look at your console and you should see a line indicating that your application is in the cluster.

GMS: address=MAGNUS-40196, cluster=ChatRegistry, physical address=2002:48c1:e10c:0:f83f:d256:6e23:8bdb:54305

Please note that If you are using OSX you may need to add “-Djava.net.preferIPv4Stack=true” to your start-up script due to a bug in JGroups IPv6 handling.

Open browsers on each instance and navigate to http://localhost:5080/chatr/chatr.html

Once loaded, enter a name and click connect. After you have two servers running and clients connected to them, your output should look similar to this when chatting.

So now you know how easy this can be, go forth and create some cool stuff!!

Downloads

Full application with Red5 server (ready-to-run): http://bit.ly/pIoVBi

Client source: http://dl.dropbox.com/u/7316897/red5/chatrclient-src.zip

Server source: http://dl.dropbox.com/u/7316897/red5/chatr-src.zip

, , , , ,

One Response to “Clustering with Red5”

  1. Quora Says:

    How do you set up a Red5 cluster without Terracotta?…

    The original clustering stuff that a terracotta engineer helped Steven Gong with only clustered shared objects. Steven later created a custom edge/origin solution which is kind of stale at this point. Since the server is written in Java, the sky is the…

Leave a Reply