【问题标题】:Akka Stream TCP + Akka Stream Kafka producer not stopping not publishing messages and not error-ing outAkka Stream TCP + Akka Stream Kafka 生产者不停止不发布消息并且不出错
【发布时间】:2017-04-29 09:09:27
【问题描述】:

我有以下流:

Source(IndexedSeq(ByteString.empty))
.via(
  Tcp().outgoingConnection(bsAddress, bsPort)
    .via(Framing.delimiter(ByteString("\n"), 256, allowTruncation = true))
    .map(_.utf8String)
)
.map(m => new ProducerRecord[Array[Byte], String](kafkaTopic, m))
.runWith(
  Producer.plainSink(
    ProducerSettings(system, new ByteArraySerializer, new StringSerializer)
      .withBootstrapServers(s"${kafkaAddress}:${kafkaPort}")
  )
).onComplete {
    case Success(Done) => printAndByeBye("Stream ends successfully")
    case Failure(ex) => printAndByeBye("Stream ends with an error: " + ex.toString)
  }

它可以正常工作一段时间,我可以使用填充在 Kafka 主题上的消息。但是有时,显然是在一个随机的时间间隔,没有更多的消息发布,并且这段代码没有记录任何错误(printAndByeBye 将打印传递的消息并终止actor系统。)重新启动应用程序后,消息继续流。

知道如何知道这里发生了什么吗?

编辑:我把 Kamon 放在上面,我可以看到以下行为:

似乎在没有通知流应该停止的情况下停止了某些事情,但我不知道如何使其明确并停止流。

【问题讨论】:

    标签: scala akka akka-stream akka-kafka


    【解决方案1】:

    我建议使用监督属性创建流,以处理 TCP 连接中可能出现的异常:

    val flow = 
        Tcp().outgoingConnection("", 12)
              .via(Framing.delimiter(ByteString("\n"), 256, allowTruncation = true))
              .map(_.utf8String).withAttributes(ActorAttributes.supervisionStrategy {
          case ex: Throwable =>
            println("Error ocurred: " + ex)
            Supervision.Resume
         }
    

    Source(IndexedSeq(ByteString.empty))
    .via(flow)
    .map(m => new ProducerRecord[Array[Byte], String](kafkaTopic, m))
    .runWith(
      Producer.plainSink(
        ProducerSettings(system, new ByteArraySerializer, new StringSerializer)
          .withBootstrapServers(s"${kafkaAddress}:${kafkaPort}")
      )
    ).onComplete {
        case Success(Done) => printAndByeBye("Stream ends successfully")
        case Failure(ex) => printAndByeBye("Stream ends with an error: " + ex.toString)
      }
    

    如果流有任何错误,流将停止。使用此配置,您将看到流程是否引发了任何异常。

    【讨论】:

      【解决方案2】:

      如果一切都静默了,可能是因为在某处施加了背压。 尝试并有选择地用非背压感知阶段替换您的背压感知阶段,并检查问题是否仍然存在。 在您的情况下,有两种可能的背压来源:

      1) TCP 连接

      您可以尝试将ByteString 的无限源附加到 Kafka,执行以下操作:

      Source.cycle(() => List(???).iterator)
      .map(m => new ProducerRecord[Array[Byte], String](kafkaTopic, m))
      .runWith(
        Producer.plainSink(
          ProducerSettings(system, new ByteArraySerializer, new StringSerializer)
            .withBootstrapServers(s"${kafkaAddress}:${kafkaPort}")
        )
      ).onComplete {
          case Success(Done) => printAndByeBye("Stream ends successfully")
          case Failure(ex) => printAndByeBye("Stream ends with an error: " + ex.toString)
        }
      

      2) 卡夫卡水槽

      用一些日志替换它

      Source(IndexedSeq(ByteString.empty))
      .via(
        Tcp().outgoingConnection(bsAddress, bsPort)
          .via(Framing.delimiter(ByteString("\n"), 256, allowTruncation = true))
          .map(_.utf8String)
      )
      .map(m => new ProducerRecord[Array[Byte], String](kafkaTopic, m))
      .runForeach(println)
      .onComplete {
          case Success(Done) => printAndByeBye("Stream ends successfully")
          case Failure(ex) => printAndByeBye("Stream ends with an error: " + ex.toString)
        }
      

      您能否仅在 2 种情况中的一种中看到问题?同时?没有?

      【讨论】:

      【解决方案3】:

      流没有失败,但是 TCP 流空闲了,因为发布数据的设备在一段时间后停止发送数据而没有断开连接。 而不是使用更简单的:

      TCP().outgoingConnection(bsAddress, bsPort)
      

      我最终使用:

      def outgoingConnection(
      remoteAddress:  InetSocketAddress,
      localAddress:   Option[InetSocketAddress]           = None,
      options:        immutable.Traversable[SocketOption] = Nil,
      halfClose:      Boolean                             = true,
      connectTimeout: Duration                            = Duration.Inf,
      idleTimeout:    Duration                            = Duration.Inf): Flow[ByteString, ByteString, Future[OutgoingConnection]] = ???
      

      所以

      Tcp().outgoingConnection(bsAddress, bsPort)
      

      成为

      val connectTimeout: Duration = 1 second
      val idleTimeout: Duration = 2 second
      Tcp().outgoingConnection(
          remoteAddress = InetSocketAddress.createUnresolved(bsAddress, bsPort),
          connectTimeout = connectTimeout,
          idleTimeout = idleTimeout
        )
      

      通过通知 idleTimeout,follow start 失败,可以重新启动另一个流。

      【讨论】:

        猜你喜欢
        • 2021-07-09
        • 1970-01-01
        • 1970-01-01
        • 2018-01-19
        • 1970-01-01
        • 2015-03-06
        • 2021-10-23
        • 2019-03-15
        • 2018-03-08
        相关资源
        最近更新 更多