何时使用Actors vs Futures?

问题描述 投票:31回答:4

我目前正在玩Play!具有以下体系结构的项目:

控制器 - >服务(演员) - >模型(常规案例类)

对于每个请求,我们将发出对服务层的调用,如下所示:

Service ? DoSomething(request, context)

我们在应用程序初始化期间创建的akka​​路由器后面有一定数量的这些服务参与者,并且可以按需扩展。

在服务中,我们主要进行适度的数据操作或数据库调用:

receive = {
    case DoSomething(x, y) => {
           ...
           Model.doSometing(...)
           sender ! result
    }
}

我想知道我们是否应该使用演员来提供我们的服务,或者仅仅使用期货。

  1. 我们没有任何需要在服务参与者中修改的内部状态,无论消息进入函数并吐出结果。这不是演员模特的大力量吗?
  2. 我们正在做很多任务,这些任务似乎与演员模型相差甚远
  3. 我们没有进行繁重的计算和远程处理没有意义,因为大多数工作是针对数据库并且对远程actor进行往返操作以使得一些db调用是不必要的
  4. 我们确实使用reactivemongo,因此每个db调用都是非阻塞的。我们可以打很多电话

在我看来,删除akka并使用Futures让我们的生活变得更轻松,而且我们并没有真正失去任何东西。

akka playframework-2.2
4个回答
31
投票

关于什么应该和不应该是演员的话题肯定不缺乏意见。像这两个帖子:

http://noelwelsh.com/programming/2013/03/04/why-i-dont-like-akka-actors/

http://www.chrisstucchio.com/blog/2013/actors_vs_futures.html

我不认为你会找到这个问题的绝对答案,除此之外它是情境性的,这完全取决于你的偏好和你的问题。我能为你做的是提出我的意见,这是基于我们实施Akka约2年。

对我来说,我喜欢将Akka视为一个平台。我们为演员模型而来,但我们仍然保留平台提供的所有其他优点,如Clustering / Remoting,FSM,Routing,Circuit Breaker,Throttling等。我们正在尝试构建一个类似SOA的架构,我们的角色充当服务。我们正在集群中部署这些服务,因此我们利用位置透明度和路由等功能,为服务使用者(本身可能是另一项服务)提供查找和使用服务的能力,无论服务在何处部署,并以高度可用的方式。 Akka基于他们提供的平台工具使整个过程非常简单。

在我们的系统中,我们拥有所谓的基础服务的概念。这些是非常简单的服务(如特定实体的基本查找/管理服务)。这些服务通常不会调用任何其他服务,在某些情况下,只需执行数据库查找。这些服务是汇集的(路由器),通常没有任何状态。它们与您描述的某些服务非常类似。然后,我们开始在这些基础服务之上构建越来越复杂的服务。这些服务中的大多数是短暂的(以避免询问),有时基于FSM,从基础服务收集数据,然后紧缩并做一些事情。尽管这些基础服务本身非常简单,有些人会说不需要演员,但我喜欢灵活性,当我将它们组合成更高级别的服务时,我可以查找它们,它们可以在任何地方(位置透明) )在我的集群中,可以使用任意数量的实例(路由)。

因此,对于我们来说,实际上是一个设计决策,围绕一个演员作为一种类似微观的服务,可以在我们的集群中使用,供任何其他服务使用,无论服务多么简单。我喜欢通过粗粒度界面以异步方式与这些服务进行通信。很多这些原则都是构建良好SOA的方面。如果那是你的目标,那么我认为Akka在实现这一目标方面非常有帮助。如果您不想做类似的事情,那么您可能会质疑您决定使用Akka作为您的服务。就像我之前说过的那样,你需要从架构的角度弄清楚你想要做什么,然后设计你的服务层来实现这些目标。


8
投票

我认为你的轨道正确。

我们没有任何需要在服务参与者中修改的内部状态,无论消息进入函数并吐出结果。这不是演员模特的大力量吗?

我发现Chris Stucchio的博客(上面提到的@cmbaxter)非常令人愉快。我的情况非常简单,建筑方面的考虑不是一个有效的观点。像你一样,只需喷涂路由和大量数据库访问。没有国家。因此未来。这么简单的代码。


0
投票

我想知道同样的事情,我们决定做的是使用Akka进行数据访问,它运行良好,非常可测试(并经过测试),非常便携。

我们创建了存储库,长期存活的演员,我们在我们的应用程序中引导:(仅供参考,我们使用光滑的数据库访问,但我们的MongoDB需求也有类似的设计)

val subscriptionRepo = context.actorOf(Props(new SubscriptionRepository(appConfig.db)), "repository-subscription")

现在我们可以发送数据的“请求”消息,例如:

case class SubscriptionsRequested(atDate:ZeroMillisDateTime)

演员会回应

case class SubscriptionsFound(users: Seq[UserSubscription])

或失败(例外)

在我们的情况下(喷涂应用程序,还有CLI),我们将这些调用包装在一个简短的生活演员中,该演员接受上下文并在接收时完成并自行关闭。 (您可以在这些actor中处理特定于域的逻辑,让它扩展另一个管理其生命周期和异常的actor,这样您只需要为您的需求指定一个部分函数,​​并让抽象actor处理超时,常见异常等。

我们还有一些情况,我们需要在初始actor中完成更多的工作,并且非常方便地将x消息发送到您的存储库并让您的actor在它们到达时存储这些消息,在它们全部存在时执行某些操作,然后重新启动完成发送者(例如)并关闭自己。

多亏了这个设计,我们的应用程序外部有一个非常活跃的存储库,完全通过Akka TestKit和H2进行测试,完全与数据库无关,并且很容易从我们的数据库访问数据(我们从不做任何ASK,只有Tell:告诉回购,告诉发件人,完成或x告诉回购,模式匹配预期结果直到完成,告诉发件人)。


0
投票

当你需要一些非常长的生活状态修改状态时,应该创造一个演员。在其他情况下,演员没有任何好处,特别是来自非打字演员。 - 每次都进行模式匹配 - 控制actor的生命周期 - 记住不应该在线程之间传递的东西为什么在你可能有简单的Future的时候做所有这些?有些任务让演员很适合,但不是到处都是

© www.soinside.com 2019 - 2024. All rights reserved.