如何使用背压溢出策略创建akka-http客户端?

时间:2017-12-11 21:47:37

标签: scala akka akka-stream akka-http

我有未定义数量的akka​​-http客户端从http服务下载数据。我使用akka-http主机级连接池,因为我想自定义池,因为有长时间运行的请求通过它。

由于客户端数量未定义且动态,我不知道如何配置连接池(max-open-requests / max-connections)。另外,我可能希望连接池很小(少于客户端数量),以免损坏带宽。

因此,我想设置一个客户端流程,以便新的连接和对池的请求被反压:

1.这是否意味着我需要一个物化的客户流程?

2.如何实现尽可能多的客户端流量,这样如果没有可用的连接(来自下游的需求)请求将被回压。

我的第一次尝试是Source.single pattern,但是这种方法可以超过max-open-request并抛出异常,因为每次将请求发送到服务器时它都会创建一个新的流实例。

我的第二次尝试是Source.Queue,这种方法创建了一个流,所有请求都被排入队列:但是尽管文档源SourceQueue的OverflowStrategy背压不起作用,当它超过max-connection或max-时open-request,akka-http抛出exception

我可以使用host-level streaming fashion完成背压 并拥有一个客户流程并使用MergeHub添加新请求?

这是我的解决方案:

  private lazy val poolFlow: Flow[(HttpRequest, Promise[HttpResponse]), (Try[HttpResponse], Promise[HttpResponse]), Http.HostConnectionPool] =
    Http().cachedHostConnectionPool[Promise[HttpResponse]](host.split("http[s]?://").tail.head, port, connectionPoolSettings)

  val ServerSink =
    poolFlow.async.toMat(Sink.foreach({
      case ((Success(resp), p)) => p.success(resp)
      case ((Failure(e), p)) => p.failure(e)
    }))(Keep.left)

  // Attach a MergeHub Source to the consumer. This will materialize to a
  // corresponding Sink.
  val runnableGraph: RunnableGraph[Sink[(HttpRequest, Promise[HttpResponse]), NotUsed]] =
  MergeHub.source[(HttpRequest, Promise[HttpResponse])](perProducerBufferSize = 16).to(ServerSink)


  val toConsumer: Sink[(HttpRequest, Promise[HttpResponse]), NotUsed] = runnableGraph.run()


  protected[akkahttp] def executeRequest[T](httpRequest: HttpRequest, unmarshal: HttpResponse => Future[T]): Future[T] = {
    val responsePromise = Promise[HttpResponse]()
    Source.single((httpRequest -> responsePromise)).runWith(toConsumer)
    responsePromise.future.flatMap(handleHttpResponse(_, unmarshal))
    )
  }

0 个答案:

没有答案