我有一个演员聚集一些信息并对其进行处理。它目前看起来像这样:
class MessageTracerActor extends Actor{
override def receive: Receive = {
case MyActor.TracableMessage(msg) => //send processed msg to another place
case v: Any => //corner-case, has special handler
}
}
演员应该发送延伸TracableMessage
的消息。但TracableMessages
是从相当多的演员发送的,并且在一台机器上托管MessageTracerActor
并不是很好。
我看了cluster shrading,但事实并非如此。他们说
当你有许多有状态的演员时,通常会使用群集分片 一起消耗更多资源(例如内存),而不是合适的资源 机。如果你只有一些有状态的演员,那可能会更容易 在 Cluster Singleton 节点上运行它们。
但Cluster Singleton严格托管在一个不可扩展的节点上。
也许有一些配置选项可用于指定用于处理actor接收的消息的线程数量(甚至是节点)?
答案 0 :(得分:4)
有一些选项可以将消息处理扩展到单个actor之外。
如果跟踪消息处理是无状态的,则可以使用routing在跟踪消息处理参与者的多个实例之间分配工作。路由器是一个参与者,它建立一个处理参与者池,并在处理参与者之间分发每个传入的消息。
// create a round robin style router for actors
val router: ActorRef = context.actorOf(RoundRobinPool(5).props(Props[MessageTracerActor]), "tracer-router")
在上面的示例中,循环式路由器用于均匀地在跟踪器角色之间分发消息。这意味着您将丢失发送到路由器的消息之间的排序保证:以后排队的消息可能会在之前排队的消息之前处理。由于每个消息处理器只能看到传入消息的任意子集,因此无法一致地进行状态处理(如聚合)。
为了使排序保持一致,您必须考虑需要按顺序排列的消息。如果所有可追踪消息都需要按照他们进入路由器的顺序进行处理,那么路由器就不会对您有所帮助。但是,某些可跟踪消息可能需要按顺序处理,而不是其他消息。例如,您的可追踪消息可能包含消息的来源,并且必须仅在来自同一来源的消息之间保证排序。
识别消息之间的顺序允许您以一致的方式在消息处理器之间分发消息。 Akka使用consistent hashing pools为此提供功能。在一致性散列池中,路由器基于散列密钥机制将传入消息分发到消息处理器。具有相同路由哈希密钥的消息将路由到同一个消息处理器,这意味着您可以针对可跟踪消息的子集始终对传入消息进行聚合。
如果一个Akka节点不足以处理可跟踪消息,则可以使用Akka的clustering features扩展消息处理。在群集中,您有多个相互连接的Akka节点,通过在群集中分配工作而不是处理单个节点中的所有内容来协同工作。
在群集中,您可以使用前面介绍的工具的分布式版本。对于消息的无状态和有状态路由,您可以使用a cluster aware router。群集感知路由器跨群集成员节点创建消息处理器池,而不是在单个节点中创建所有消息处理器。
除群集感知路由器外,您还可以使用cluster sharding。与在一致性哈希池中一样,您需要为群集分片指定哈希键,以便始终将消息路由到正确的actor。群集感知路由器和分片之间的区别在于分片会自动为每个密钥创建一个actor,因此消息处理器actor不需要单独处理来自不同密钥的消息。
如果所有可追踪消息都需要在同一状态下聚合,那么您的最终选择是考虑Akka的distributed data功能。在此功能中,聚合工作分布在多个节点上,并在稍后阶段加入。请注意,分布式数据API在Akka 2.4中仍处于试验阶段。
跨多个节点分发消息处理意味着单个消息处理器丢失的风险更高(例如,网络连接失败,节点崩溃)。为了使状态在节点之间保持持久性和可转移性,您可能需要查看Akka的persistence功能。