Akka.net: Access remote Actors in Cluster

2019-04-29 20:06发布

问题:

In an clustered environment I have a seed node and node1 and node2.

From node1 I want to send a message to an Actor which has been created on node2. The local path to this node on node2 is akka:MyAkkaSystem/user/AnActor.

Now I want to send a message from an Actor from node1 to this specific actor by using an ActorSelection like that:

var actorSystem = ActorSystem.Create("MyTestSystem");
var c = actorSystem.ActorSelection("/user/ConsoleReceiver");
c.Tell("Hello World");

On node2 the actor has been created like that:

var actorSystem = ActorSystem.Create("MyTestSystem");
            var r = actorSystem.ActorOf(Props.Create<MessageReceiver>(), "ConsoleReceiver");
            Console.WriteLine(r.Path);
            Console.ReadLine();
            actorSystem.Terminate().Wait();

Unfortunately this does not work out since the attempt ends in dead letters.

The HOCON configuration on node2 looks like that:

akka {
    actor {
      provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster"                  
      deployment {                  
      }              
    }

    remote {
      log-remote-lifecycle-events = DEBUG
      log-received-messages = on

      helios.tcp {
        transport-class = "Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote"
            applied-adapters = []
            transport-protocol = tcp       
        hostname = "127.0.0.1"
        port = 0
      }
    }            

    cluster {
      #will inject this node as a self-seed node at run-time
      seed-nodes = ["akka.tcp://webcrawler@127.0.0.1:4053"] #manually populate other seed nodes here, i.e. "akka.tcp://lighthouse@127.0.0.1:4053", "akka.tcp://lighthouse@127.0.0.1:4044"
      roles = [crawler]
    }
  }

As seed node I am using lighthouse. From connection point of view everything seems to work out. The seed has been found and each node got has received a welcome message.

I thought I had location transparency on a Cluster and could reach remote resources as if they where local.

回答1:

I thought I had location transparency on a Cluster and could reach remote resources as if they where local.

This is not so easy. Consider following scenario: What if you've created an actor on both nodes under the same path. If you'll try to use relative path - without showing which node you have in mind - which of the actor's should receive the message?.

Using basic cluster capabilities you can choose node easily using Context.ActorSelection(_cluster.ReadView.Members.Single(m => /* which node you want to choose */).Address + "/user/ConsoleReceiver");. Cluster extension gives you a read view data with info about all members visible from current node.

There are many ways to send message to another actor, without having to know on which node it lives.

First approach is to use Akka.Cluster.Tools cluster singleton feature - it allows you to create at most one instance of an actor present in the cluster. In case of node failures it will migrate to another node. Be aware that this solution shouldn't be used, if you want to have many actors working that way. It's more for distinct, special-case actors.

Second approach is to use Akka.Cluster.Tools Distributed Pub/Sub feature to broadcast cluster-wide events across actors in the cluster subscribed to specific topic without worrying of their actual location. This is good choice for message broadcasting scenarios.

Last approach is to use Akka.Cluster.Sharding feature which manages actors lifecycle automatically - you don't need to create actors explicitly - it's also able to route messages to them from anywhere in the cluster and can rebalance them across many cluster nodes when needed.