使用reactive-kafka有条件地处理消息

时间:2018-02-15 22:16:09

标签: scala apache-kafka akka akka-stream akka-kafka

我一直在尝试使用被动式kafka,我遇到条件处理问题,我没有找到令人满意的答案。

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

我的第一次尝试是:

// 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

这个解决方案显然不是很好,因为我可以处理的消息通过图的第二个分支并在可处理消息被真正推送到目的地之前得到提交,这比第一个更糟糕消息,因为它甚至不保证至少一次交付。

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

1 个答案:

答案 0 :(得分:1)

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

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

in ~> broadcast ~> isProcessable ~> process ~> producer ~> merge ~> out
   ~> broadcast ~>            isNotProcessable          ~> merge

然后将其包装成一个保存流程的订单(取自我们公司开发的库):OrderPreservingFlow。然后可以将生成的流发送到提交器接收器。

如果您的处理阶段保证订购,您甚至可以通过直接在图表中嵌入逻辑来提高效率并避免任何缓冲:

in ~> injectSeqNr ~> broadcast ~> isProcessable ~> process ~> producer ~> mergeNextSeqNr ~> commit
                  ~> broadcast ~>             isNotProcessable         ~> mergeNextSeqNr

这里你的mergeNextSeqNr只是一个修改过的合并阶段,如果输入在端口1上可用,如果它的序列号是预期的,你立即发出它,否则你只是等待数据在另一个端口上可用。

最终结果应与使用上面的流程包装完全相同,但如果嵌入它,您可能更容易根据需要调整它。