Deploy Akka Cluster Sharding for Single-Instance Entity Actors
Configure Akka Cluster Sharding to ensure exactly one actor instance per entity ID across a JVM cluster, set extraction functions, start ShardRegion, and verify distribution and rebalancing.
21 Sept 2025, 10:25 UTC

Desired outcome
\nYou want a set of long‑lived entity actors that are distributed over cluster nodes, created lazily on first message, automatically rebalanced when nodes join or leave, and passivated when idle to free memory. All messages with the same entity ID must be processed by a single actor instance, even if sent from different nodes.
\nPrerequisites
\nA stable Akka cluster with a membership provider and split‑brain resolver (e.g., Akka Management). All nodes must use the same serialization configuration for entity messages.
\nDefine the entity protocol and a restartable actor behavior. Choose an entity ID format and a deterministic shard ID function that distributes IDs uniformly.
\nOperating permissions: ability to start JVM processes on each node with distinct ports and config files; no special OS privileges beyond network access to cluster ports.
\nFocused procedure
\n1. Define entity and extraction functions
\nThe ShardRegion needs two functions: entityIdExtractor (maps a message to an entity ID) and extractShardId (maps an entity ID to a shard number). Uniform shard allocation avoids hot shards.
// Example extraction logic\nval numberOfShards = 100\nval extractShardId: String => Int = { entityId =>\n Math.abs(entityId.hashCode()) % numberOfShards\n}\nval entityIdExtractor: Any => Option[String] = {\n case msg: EntityCommand => Some(msg.entityId)\n case _ => None\n}\n2. Implement the entity actor
\nThe entity actor must be serializable and able to recover after passivation or restart.
\nclass UserActor(entityId: String) extends Actor {\n var state: UserState = UserState()\n def receive: Receive = {\n case cmd: UpdateUser => state = state.update(cmd); sender() ! state\n case GetState => sender() ! state\n }\n}\n3. Start the ShardRegion
\nInitialize ClusterSharding and register the entity type.
\nval sharding = ClusterSharding(system)\nval userRegion = sharding.init(\n typeName = \"User\",\n entityProps = entityId => Props(new UserActor(entityId)),\n settings = ClusterShardingSettings(system)\n .withPassivateIdleAfter(Duration.ofMinutes(30))\n .withRememberEntities(false)\n)\n4. Send messages through the region
\nClients use the userRegion ActorRef; the ShardRegion routes each message to the correct entity actor.
userRegion ! UpdateUser(entityId = \"user-42\", data = \"new\")\nExpected checks
\n- \n
- Shard allocation: Look at
akka.cluster.sharding.ShardCoordinatorlogs for lines likeShard [X] allocated to node [akka.tcp://sys@host:port]and verify shards are spread across nodes. \n - Message routing: From two different nodes, send messages with the same entity ID. Check actor start logs; only one
UserActorstart log should appear for that ID. \n - Failover test: Stop one JVM node. Observe the ShardCoordinator rebalancing the shards from the stopped node to the remaining nodes (log entries about shard handoff). \n
Recovery and rollback
\nIf you need to disable sharding:
\n- \n
- Stop sending messages to the
userRegion. \n - Issue a graceful leave of the node from the cluster (
cluster.leave()) or terminate the JVM. \n - The ShardCoordinator will reassign shards; after the node is down, you can safely remove the ShardRegion initialization code from the system. \n
Limitations and mitigation
\n- \n
- Hot shards: Non‑uniform extractShardId causes some shards to receive disproportionate traffic, creating CPU/memory bottlenecks. Mitigate by using a hash‑based function and increasing the number of shards. \n
- Passivation churn: A short
passivateIdleAftertimeout leads to frequent stop/start cycles. Increase the duration if you see high restart rates in logs. \n - Split‑brain risk: Unstable cluster membership can cause duplicate entity instances. Ensure a reliable membership provider (Akka Management with Kubernetes or Consul) and a split‑brain resolver are active before enabling sharding. \n
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.