我目前正在学习有关akka流的信息,并且我正在尝试实现一个简单的流,该流从源中获取项目并调用a REST API用于每一项。
我的代码的简化版本如下:
source.mapAsync(parallelism){ item =>
Http().singleRequest(HttpRequest(HttpMethods.GET, "http://myserver:8080/$item"))
.flatMap(response => response.entity.toStrict(20.seconds))
}
我现在想知道如果瓶颈是REST服务器,如何设置parallelism
以获得最大的吞吐量。
我的理解是,如果我们假设服务器无法并行处理请求,则可以使用parallelism = 1
作为第一近似值
然后我的信息流会发送一个请求。
如果服务器可以并行处理n
个请求,则流将不会利用该请求,因此我必须设置parallelism = n
才能获得一个
更好的吞吐量。
我现在可以使用parallelism
来在给定的时间点优化设置的吞吐量。
但是,myserver可能位于负载平衡器和自动缩放器之后。然后,流中可用的并行请求数将取决于时间
也许我的程序不是REST API的唯一用户。
我的问题是,当我想尽可能利用myserver时,调用REST API的最佳方法是什么? 不想承受压力还是尚未扩大规模?
答案 0 :(得分:0)
实际上,这是一种内置流,因为它们正在利用背压。因此,只要其余服务器达到极限,答案将花费更长的时间,然后您的流将向源请求更少的请求。因此,您实际上不需要针对请求服务器的当前状态优化并行性,而是对其进行调整以获得良好的吞吐量。对于任何请求的服务器,这只会与您请求的服务器能够回答的速度一样快。 通过使用与上面类似的Graph ure,我能够将2个节点的群集扩展到其极限,并在群集中内置了16个节点,并按比例放大,因此Graph在两种状态下均能正常工作,只有吞吐量显着提高: )。
通过将并行度设置为计算机所使用的内核数量,您应该过得很好。
您还可以在源上使用.throttle(...)
来设置每个时间单位要提供的最大请求数。
如果您动态地希望对服务响应的最大请求数量做出反应,然后说将自己限制为其中的80%,那么我认为您必须为此编写一些自定义代码。例如,流阶段计算请求的时间,然后相应地进行节流,并在稍后扩展以防服务规模扩大等等。但是,最终每个用户的请求处理应处于请求的服务级别。
答案 1 :(得分:0)
提出问题的方式比问题中显示的方式更为“最佳”。
如果使用connection level client-side api,则可以打开与您感兴趣的服务的连接池:
val connectionFlow: Flow[HttpRequest, HttpResponse, Future[Http.OutgoingConnection]] =
Http().outgoingConnection("http://myserver:8080")
此池可用于处理您的item
请求:
type Item = ???
val itemToRequest : Item => HttpRequest =
item => HttpRequest(uri = URI(item.toString))
source
.map(itemToRequest)
.via(connectionFlow)
.flatMap(_.entity.toStrict(20.seconds))
然后,您可以使用the akka configuration settings指定对myserver
的打开请求的最大数量:
host-connection-pool {
max-open-requests = 8
}
答案 2 :(得分:-3)
因此,方法mapAsync(parallelism)
属于object source
,并且您具有一些嵌套函数-让我们将其简化为几个简单函数,而不是一个大嵌套函数,应该对其进行优化。