21 April 2014
by Jem Mawson

Cluster Singleton in Akka

In a highly-available application, it is occasionally necessary to have some processing performed in isolation within a cluster, whilst still allowing for processing to continue should the designated worker node fail. This is trivial with Akka clustering support for the Cluster Singleton pattern.

For a motivating example, consider a system that processes large files from a clustered file system. It is important that any given file is processed exactly once. Atomic file management is difficult due to the lag time of the file system clustering. Any system that relies solely on file renaming or locking to designate which node is processing the file will most likely run into contention, leading to unreliable results. An alternative approach is to ensure only one node is actively seeking work. In this scenario no contention can possibly occur.

Akka has made things very easy for developers in the Java ecosystem who need this kind of support. Built upon its remote actor support, Akka enables clusters to be created - the formation of disparate actor systems into one logical actor system. Creation of a cluster is straight-forward, requiring only the configuration of a cluster-specific provider and one or more seed nodes. Akka handles the complexity of node membership for us, using a gossip protocol. In a short time it is easy to demonstrate a simple system that is aware of the joining and leaving of nodes and provides horizontal scalability.

Within a cluster there is implicitly always at most one node designated as leader. It is possible to define an actor that is active only on the leader node. This is the Cluster Singleton pattern. It is enabled simply by defining actor properties using the akka.contrib.pattern.ClusterSingletonManager.

    val clusterSingletonProperties = ClusterSingletonManager.props(
      singletonProps = Props(classOf[YourSingletonActor]),
      singletonName = "the-singleton",
      terminationMessage = PoisonPill,
      role = None)
    system.actorOf(clusterSingletonProperties, "clusterSingleton")

The resulting actor will always be created on a node when that node becomes the leader. It will not exist more than once in a cluster. However it is possible that, through an unfortunate sequence of seed node termination and restarts that you obtain two clusters! (In which case you will certainly have two cluster singletons running). The configuration property akka.cluster.role.$role.min-nr-of-members can be used to ensure that the cluster is not effected until a quorum is established.

I have derived a simplified example of cluster singleton usage from the provided typesafe activator examples. Clone it from GitHub and follow the instructions in the readme to observe the cluster singleton in action. https://github.com/Synesso/scratch-akka-cluster-singleton.

akka scala

This post is written by Jeremy Mawson. Jem is an agile software engineer and technical lead. He is a specialist in software development with wide interests and currently focusing on Scala and the Typesafe stack. He lives in Australia with his wife Chen. Together they remotely assist innovative and socially positive companies to achieve their technology goals.
More about Loft in Space.