akka balance router的实现

当akka处于balance策略的时候,Akka的父actor在选择相应的子actor去执行相应的消息时,不会直接直接选择,而是在分发器dispatch中,通过共享邮箱的方式,选择一个空闲的子actor去执行这个消息。

 

具体的balance策略BalanceRoutingLogic的apply方法只是返回了所有子actor的第一个,并没有执行具体的选择操作。

private[akka] object BalancingRoutingLogic {
  def apply(): BalancingRoutingLogic = new BalancingRoutingLogic
}

但是,在balance对应的RouterPool的BalancePool则实现了自己的newRoutee()方法,在这个方法中,给actor对应的分发器设置了BalancingDispatcherConfigurator,使得具体的分发器变成了BalancingDispatcher,并建立了actor与分发器的绑定关系。

override private[akka] def newRoutee(routeeProps: Props, context: ActorContext): Routee = {

  val rawDeployPath = context.self.path.elements.drop(1).mkString("/", "/", "")
  val deployPath = BalancingPoolDeploy.invalidConfigKeyChars.foldLeft(rawDeployPath) { (replaced, c) =>
    replaced.replace(c, '_')
  }
  val dispatcherId = s"BalancingPool-$deployPath"
  def dispatchers = context.system.dispatchers

  if (!dispatchers.hasDispatcher(dispatcherId)) {
    // dynamically create the config and register the dispatcher configurator for the
    // dispatcher of this pool
    val deployDispatcherConfigPath = s"akka.actor.deployment.$deployPath.pool-dispatcher"
    val systemConfig = context.system.settings.config
    val dispatcherConfig = context.system.dispatchers.config(
      dispatcherId,
      // use the user defined 'pool-dispatcher' config as fallback, if any
      if (systemConfig.hasPath(deployDispatcherConfigPath))
        systemConfig.getConfig(deployDispatcherConfigPath)
      else ConfigFactory.empty)

    dispatchers.registerConfigurator(
      dispatcherId,
      new BalancingDispatcherConfigurator(dispatcherConfig, dispatchers.prerequisites))
  }

  val routeePropsWithDispatcher = routeeProps.withDispatcher(dispatcherId)
  ActorRefRoutee(context.actorOf(routeePropsWithDispatcher))
}

在具体执行平衡逻辑的BalancingDispathcer中,在其dispatch()方法中实现了平衡的目的。

override protected[akka] def dispatch(receiver: ActorCell, invocation: Envelope) = {
  messageQueue.enqueue(receiver.self, invocation)
  if (!registerForExecution(receiver.mailbox, false, false)) teamWork()
}

protected def teamWork(): Unit =
  if (attemptTeamWork) {
    @tailrec def scheduleOne(i: Iterator[ActorCell] = team.iterator): Unit =
      if (messageQueue.hasMessages
          && i.hasNext
          && (executorService.executor match {
            case lm: LoadMetrics => lm.atFullThrottle == false
            case _               => true
          })
          && !registerForExecution(i.next.mailbox, false, false))
        scheduleOne(i)

    scheduleOne()
  }

在BalancingDispathcer中,所有共享邮箱的actor都会保存在team中,当第一次的actor也就刚才的第一个actor进入,将会直接被消息分配给它,但是如果第二条消息进来,之前的actor如果还没有处理完毕,将会选取team中的下一个空闲的actor进行分配,达到平衡到空闲actor的目的。

发布了141 篇原创文章 · 获赞 19 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/weixin_40318210/article/details/90982216