我最近继承了Spark Streaming应用程序的大型重构提交。最初的开发人员告诉我,似乎存在一些隐式缓存,但是他在离开公司之前无法解决问题。
调试代码后,我发现,如果在将另一个RDD加入一个DStream之前将其加入另一个RDD,则火花将不会为每个批次重新获取RDD。
另一方面,如果仅在DStream上加入单个RDD,则spark将每批重新获取RDD数据。
注意:这些RDD是通过对Mysql的jdbc调用填充的。
最初,此问题在Spark 2.1.1中引起了人们的注意。此后,我将应用程序升级到了2.4.3,但这没什么区别。
另外,我尝试使用SparkSql加入RDD,这也没有任何区别。
这将很好地工作:对于每个火花流批处理,都将从数据库中获取entity1DF值。
val wordCounts: DStream[(String, Int)] = ...
val entity1DF = sparkSession.read.format("jdbc").jdbc("jdbc:mysql://127.0.0.1/barebones", "myword", driverProperties)
val entity1Rdd = entity1DF.rdd.map(Word.rowMapper)
val joinedStream = wordCounts.transform(rdd =>
rdd.leftOuterJoin(entity1Rdd)
)
这不起作用:对于每个火花流批处理,从第一个批处理中重新使用entity1DF和entity2DF值。 Spark UI通过将作业显示为灰色来很好地直观显示。
val wordCounts: DStream[(String, Int)] = ...
val entity1DF: DataFrame = sparkSession.read.format("jdbc").jdbc("jdbc:mysql://127.0.0.1/barebones", "myword", driverProperties)
val entity1Rdd: RDD[(String, Int)] = entity1DF.rdd.map(Word.rowMapper)
val entity2DF: DataFrame = sparkSession.read.format("jdbc").jdbc("jdbc:mysql://127.0.0.1/barebones", "myword", driverProperties)
val entity2Rdd: RDD[(String, Int)] = entity2DF.rdd.map(Word.rowMapper)
val joinedRdd: RDD[(String, (Option[Int], Option[Int]))] = entity1Rdd.fullOuterJoin(entity2Rdd)
val joinedStream: DStream[(String, (Int, Option[(Option[Int], Option[Int])]))] = wordCounts.transform(rdd =>
rdd.leftOuterJoin(joinedRdd)
)
我希望每个流批次都重新评估entity1DF和entity2DF值。而不是将它们缓存以备后用。