Akka - 你应该创建多少个Actor实例?

69

我不熟悉Akka框架,目前正在使用Netty + Akka构建HTTP服务器应用程序。

我的想法是为每种类型的请求创建一个Actor。例如,我会为POST到/my-resource的请求创建一个Actor,为GET到/my-resource的请求创建另一个Actor。

我困惑的是如何创建Actor?我应该:

  1. 针对每个请求创建一个新的Actor(也就是说,对于每个请求,应该使用适当的Actor的TypedActor.newInstance()创建一个新的Actor)?创建一个新的Actor的代价有多大?

  2. 在服务器启动时创建每个Actor的一个实例,并将该Actor实例用于每个请求?我读过一个Actor只能处理一个消息,那么这样做是否会成为瓶颈?

  3. 还有其他方法吗?

感谢任何反馈。

5个回答

36

对于每个需要管理的可变状态实例,都要创建一个Actor。

在您的情况下,如果my-resource是单个对象,并且您想要按顺序处理每个请求,则可能只需要一个Actor- 这很容易确保在修改之间仅返回一致的状态。

如果(更有可能)您管理多个资源,则每个资源实例通常最好一个Actor,除非您遇到许多资源。虽然您也可以运行每个请求的Actor,但是如果不考虑这些请求正在访问的状态,您将会得到一种奇怪的设计——例如,如果您只为每个POST请求创建一个Actor,则会发现自己担心如何使它们不同时修改同一资源,这清楚地表明您错误地定义了Actor。

我通常使用相当简单的请求/响应Actor,其主要目的是抽象与外部系统的通信。它们与“实例”Actor 的通信通常仅限于执行实际操作的一对请求/响应。


25

选项1或2都有其缺点。那么,让我们使用选项 3) Routing(Akka 2.0+)

路由器是一个元素,充当负载均衡器,将请求路由到执行所需任务的其他Actor。

Akka提供了不同的路由器实现,具有不同的逻辑来路由消息(例如SmallestMailboxPool或RoundRobinPool)。

每个路由器可以有多个子级,并且其任务是监督它们的邮箱以进一步确定要将接收到的消息路由到哪里。

//This will create 5 instances of the actor ExampleActor
//managed and supervised by a RoundRobinRouter
ActorRef roundRobinRouter = getContext().actorOf(
Props.create(ExampleActor.class).withRouter(new RoundRobinRouter(5)),"router");

这个过程在这篇博客中有很好的解释。


1
当你说将请求路由到时 - Diego Ramos

25

如果你正在使用Akka,你可以为每个请求创建一个Actor。Akka非常节省资源,你可以在普通的JVM堆上创建成百上千甚至是数百万个Actor。此外,它们只会在实际执行任务时才会消耗CPU/堆栈/线程。

一年前我对基于线程和事件的标准Actor的资源消耗进行了比较,而Akka甚至比事件更好。

在我看来,Akka的一个重要特点是它“允许”你将系统设计为“每个用途一个Actor”,而早期的Actor系统往往强制你只使用Actor来共享服务,因为存在资源开销。

我建议你选择选项1。


我认为问题不在于资源开销 - 我的意思是,我理解这个问题是涉及到架构问题的。我不认为我理解创建每个请求一个Actor的好处 - 你尝试用这种方法解决什么并发问题?我认为您应该先了解要管理的资源,然后再决定需要多少个Actor。 - Victor

9
  1. 这是一个相当合理的选项,但其是否适用取决于您请求处理的具体情况。

  2. 是的,当然可以。

  3. 对于许多情况来说,最好的做法就是只有一个actor响应每个请求(或者也可以每种请求一个actor),但这个actor所做的唯一事情就是将任务转发给另一个actor(或产生一个Future),由它来实际完成工作。


在第3点中,这是否意味着如果执行该actor的机器具有多个核心,它将无法正确使用? - Diego
1
@Diego 不行,因为它转发到的actor/future可能会在那些核心上工作。 - Alexey Romanov

4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接