在火花流中重放RDD以更新累加器

时间:2015-12-10 17:28:03

标签: apache-spark spark-streaming

我实际上用完了选项。 在我的火花流应用程序中。我想在某些键上保持状态。我正在接受卡夫卡的活动。然后我从事件中提取密钥,比如userID。当没有来自Kafka的事件时,我想每隔3秒更新一个相对于每个用户ID的计数器,因为我将StreamingContext的批量配置为3秒。

现在我这样做的方式可能很难看,但至少它有效:我有一个像这样的accumulableCollection:

val userID = ssc.sparkContext.accumulableCollection(new mutable.HashMap[String,Long]())

然后我创建了一个“假”事件并继续将其推送到我的火花流式上下文中,如下所示:

val rddQueue = new mutable.SynchronizedQueue[RDD[String]]()
for ( i <- 1 to  100) {
  rddQueue += ssc.sparkContext.makeRDD(Seq("FAKE_MESSAGE"))
  Thread.sleep(3000)
}
val inputStream = ssc.queueStream(rddQueue)

inputStream.foreachRDD( UPDATE_MY_ACCUMULATOR )

这将让我访问我的accumulatorCollection并更新所有userID的所有计数器。到目前为止一切正常,但是当我改变我的循环时:

for ( i <- 1 to  100) {} #This is for test

要:

while (true) {} #This is to let me access and update my accumulator through the whole application life cycle

然后当我运行我的./spark-submit时,我的应用程序就会陷入这个阶段:

15/12/10 18:09:00 INFO BlockManagerMasterActor: Registering block manager slave1.cluster.example:38959 with 1060.3 MB RAM, BlockManagerId(1, slave1.cluster.example, 38959)

有关如何解决此问题的任何线索?是否有一种非常简单的方法可以让我更新我的userID的值(而不是创建一个无用的RDD并定期将其推送到队列流中)?

1 个答案:

答案 0 :(得分:3)

while (true) ...版本不起作用的原因是控件永远不会返回到主执行行,因此该行以下的任何内容都不会被执行。要解决该特定问题,我们应该在单独的线程中执行while循环。 Future { while () ...}应该可行。 此外,不需要在上面的示例中填充Thread.sleep(3000)QueueDStream。 Spark Streaming将在每个流间隔消耗来自队列的一条消息。

触发'tick'消息流入的更好方法是使用ConstantInputDStream在每个流间隔播放相同的RDD,因此无需使用{{1}创建RDD流入}。

那就是说,在我看来,目前的做法似乎很脆弱,需要修改。