Technical Overview of Akka.Cluster.Sharding in Akka.NET

How Akka.Cluster.Sharding Allocates Shards, Rebalances, and More

In our previous post about using Akka.Cluster.Sharding we looked at the module from an end-user’s perspective. Today we’ll provide a little more insights into how this plugin works internally.

Cluster sharding depends on several types of actors:

  • Coordinator - one per entity type for an entire cluster.
  • Shard region - one per entity type per each cluster node, where sharding should be enabled.
  • Shard - there can be many on each shard region, and they can move between shard regions located on different nodes.
  • Entity - actors defined by the end-user. There can be many on each shard, but they are always bound to a specific shard.

All of them can be visualized using diagram below:

Conceptual image of cluster shard internal actors located across the cluster nodes

If you look at actor paths of the entities you’ve created you’ll see that they reflect the structure of that hierarchy. They follow the pattern /user/sharding/<typeName>/<shardId>/<entityId>. Given that, it’s easy to infer that /user/sharding/<typeName> is path to a shard region while subsequent path segments are responsible for shard actor and entity actor.

Introduction to Akka.Cluster.Sharding in Akka.NET

Distributing State Evenly and Automatically with Self-Managing Actors

In this post, we’ll discuss one of the Akka.NET plugins, Akka.Cluster.Sharding and how it gives us easier, higher level abstractions to work with actors (in this case also referred to as entities). Cluster.Sharding gives us:

  • By using a logical keys (in form of ShardId/EntityId pairs) it’s able to route our messages to the right entity without need to explicitly determine on which node in the cluster it lives.
  • It automatically manages the process of actor creation, so you don’t have to do it explicitly. When a message is addressed to an entity that didn’t exist, an actor for that entity will be created automatically.
  • It’s able to rebalance actors across cluster as it grows or shrinks, to ensure its optimal usage.

Given all of those traits, let’s see how to utilize cluster sharding in a standard Akka.NET application.

Designing Akka.NET Applications from Scratch Part 2: Hierarchies and SOLID Principles

Decomposing Complex Domains into Understandable Actor Hierarchies

In the first post in this series, we discussed how the correct place to begin thinking about an Akka.NET application is actually with your data flows and organizing those into reusable “protocols”. Once that’s done, then it’s time to start slotting actors into some of the interaction points inside the protocol.

But what happens when certain types of interactions are complicated and can’t easily be expressed inside one actor? Or what happens if you need to accumulate state for each individual instance of the protocol?

Think of a protocol like a class. A protocol is a logical unit of encapsulation that expresses some defined behaviors, inputs, and outputs. And just like classes, protocols can be composed - one class can have members that are of another type of class. Small protocols can be combined with other protocols to build large, system-defining behaviors. This is generally how stream processing architectures are actually designed at scale.

An instance of a class is called an object in OOP. In protocol-driven design a “protocol instance” is an instance of a protocol, just like how a class is instance of an object.

Actor Hierarchies and Protocols

A protocol consists of multiple different interactions and can have totally different flows depending on the state of each particular protocol instance. Your Akka.NET actor system can theoretically run hundreds of thousands of concurrent protocol instances at the same time. It’s the goal of a well-designed actor hierarchy to make it performant and easy to manage.

So the first rule of thumb when it comes to designing an actor hierarchy is once again: separate your concerns.

Brute actor hierarchy

It’s pointless to attempt to design an entire end-to-end actor system before you’ve written any code, because you don’t know what you don’t know yet....