Akka HTTP:使用Akka Streams还是Actors构建REST服务?

22

当涉及到使用akka http创建60多个API的REST web服务时,我该如何选择是使用akka streams还是akka actors?Jos在他的文章中展示了两种在akka http上创建API的方法,但他没有说明我应该在何时选择其中一种方式。

2个回答

24

这是一个很难回答的问题。显然,两种方法都可行。因此在某种程度上,这是一种品味/熟悉度的问题。因此,接下来的所有内容都只代表我的个人观点。

如果可能的话,我更喜欢使用akka-stream,因为它具有更高级别的特性和类型安全性。但是否这种方法适用取决于REST API任务。

Akka-stream

如果您的REST API是一种根据外部数据(例如货币汇率API)回答问题的服务,则最好使用akka-stream实现。

另一个akka-stream更适合的示例是某种数据库前端,其中REST API的任务是解析查询参数,将它们转换为DB查询,执行查询并根据用户请求的内容类型转换结果。在这两种情况下,数据流易于映射到akka-stream原语。

Actors

使用actors更适合的示例可能是,如果您的API允许在集群上查询和更新多个持久actors。在这种情况下,纯基于actor的解决方案或混合解决方案(使用akka-stream解析查询参数和转换结果,其余使用actors)可能更适合。

另一个使用基于actor的解决方案更合适的示例是,如果您有一个REST API用于长时间运行的请求(例如Websockets),并且希望将REST API本身的处理流水线部署在集群上。我认为使用akka-stream目前根本无法实现这种情况。

总结

因此,总之:查看每个API的数据流,并查看它是否可以干净地映射到akka-stream提供的原语。如果是这种情况,请使用akka-stream实现。否则,使用actors或混合解决方案进行实现。


感谢Rüdiger提供清晰的答案。我不喜欢混合使用的原因是,为了实现反压力,您需要依赖于发布者/订阅者模型来管理您的actor。这将迫使您在向actor层次结构发送请求时严重依赖于“ask”模式而非“tell”模式。每个请求一个actor的模式非常有价值,考虑到新actor的成本微不足道。我还看到流作为底层子REST服务的聚合器非常有效,可以轻松地对子API进行分组。当您开发移动应用程序时,这一点尤其重要,因为请求数量应该最小化。您认为呢? - Mutaz
1
说实话,我尽量多使用akka-stream,并且只在特殊部署或其他需求时才使用原始的actors。我认为很多使用情况都可以很好地映射到akka-stream。 - Rüdiger Klaehn
太好了!顺便问一下,你能提供一个简单的用例来解释这句话吗?“如果你的API允许在集群上查询和更新多个持久化的actor,那么使用actor可能更好。” - WeiChing 林煒清

11

不要忘记使用Futures!

我想对Rudiger Klaehn的回答进行补充,考虑到Future的使用情况。 Futures的可组合性和ExecutionContext的资源管理使得Futures在许多情况下都是理想的选择。

有一篇优秀的博客文章描述了何时使用Futures比使用Actors更好。此外,流提供的反压力带来了相当大的开销

仅仅因为你在使用akka-http并不意味着你的请求处理程序中所有的并发都必须限制在Actors或Streams中。

路由(Route)

Route类型定义中天然地支持Futures:

type Route = (RequestContext) ⇒ Future[RouteResult]

因此,您可以仅使用函数和Futures而无需指令,直接将Future嵌入到您的路由中进行处理:
val requestHandler : RequestContext => HttpResponse = ???

val route : Route = 
  (requestContext) => Future(requestHandler(requestContext)) map RouteResult.Complete

onComplete指令

onComplete指令允许你在Route中“解包”一个Future:

val route = 
  get {

    val future : Future[HttpResponse] = ???

    onComplete(future) {
      case Success(httpResponse) => complete(httpResponse)
      case Failure(exception)    => complete(InternalServerError -> exception.toString)
    }
  } 

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