簡體   English   中英

Akka Stream 動態接收器取決於來自 Kafka 主題的消息

[英]Akka Stream dynamic Sink depending on Message from Kafka topic

我有一個閱讀 Message 的 Kafka 消費者。 每條消息都有一個 ID 和內容。

case class Message(id: String, content: String)

根據 ID,我想將 Message 寫入單獨的接收器。 具體到 MongoDB 集合中。 Mongo 提供了一個 Sink 將其寫入 DB 到指定的集合中。

val sink: Sink[Document, Future[Done]] = MongoSink.insertOne(collection(id))

問題是,我需要在連接 Kafka 消費者源時指定接收器,但是每個元素都定義了它應該進入哪個接收器 go。 有沒有辦法在元素到達時動態使用特定的接收器。 或者這是不可能的,例如,我應該為每個 id 使用不同的 Kafka 主題並將每個源連接到單獨的接收器?

您的示例中的類型如何排列並不完全清楚(例如DocumentMessage之間的關系),但您可以采取以下幾種方法:

  • 如果有很多可能的 collections 並且無法提前知道,那么 Akka Streams 中最不壞的選項將是
Sink.foreachAsync[Message](parallelism) { msg =>
  val document = documentFromMessage(msg)
  val collection = collection(msg.id)
  Source.single(document).runWith(MongoSink.insertOne(collection))
}

請注意,這將為每條消息使用一個新的 Mongo 接收器,這可能會帶來效率問題。 請注意,如果有一種更輕量級的方式(例如在 reactivemongo 驅動程序中?)在插入單個文檔后返回Future ,但使用連接池之類的東西來減少單個文檔插入的開銷,那可能會更可取。

  • 如果事先知道 collections,您可以為每個集合預構建接收器並使用PartitionGraphDSL定義一個包含預構建接收器的接收器
// collection0, etc. are predefined and encompass all of the collections which might be returned by collection(id)
val collections: Map[MongoCollection[Document], (Int, Sink[Document, Future[Done]])] = Map(
  collection0 -> (0 -> MongoSink.insertOne(collection0)),
  collection1 -> (1 -> MongoSink.insertOne(collection1)),
  collection2 -> (2 -> MongoSink.insertOne(collection2)),
  collection3 -> (3 -> MongoSink.insertOne(collection3))
)

val combinedSink = Sink.fromGraph(GraphDSL.create() { implicit builder =>
  import GraphDSL.Implicits._

  val partition = builder.add(
    Partition[Message](
      collections.size,
      { msg => collections(collection(msg.id))._1 }
    )
  )

  val toDocument = Flow[Message].map(documentFromMessage)

  collections.foreach {
    case (_, (n, sink)) =>
      partition.out(n) ~> toDocument ~> sink
  }

  SinkShape.of(partition.in)
}

暫無
暫無

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

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