有没有办法根据Akka(Scala)中的藏匿大小来路由消息

时间:2014-02-27 12:25:00

标签: scala akka

我有一个带负载均衡的工作池,其定义如下:

class Worker(workerNr: Int) extends Actor with Stash
...
val workers = (1 to poolSize).map(c => context.actorOf(Props(() => new Worker(c)).withDispatcher("stash-dispatcher"), "worker" + c))
val pool = context.actorOf(Props[Worker].withRouter(SmallestMailboxRouter(routees = workers)))
...
pool ! Request("do something")

现在这个工作者演员不是无国籍的,并且在他将请求转发给另一个演员(执行实际工作)并将所有后续请求存储起来之后使用,直到他获得当前请求的响应(可以采取而)。然后他将响应发送给请求的actor,解除所有被删除的消息,并在切换回unbecome后处理下一个请求。

case request@Request(_) => {
   val requestor = sender
   requestHandler ! request
   become {
     case response@Response(_) => {
       requestor ! response
       unstashAll
       unbecome
     }

     case msg => stash
   }
}

我的问题是SmallestMailboxRouter,我正在使用。它将消息路由到具有最小邮箱的worker。但是由于工作人员没有阻止,并且藏匿了他们目前无法处理的消息,他们的邮箱总是很空(与他们的存储相反)。

我想要一个路由器,它将消息路由到具有最小存储的工作者。我想过自己实现一个路由器这样做,但是看implementation of Stash,似乎我甚至无法访问存储大小,因为存储本身对于存储特征是私有的。

private var theStash = Vector.empty[Envelope]

有没有办法做到这一点,或者这是实现具有负载平衡的工作池的错误方法?

1 个答案:

答案 0 :(得分:4)

回答你最后问的这个问题:“有没有办法做到这一点,或者这是用错误的方法实现负载均衡的工作池?”

以下是我使用负载平衡实现工作池的方法:

有一个WorkerManager actor接收作业请求。它立即将它们放入自己的队列中。这可以是保存作业请求Job的任何类型的队列,例如Queue[Job]WorkerManager还有一个工作人员列表,其中包含了List[(ActorRef, Option[Job]]

每当WorkerManager收到Job请求并且在将其放入队列之后,它就可以检查分配的作业列表中是否有空闲的actor,即(ActorRef, None)。如果是,则它在该列表中为该工作者actor设置分配的作业,并向该actor发送Job消息。如果没有空闲工作人员WorkerManager根本不做任何事情,并等待其中一个工作人员回复作业完成消息。

另一方面,只要Worker完成对Job的处理,它就会使用WorkerManager ID回复Job,而WorkerManager会从列表中删除该作业已分配/正在运行的作业如果Worker失败,可以根据需要使用相同的作业重新启动。

您可以选择回复Client的人 - 可以是WorkerWorkerManager。出于这些目的,您可能希望将客户端ActorRefJob消息一起发送到Worker

并发队列修改或与维护队列相关的任何竞争条件都没有问题,因为Actors逐个处理消息,因此WorkerManager将始终按顺序处理队列。

此外Worker可以是具有状态转换超时的状态机,以避免永远等待它。

工作人员可以由WorkerManager创建,也可以单独创建,并通过发送注册消息向WorkerManager注册。可能有多个WorkerManager演员使用其中一种路由算法(循环法等)获取任务。

修改

显然有一种模式:) - 它被称为工作拉动模式或其他东西。