我正在尝试处理可以“会话”到会话中的事件流。计划是使用一个actor池,其中来自池的单个actor将处理来自一个会话的所有事件(原因是我需要维护一些会话状态)。在我看来,为了让我实现这一点,我必须保持ActorRef周围的特定演员被分配到特定的会话。但是,如果我使用:
使用actor池val randomActor = _system.actorOf(Props[SessionProcessorActor].withRouter(RandomPool(100)), name = "RandomPoolActor")
然后,在这种情况下, randomActor 将ActorRef提供给整个池,而不是池中的各个actor。那我怎么能实现我上面提到的呢?
我能想到的一种方法是在池中的actor初始化之后发回引用(可能看起来像RandomPoolActor $ ab等)。然而,这个方法有一些问题,其中一个是我必须使用ask模式而不是tell,这样我就不会错过来自同一会话的事件。
任何其他方式来实现这一目标?还有其他任何模式吗?
答案 0 :(得分:2)
您可以使用ConsistentHashingPool
来执行与您要查找的内容类似的操作。 ConsistentHashingRouter
确保每条消息都基于hashKey
在同一个actor中结束。此键将是您的方案中的sessionId。没有必要保持ActorRefs或其他引用来完成此任务。
您可以通过多种方式在代码中定义hashKey
。我建议创建一个扩展ConsistentHashable
的案例类。完成后,您将需要实施方法consistentHashKey
。例如:
case class HashableEnvelope(yourMsgClass: YourMsgClass) extends ConsistentHashable {
override def consistentHashKey = yourMsgClass.sessionId
}
然后你可以像这样定义你的游泳池:
val pool = system.actorOf(Props[SessionProcessorActor].withRouter(ConsistentHashingPool(100)))
另外要提到的是路由器将确保具有相同hashKey的所有消息将最终在同一个actor中,但是,它不能确保特定actor仅接收给定hashKey的消息。它可以接收多个hashKeys。这不应该是一个问题,只是你的SessionProcessorActor
应该能够处理一些hashKeys而不是一个。
一致的散列算法将决定哪个消息发送给每个actor。您可以在维基百科上阅读它的工作原理:https://en.wikipedia.org/wiki/Consistent_hashing。要以更均匀的方式分发消息,您应该增加配置中的虚拟节点数(默认值为10):
akka.actor.deployment.default.virtual-nodes-factor = 1000
根据您拥有的sessionIds和actor的数量,您将看到该消息的分布更加均匀。