我实际上用完了选项。 在我的火花流应用程序中。我想在某些键上保持状态。我正在接受卡夫卡的活动。然后我从事件中提取密钥,比如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并定期将其推送到队列流中)?
答案 0 :(得分:3)
while (true) ...
版本不起作用的原因是控件永远不会返回到主执行行,因此该行以下的任何内容都不会被执行。要解决该特定问题,我们应该在单独的线程中执行while
循环。 Future { while () ...}
应该可行。
此外,不需要在上面的示例中填充Thread.sleep(3000)
时QueueDStream
。 Spark Streaming将在每个流间隔消耗来自队列的一条消息。
触发'tick'消息流入的更好方法是使用ConstantInputDStream在每个流间隔播放相同的RDD,因此无需使用{{1}创建RDD流入}。
那就是说,在我看来,目前的做法似乎很脆弱,需要修改。