如何处理最后,最相关的事件(当延迟增长太快时跳过其他事件)?

时间:2016-01-06 14:41:11

标签: apache-spark apache-kafka spark-streaming

上下文:处理来自Kafka的数据并将结果发送给Kafka。

问题:每个事件可能需要几秒钟才能处理(正在进行中以改进)。在此期间,事件(和RDD)确实累积。不必处理中间事件(按键),只需处理最后的事件。因此,当一个进程完成时,Spark Streaming将跳过所有不是当前最后事件(按键)的事件是理想的。

我不确定解决方案是否只能使用Spark Streaming API完成。据我了解Spark Streaming,DStream RDD将逐个累积并进行处理,如果之后还有其他的则不考虑。

可能的解决方案:

  • 仅使用Spark Streaming API,但我不确定如何使用。 updateStateByKey似乎是一种解决方案。但是我不确定当DStream RDD累积时它会正常工作,你只需按键处理持续事件。

  • 有两个Spark Streaming管道。一个按键获取上次更新的事件,将其存储在地图或数据库中。第二个管道只有在它们是另一个管道指示的最后一个事件时才处理事件。子问题:

    • 两个管道可以共享相同的sparkStreamingContext并以不同的速度处理相同的DStream(低处理与高处理)?

    • 是否可以轻松地在不使用外部数据库的情况下在管道之间共享值(例如地图)?我认为累加器/广播可以工作,但在两个管道之间,我不确定。

1 个答案:

答案 0 :(得分:4)

考虑到流媒体是一个连续的过程,很难定义“最后”在这种情况下的含义。但是,假设您要在给定的时间段内处理最后一个事件,例如每隔10秒运行一次处理,并且在这10秒帧内仅为每个键执行最后一个事件 - 有几种可能的方法。

窗口方法

其中一个选项是在DStream窗口

val windowStream = dStream.window(Seconds(10), Seconds(10))
windowStream.forEachRDD { /* process only latest events */ }

在这种情况下,windowStream将具有RDD,它在过去10秒内组合来自所有RDD的键/值,您可以在forEachRDD中访问所有这些,就像您最初在单个RDD中一样。缺点是它不会提供关于它们如何进入流的事件排序的任何信息,但是你可能有值的事件时间信息或重用Kafka的偏移量

updateStateByKey方法

基本上如你所建议的那样 - 它可以让你积累价值。 Databricks有一个很好的例子来说明如何执行此操作here

虽然他们在示例中积累了,但您可以更新密钥的值而不是

Kafka日志压缩

虽然这不会取代在Spark方面处理它的需要,但如果你将事件保存在Kafka一段时间,你可能会考虑使用Kafka的Log Compaction 它不能保证重复项不会从Kafka进入Spark流,但会通过仅保留日志尾部的最新密钥来减少Kafka中存储事件的数量。