当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的目的。