是否使用源队列实现线程安全的akka​​-http中的连接池?

时间:2017-03-25 07:32:56

标签: scala connection-pooling akka-stream akka-http

参考以下提及的实施方案:

http://doc.akka.io/docs/akka-http/10.0.5/scala/http/client-side/host-level.html

val poolClientFlow = Http().cachedHostConnectionPool[Promise[HttpResponse]]("akka.io")
val queue =
  Source.queue[(HttpRequest, Promise[HttpResponse])](QueueSize, OverflowStrategy.dropNew)
    .via(poolClientFlow)
    .toMat(Sink.foreach({
      case ((Success(resp), p)) => p.success(resp)
      case ((Failure(e), p))    => p.failure(e)
    }))(Keep.left)
    .run()

从多个线程提供队列http请求是否可以安全? 如果不是,那么实施此类要求的最佳方式是什么?或许使用专门的演员?

2 个答案:

答案 0 :(得分:2)

不,根据api docSourceQueue that current source is materialized to is for single thread usage only.

,它不是线程安全的

专门的演员可以正常工作,但是,如果可以的话,使用Source.actorRefdoc link)代替Source.queue会更容易。

一般来说,Source.actorRef的缺点是背压不足,但是当你使用OverflowStrategy.dropNew时,很明显你没有预料到背压。因此,您可以使用Source.actorRef获得相同的行为。

答案 1 :(得分:2)

正如@ frederic-a所说,SourceQueue不是线程安全的解决方案。

也许合适的解决方案是使用MergeHub(有关详细信息,请参阅docs)。这有效地允许您分两个阶段运行图表。

  1. 从您的枢纽到您的水槽(这实现了一个水槽)
  2. 将第1点物化的水槽分发给您的用户。 Sink实际上是为了分发而设计的,所以这是非常安全的。
  3. 根据MergeHub行为

    ,此解决方案将是安全的背压方式
      

    如果消费者无法跟上,那么所有的生产者都是   backpressured。

    下面的代码示例:

    val reqSink: Sink[(HttpRequest, Promise[HttpResponse]), NotUsed] =
      MergeHub.source[(HttpRequest, Promise[HttpResponse])](perProducerBufferSize = 16)
      .via(poolClientFlow)
      .toMat(Sink.foreach({
        case ((Success(resp), p)) => p.success(resp)
        case ((Failure(e), p))    => p.failure(e)
      }))(Keep.left)
      .run()
    
    // on the user threads
    
    val source: Source[(HttpRequest, Promise[HttpResponse]), NotUsed] = ???
    source.runWith(reqSink)