Typesafe Activator

Akka Clustered PubSub with Scala!

Akka Clustered PubSub with Scala!

typesafehub
Source
July 2, 2014
basics akka starter scala

Illustrates publish-subscribe in a cluster of Akka nodes.

How to get "Akka Clustered PubSub with Scala!" on your computer

There are several ways to get this template.

Option 1: Choose akka-clustering in the Typesafe Activator UI.

Already have Typesafe Activator (get it here)? Launch the UI then search for akka-clustering in the list of templates.

Option 2: Download the akka-clustering project as a zip archive

If you haven't installed Activator, you can get the code by downloading the template bundle for akka-clustering.

  1. Download the Template Bundle for "Akka Clustered PubSub with Scala!"
  2. Extract the downloaded zip file to your system
  3. The bundle includes a small bootstrap script that can start Activator. To start Typesafe Activator's UI:

    In your File Explorer, navigate into the directory that the template was extracted to, right-click on the file named "activator.bat", then select "Open", and if prompted with a warning, click to continue:

    Or from a command line:

     C:\Users\typesafe\akka-clustering> activator ui 
    This will start Typesafe Activator and open this template in your browser.

Option 3: Create a akka-clustering project from the command line

If you have Typesafe Activator, use its command line mode to create a new project from this template. Type activator new PROJECTNAME akka-clustering on the command line.

Option 4: View the template source

The creator of this template maintains it at https://github.com/typesafehub/activator-akka-clustering#master.

Option 5: Preview the tutorial below

We've included the text of this template's tutorial below, but it may work better if you view it inside Activator on your computer. Activator tutorials are often designed to be interactive.

Preview the tutorial

Run the Application

This tutorial will demonstrate a chat room application. Chat users communicate with publish-subscribe to other users somewhere in the cluster.

Open the Run tab. On the left-hand side we can see the console output, which is logging output from nodes joining the cluster and the fictive chat users publishing random Scott Adams quotes to the chat room as illustrated with the >>>> markers. Other chat users in the room receive those messages as illustrated by the << markers.

Explore the Code - Startup

Let's look at the Main.scala file.

The application starts in the main method. Normally you would run cluster nodes in separate JVMs, typically on different physical machines. Here we simulate that by starting 3 separate actor systems in the same JVM. The actor systems use remoting to communicate with each other, so the code would be the same for a real distributed application.

The configuration of the actor systems is located in application.conf. The ClusterActorRefProvider is the only mandatory configuration to enable Akka clustering.

port=0 means that the remoting of each actor system will listen on a random available port. This is important when running several actor systems on the same host, since they cannot bind to the same port.

A few chat user actors are created in each actor system.

To form a cluster the nodes must join some other node in the cluster. The first node joins itself, the other 2 nodes join the first node.

Note that there is a delay between the startup of each actor system and that explains why the first messages are not delivered to Miguel and Tyler. An Akka cluster is elastic in its nature. Nodes may join and exit over time and that is discovered by other members of the cluster. Go through the log output in the Run tab again and make sure you see that the 3 nodes become members. Look for "Member is Up". If the log has grown too much you can restart the app.

Explore the Code - Chat Client Actor

Let's look at the RandomUser.scala file.

The RandomUser simulates a chat user. It schedules a Tick message to itself with a random interval. For each tick it picks a Scott Adams quote and publishes it to the chat room via the ChatClient, which is a child actor to RandomUser.

Open the ChatClient.scala file.

The ChatClient receives Publish messages from the RandomUser and sends those to the chat room topic via the DistributedPubSubMediator. It subscribes to the same topic to receive messages from itself and other chat users. Note that the chat users are completely decoupled from each other and only know about the publish-subscribe topic that is managed by the mediator. The sender of the message is still the original sender, which makes it possible to reply directly to that actor.

DistributedPubSubMediator facilitates this publish-subscribe communication pattern. It is built on top of Akka cluster and packaged in the Akka Contrib Module. The mediator actor keeps track of registered subscribers, but there is no central broker. One mediator actor is running on each node, and it replicates the actor references to peer mediators at other cluster members. This distributed registry is eventually consistent, i.e. changes are not immediately visible at other nodes, but typically they will be fully replicated to all other nodes after a few seconds.

Cluster Membership

Discovery of new nodes in the cluster, as well as detection of unreachable and removed nodes, is important to be able to build cluster aware features, such as the DistributedPubSubMediator. The API for cluster membership is event based.

The MemberListener.scala illustrates how to subscribe to such cluster membership events and keep track of addresses of the current members in the cluster.

A snapshot of the full state, CurrentClusterState, is sent to the subscriber as the first event. Here we are only interested in members with status Up and grab the Address of those members. When there are changes to the members of the cluster other events are sent to the subscriber. MemberUp is received when a new member is added to the cluster. MemberRemoved is received when a member is removed from the cluster due to graceful exit or failure.

Using the Address information you can send messages to actors at those nodes.

			
  import akka.actor.RootActorPath
  val service = context.actorSelection(RootActorPath(member.address) /
    "user" / "backendService")
  service ! Request("..")

		

Next Steps

With the presented publish-subscribe feature and brief understanding of cluster membership you can develop applications that scale out. Of course there are more things in Akka cluster to take advantage of, such as Cluster Aware Routers and the Cluster Singleton.

In depth documentation can be found in the Cluster Specification and in the Cluster Usage documentation.

comments powered by Disqus