Scala 使用反应式卡夫卡有条件地处理消息

Scala 使用反应式卡夫卡有条件地处理消息,scala,apache-kafka,akka,akka-stream,akka-kafka,Scala,Apache Kafka,Akka,Akka Stream,Akka Kafka,我一直在尝试使用反应式卡夫卡,但我在条件处理方面遇到了问题,我没有找到令人满意的答案 基本上,我正在尝试使用一个卡夫卡主题,其中包含大量的消息(每天大约100亿条消息),并且仅根据消息的某些属性处理其中的几条消息(每天数千条),然后将处理后的消息推送到另一个主题,我正在努力正确地做到这一点 我的第一次尝试是: // This is pseudo code. Source(ProducerSettings(...)) .filter(isProcessable(_)) .map(p

我一直在尝试使用反应式卡夫卡,但我在条件处理方面遇到了问题,我没有找到令人满意的答案

基本上,我正在尝试使用一个卡夫卡主题,其中包含大量的消息(每天大约100亿条消息),并且仅根据消息的某些属性处理其中的几条消息(每天数千条),然后将处理后的消息推送到另一个主题,我正在努力正确地做到这一点

我的第一次尝试是:

// This is pseudo code.
Source(ProducerSettings(...))
    .filter(isProcessable(_))
    .map(process(_))
    .via(Producer.flow(producerSettings))
    .map(_.commitScalaDsl())
    .runWith(Sink.ignore)
这种方法的问题是,我只在阅读我能够处理的消息时才提交,这显然是不酷的,因为如果我必须停止并重新启动我的程序,那么我就必须重新阅读一堆无用的消息,因为它们太多了,我负担不起这样做

然后,我尝试使用GraphDSL,方法是围绕以下几行进行操作:

in ~> broadcast ~> isProcessable    ~> process ~> producer ~> merge ~> commit
   ~> broadcast ~>              isNotProcessable           ~> merge
这种解决方案显然也不好,因为我无法处理的消息会经过图的第二个分支,并在可处理消息真正推送到目的地之前提交,这比第一条消息更糟糕,因为它甚至不能保证至少一次传递


有人知道我如何解决这个问题吗?

我以前解决类似问题的方法是利用序列号来保证排序

例如,您可以构建一个类似于您描述的保存提交的流:

in ~> broadcast ~> isProcessable ~> process ~> producer ~> merge ~> out
   ~> broadcast ~>            isNotProcessable          ~> merge
然后将其包装成这样一个保持顺序的流(取自我们公司开发的库):。然后,生成的流可以发送到提交器接收器

如果您的处理阶段保证了排序,您甚至可以通过将逻辑直接嵌入到图形中来提高效率并避免任何缓冲:

in ~> injectSeqNr ~> broadcast ~> isProcessable ~> process ~> producer ~> mergeNextSeqNr ~> commit
                  ~> broadcast ~>             isNotProcessable         ~> mergeNextSeqNr
在这里,您的mergeNextSeqNr只是一个修改的合并阶段,如果端口1上有可用的输入,那么如果其序列号是预期的,您将立即发出它,否则您只需等待另一个端口上有可用的数据


最终结果应该与使用上面的流包装完全相同,但是如果嵌入它,您可能会更容易地使其适应您的需要。

实际上,我刚刚做了一个尝试,并意识到GraphDSL解决方案并不存在问题。当至少有一个out分支背压时,这意味着在前一个元素离开图形并提交之前没有新元素被广播,因此没有排序问题。我更新了我的原型,并意识到由于生产者是异步的,来自广播连接的背压不起作用。谢谢你的想法。