簡體   English   中英

Akka Stream TCP + Akka Stream Kafka制作人不停止不發布消息而不是錯誤輸出

[英]Akka Stream TCP + Akka Stream Kafka producer not stopping not publishing messages and not error-ing out

我有以下流:

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放在上面,我可以看到以下行為:

每位演員的郵箱大小

每個Actor的郵箱時間

每位演員的處理時間

它看起來像是在沒有通知流應該停止的情況下停止了,但我不知道如何使其顯式並停止流。

我建議用監督屬性創建流程來處理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)
  }

如果流有任何錯誤,則流停止。 使用此配置,您將查看流是否已拋出任何異常。

如果一切都變得沉默, 可能會在某個地方應用背壓。 嘗試並選擇性地更換具有非背壓感知階段的背壓感知階段,並檢查問題是否仍然存在。 在您的情況下,有兩種可能的背壓源:

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個案例中只有一個看到問題嗎? 同時? 沒有?

流沒有失敗,但是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,跟隨啟動失敗,可以重新啟動另一個流程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM