在Akka的ClusterRouter中向Routees广播消息

时间:2013-05-20 21:47:25

标签: scala akka broadcast akka-cluster

我正在尝试向ClusterRouter配置中的所有路由广播消息。我已经尝试了两种选择。这一个:

 val workerRouter = context.actorOf(Props[ClusterRouter].withRouter(
    ClusterRouterConfig(AdaptiveLoadBalancingRouter(metrics), ClusterRouterSettings(
      totalInstances = 100, routeesPath = "/user/slave",
      allowLocalRoutees = true, useRole = None))), name = "slaveRouter")

  context.system.scheduler.schedule(2 seconds, 5 seconds, workerRouter, Broadcast(CapabilityRequest))

这一个:

 val broadcastRouter = context.actorOf(Props[ClusterRouter].withRouter(
    ClusterRouterConfig(BroadcastRouter(Nil), ClusterRouterSettings(
      totalInstances = 100, routeesPath = "/user/slave",
      allowLocalRoutees = true, useRole = None))), name = "slaveRouter")

  context.system.scheduler.schedule(2 seconds, 5 seconds, broadcastRouter, CapabilityRequest)

但是对于他们两个,只有slaves中的一个收到了消息。想法?


为了理解为什么我认为第一次尝试应该有效,我必须在创建AdaptiveLoadBalancingRouterLike时在Route特征中查看AdaptiveLoadBalancingRounter.scala

{
  case (sender, message) ⇒
    message match {
      case Broadcast(msg) ⇒ toAll(sender, routeeProvider.routees)
      case msg            ⇒ List(Destination(sender, getNext()))
    }
}

1 个答案:

答案 0 :(得分:2)

在您的第一个示例中,您使用的路由器只会发送给一个路由器。从我读过的文档中,这个路由器将使用来自不同节点的指标来选择看似受到最少胁迫的节点,并向该节点上的routee发送消息。我认为您预期会出现此设置的行为。

在第二个示例中,我没有在文档中看到有关在群集环境中使用BraodcastRouter的内容,因此我不确定是否支持此方法。话虽如此,我的猜测是创建带有空路由列表(BraodcastRouter)的Nil是导致您看到的行为的原因。我想如果你将其改为BroadcastRouter(100),你可能会看到不同的行为。但同样,我不认为(基于文档中缺少示例)支持使用BroadcastRouter(我可能错了)。

您能否对您的用例进行更多解释,以便了解为什么您的群集需要广播类型的路由器?

修改

FWIW,我使用以下代码。首先,配置:

akka {
  actor {
    provider = "akka.cluster.ClusterActorRefProvider"
  }
  remote {
    transport = "akka.remote.netty.NettyRemoteTransport"
    log-remote-lifecycle-events = off
    netty {
      hostname = "127.0.0.1"
      port = 0
    }
  }

  cluster {
    min-nr-of-members = 2
    seed-nodes = [
      "akka://ClusterSystem@127.0.0.1:2551", 
      "akka://ClusterSystem@127.0.0.1:2552"]

    auto-down = on
  }
}

然后,我使用以下代码启动了两个节点(一个在2551上,另一个在2552上):

object ClusterNode {

  def main(args: Array[String]): Unit = {

    // Override the configuration of the port 
    // when specified as program argument
    if (args.nonEmpty) System.setProperty("akka.remote.netty.port", args(0))


    // Create an Akka system
    val system = ActorSystem("ClusterSystem")
    val clusterListener = system.actorOf(Props(new Actor with ActorLogging {
      def receive = {
        case state: CurrentClusterState =>
          log.info("Current members: {}", state.members)
        case MemberJoined(member) =>
          log.info("Member joined: {}", member)
        case MemberUp(member) =>
          log.info("Member is Up: {}", member)
        case UnreachableMember(member) =>
          log.info("Member detected as unreachable: {}", member)
        case _: ClusterDomainEvent => // ignore

      }
    }), name = "clusterListener")

    Cluster(system).subscribe(clusterListener, classOf[ClusterDomainEvent])    
  }

}

class FooActor extends Actor{

  override def preStart = {
    println("Foo actor started on path: " + context.self.path)
  }

  def receive = {
    case msg => println(context.self.path + " received message: " + msg)
  }
}

然后我使用以下代码启动了第三个“节点”,我的客户端节点:

object ClusterClient {
  def main(args: Array[String]) {
    val system = ActorSystem("ClusterSystem")

    Cluster(system) registerOnMemberUp{
      val router = system.actorOf(Props[FooActor].withRouter(
        ClusterRouterConfig(AdaptiveLoadBalancingRouter(HeapMetricsSelector),
        ClusterRouterSettings(
        totalInstances = 20, maxInstancesPerNode = 10,
        allowLocalRoutees = false))),
        name = "fooRouter")  

     router ! Broadcast("bar")
    }
  }
}

当发送消息时,我看到它在两个服务器节点VM中都被接收,每个VM有10个actor。

我的路由器与您的路由器之间的区别在于我没有指定本地路由,而是为routeesPath交换了maxInstancesPerNode。我希望这会有所帮助。