Akka Cluster basic clarifications about creating actors dynamically

310 Views Asked by At

In Akka remote we crate actor by defining in actor system configuration,or programmatically saying the other actor system location.
We send messages to the actor by the references we created or we can get a actor reference by getting actorselection.

But with Akka Cluster there is no clear point for me.
How we create actors out side of cluster dynamically?
How we send messages to that actors and how that actors created across cluster (distributed way)?
Or we have to send a particular actor in cluster and that will create actors or distribute message?

1

There are 1 best solutions below

0
On BEST ANSWER

Edited answer for responding to missed points.

A General Approach

This approach is suggested for a more general usecase.

Q1: How we create actors out side of cluster dynamically?

You cannot directly create actors in other members in the cluster or outside. But However, you can implement member creation in your application logic. Then, you can subscribe for cluster membership events in a supervisor level actor. See the documentation

Assume you subscribed to MemberUp events to detect new members in cluster, and MemberRemoved events to detect offline members. So you can maintain a routing table in each actor system to communicate with other actor systems in your cluster.

 cluster.subscribe(
                 getSelf(), ClusterEvent.initialStateAsEvents(),
                 ClusterEvent.MemberUp.class,
                 ClusterEvent.MemberRemoved.class );

Then you can receive get the member address from the membership events and implement other application logics. Checkout the following snippet for getting an idea.

        @Override
        public Receive createReceive() {
            return receiveBuilder()
                    .match(ClusterEvent.MemberUp.class, memberUp -> {
                        // update routing table                        
                        // implement your logic when member is up
                    }).match(ClusterEvent.MemberRemoved.class, memberUp -> {
                        // update routing table                        
                        // implement your logic when member is up
                    }).build();
        }

Q2: How we send messages to that actors and how that actors created across cluster

Since you have the actor addresses in your routing table, you can use Akka remoting to send messages to them.

For more distributed methods to create and communicate with actors dynamically in a cluster, you can use Cluster Singleton and/or Cluster Sharding.

Cluster Singleton

If your cluster needs only one specific type of actor in the cluster, you can create a Cluster Singleton This actor will be always available/running somewhere in the cluster irrespective of how many members are in cluster.

Q1: How we create actors out side of cluster dynamically?

You can create a singleton actor, and it will be dynamically available in your cluster. If the cluster member running your singleton actor is stopped, cluster will spawn another singleton actor somewhere in the cluster.

on every node in the cluster, or every node with a given role, use the ClusterSingleton extension to spawn the singleton.

// From the docs    
ClusterSingleton singleton = ClusterSingleton.get(system);
    // Start if needed and provide a proxy to a named singleton
    ActorRef<Counter.Command> proxy =
        singleton.init(SingletonActor.of(Counter.create(), "GlobalCounter"));

Q2: How we send messages to that actors and how that actors created across cluster

Use the proxy reference to send messages to the singleton.

proxy.tell(Counter.Increment.INSTANCE);

Cluster Sharding

From the docs,

Cluster sharding is useful when you need to distribute actors across several nodes in the cluster and want to be able to interact with them using their logical identifier, but without having to care about their physical location in the cluster, which might also change over time.

Q1: How we create actors out side of cluster dynamically?

Cluster sharding init should be called on every node for each entity type. Which nodes entity actors are created on can be controlled with roles. init will create a ShardRegion or a proxy depending on whether the node’s role matches the entity’s role.

EntityTypeKey<Counter.Command> typeKey = EntityTypeKey.create(Counter.Command.class, "Counter");

ActorRef<ShardingEnvelope<Counter.Command>> shardRegion =
    sharding.init(Entity.of(typeKey, ctx -> Counter.create(ctx.getEntityId())));

Q2: How we send messages to that actors and how that actors created across cluster

Messages to a specific entity are then sent via an EntityRef. The entityId and the name of the Entity’s key can be retrieved from the EntityRef. It is also possible to wrap methods in a ShardingEnvelope or define extractor functions and send messages directly to the shard region.

EntityRef<Counter.Command> counterOne = sharding.entityRefFor(typeKey, "counter-1");
counterOne.tell(Counter.Increment.INSTANCE);

shardRegion.tell(new ShardingEnvelope<>("counter-1", Counter.Increment.INSTANCE));

You may define the number of shards in the actor system configuration. Note that this value should be same for all actor systems in the cluster, and changing this value will require cluster wide restart.

akka.cluster.sharding {
  # Number of shards used by the default HashCodeMessageExtractor
  # when no other message extractor is defined. This value must be
  # the same for all nodes in the cluster and that is verified by
  # configuration check when joining. Changing the value requires
  # stopping all nodes in the cluster.
  number-of-shards = 1000
}

Q2: How we send messages to that actors and how that actors created across cluster

Alternatively, You can use Cluster Client to send messages to actors in a cluster, from outside the cluster.

I strongly suggest you to read the documentation since these are some deep topics in Akka Clustering.