Lightbend Activator

Akka Distributed Data Samples with Scala

Activator will be EOL-ed on May 24, 2017.

We’re making it easier and simpler for developers to get started with Lightbend technologies. This unfortunately means that future releases of Play, Akka and Scala will no longer include Activator support, and Lightbend’s Activator server will be decommissioned by the end of 2017. Instead of supporting Activator to create and set up development projects, we'll be supporting standard Giter8 templates for sbt users and Maven archetypes for Maven users. So going forward,

To create new Lightbend projects

Instead of using the Activator command, make sure you have sbt 0.13.13 (or higher), and use the “sbt new” command, providing the name of the template. For example, “$ sbt new akka/hello-akka.g8”. You can find a list of templates here.

Also, as a convenience, the Lightbend Project Starter allows you to quickly create a variety of example projects that you just unzip and run.

To create new templates

If you want to create new templates, you can now do that in Giter8.

To migrate templates from Activator to Giter8

If you created Activator templates in the past, please consider migrating them to Giter8 with this simple process.

Akka Distributed Data Samples with Scala

Akka Team
Source
September 30, 2016
akka cluster scala sample distributed-data

Akka Distributed Data Samples with Scala

How to get "Akka Distributed Data Samples with Scala" on your computer

There are several ways to get this template.

Option 1: Choose akka-sample-distributed-data-scala in the Lightbend Activator UI.

Already have Lightbend Activator (get it here)? Launch the UI then search for akka-sample-distributed-data-scala in the list of templates.

Option 2: Download the akka-sample-distributed-data-scala project as a zip archive

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

  1. Download the Template Bundle for "Akka Distributed Data Samples 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 Lightbend 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-sample-distributed-data-scala> activator ui 
    This will start Lightbend Activator and open this template in your browser.

Option 3: Create a akka-sample-distributed-data-scala project from the command line

If you have Lightbend Activator, use its command line mode to create a new project from this template. Type activator new PROJECTNAME akka-sample-distributed-data-scala on the command line.

Option 4: View the template source

The creator of this template maintains it at https://github.com/akka/akka.

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

This tutorial contains 5 samples illustrating how to use Akka Distributed Data.

  • Low Latency Voting Service
  • Highly Available Shopping Cart
  • Distributed Service Registry
  • Replicated Cache
  • Replicated Metrics

Akka Distributed Data is useful when you need to share data between nodes in an Akka Cluster. The data is accessed with an actor providing a key-value store like API. The keys are unique identifiers with type information of the data values. The values are Conflict Free Replicated Data Types (CRDTs).

All data entries are spread to all nodes, or nodes with a certain role, in the cluster via direct replication and gossip based dissemination. You have fine grained control of the consistency level for reads and writes.

The nature CRDTs makes it possible to perform updates from any node without coordination. Concurrent updates from different nodes will automatically be resolved by the monotonic merge function, which all data types must provide. The state changes always converge. Several useful data types for counters, sets, maps and registers are provided and you can also implement your own custom data types.

It is eventually consistent and geared toward providing high read and write availability (partition tolerance), with low latency. Note that in an eventually consistent system a read may return an out-of-date value.

Note that there are some Limitations that you should be aware of. For example, Akka Distributed Data is not intended for Big Data.

Low Latency Voting Service

Distributed Data is great for low latency services, since you can update or get data from the local replica without immediate communication with other nodes.

Open VotingService.scala.

VotingService is an actor for low latency counting of votes on several cluster nodes and aggregation of the grand total number of votes. The actor is started on each cluster node. First it expects an Open message on one or several nodes. After that the counting can begin. The open signal is immediately replicated to all nodes with a boolean Flag. Note WriteAll.


replicator ! Update(OpenedKey, Flag(), WriteAll(5.seconds))(_.switchOn)

The actor is subscribing to changes of the OpenedKey and other instances of this actor, also on other nodes, will be notified when the flag is changed.


replicator ! Subscribe(OpenedKey, self)

case c @ Changed(OpenedKey) if c.get(OpenedKey).enabled

The counters are kept in a PNCounterMap and updated with:


val update = Update(CountersKey, PNCounterMap(), WriteLocal, request = Some(v)) {
  _.increment(participant, 1)
}
replicator ! update

Incrementing the counter is very fast, since it only involves communication with the local Replicator actor. Note WriteLocal. Those updates are also spread to other nodes, but that is performed in the background.

The total number of votes is retrieved with:


case GetVotes ⇒
  replicator ! Get(CountersKey, ReadAll(3.seconds), Some(GetVotesReq(sender())))

case g @ GetSuccess(CountersKey, Some(GetVotesReq(replyTo))) ⇒
  val data = g.get(CountersKey)
  replyTo ! Votes(data.entries, open)

The multi-node test for the VotingService can be found in VotingServiceSpec.scala.

Read the Using the Replicator documentation for more details of how to use Get, Update, and Subscribe.

Highly Available Shopping Cart

Distributed Data is great for highly available services, since it is possible to perform updates to the local node (or currently available nodes) during a network partition.

Open ShoppingCart.scala.

ShoppingCart is an actor that holds the selected items to buy for a user. The actor instance for a specific user may be started where ever needed in the cluster, i.e. several instances may be started on different nodes and used at the same time.

Each product in the cart is represented by a LineItem and all items in the cart is collected in a LWWMap.

The actor handles the commands GetCart, AddItem and RemoveItem. To get the latest updates in case the same shopping cart is used from several nodes it is using consistency level of ReadMajority and WriteMajority, but that is only done to reduce the risk of seeing old data. If such reads and writes cannot be completed due to a network partition it falls back to reading/writing from the local replica (see GetFailure). Local reads and writes will always be successful and when the network partition heals the updated shopping carts will be be disseminated by the gossip protocol and the LWWMap CRDTs are merged, i.e. it is a highly available shopping cart.

The multi-node test for the ShoppingCart can be found in ShoppingCartSpec.scala.

Read the Consistency section in the documentation to understand the consistency considerations.

Distributed Service Registry

Have you ever had the need to lookup actors by name in an Akka Cluster? This example illustrates how you could implement such a registry. It is probably not feature complete, but should be a good starting point.

Open ServiceRegistry.scala.

ServiceRegistry is an actor that is started on each node in the cluster. It supports two basic commands:

  • Register to bind an ActorRef to a name, several actors can be bound to the same name
  • Lookup get currently bound services of a given name

For each named service it is using an ORSet. Here we are using top level ORSet entries. An alternative would have been to use a ORMultiMap holding all services. That would have a disadvantage if we have many services. When a data entry is changed the full state of that entry is replicated to other nodes, i.e. when you update a map the whole map is replicated.

The ServiceRegistry is subscribing to changes of a GSet where we add the names of all services. It is also subscribing to all such service keys to get notifications when actors are added or removed to a named service.

The multi-node test for the ServiceRegistry can be found in ServiceRegistrySpec.scala.

Replicated Cache

This example illustrates a simple key-value cache.

Open ReplicatedCache.scala.

ReplicatedCache is an actor that is started on each node in the cluster. It supports three commands: PutInCache, GetFromCache and Evict.

It is splitting up the key space in 100 top level keys, each with a LWWMap. When a data entry is changed the full state of that entry is replicated to other nodes, i.e. when you update a map the whole map is replicated. Therefore, instead of using one ORMap with 1000 elements it is more efficient to split that up in 100 top level ORMap entries with 10 elements each. Top level entries are replicated individually, which has the trade-off that different entries may not be replicated at the same time and you may see inconsistencies between related entries. Separate top level entries cannot be updated atomically together.

The multi-node test for the ReplicatedCache can be found in ReplicatedCacheSpec.scala.

Replicated Metrics

This example illustrates to spread metrics data to all nodes in an Akka cluster.

Open ReplicatedMetrics.scala.

ReplicatedMetrics is an actor that is started on each node in the cluster. Periodically it collects some metrics, in this case used and max heap size. Each metrics type is stored in a LWWMap where the key in the map is the address of the node. The values are disseminated to other nodes with the gossip protocol.

The multi-node test for the ReplicatedCache can be found in ReplicatedMetricsSpec.scala.

×

Welcome to the Lightbend Enterprise Suite


You are excited about Reactive applications. And you want to build, manage and monitor them easily and reliably in your environment.
We get it. So we built Lightbend Enterprise Suite to help you do that, and more, with a range of powerful Application Management, Intelligent Monitoring, Enterprise Integration and Advanced Tooling features.