我有一个Spark流应用程序,它使用了很多状态转换。回想起来,Spark可能不是最佳选择,但我仍然试图让它发挥作用。
我的问题是为什么我的MapWithStateRDD占用了这么多内存?作为一个例子,我有一个转换,其中状态大约是1.5 Gb的内存,我看到每个批次都恢复相同的RDD。因此,在第3批之后,它在UI上显示有3个具有完全相同大小的MapWithStateRDD,而状态在这些批次中没有变化。这些实际占用了3倍的空间吗?这似乎是一个巨大的浪费,它不应该只存储增量直到一个检查点,然后将它们压缩到一个RDD或类似的东西?我认为它是如何工作的,并且进行更多有状态转换会占用大量内存。
答案 0 :(得分:0)
正如注释链接中所指出的那样,这是因为mapWithState每10个批次后都会检查一次数据,因此它将RDD保留到该点为止。
要消除这种空间浪费,您可以选择在每个批次中检查状态。就我而言,这并不是很昂贵。
JavaInputDStream<ConsumerRecord<String, Object>> rtStream = ...
JavaMapWithStateDStream<String, Object, Object, Tuple2<String, Object>> mapWithStateSTream = rtStream .mapToPair(..).mapWithState(...);
mapWithStateSTream.checkpoint(Durations.seconds(10)); //keep this same as your batch interval, or feel free to change acc to your requirement
mapWithStateSTream.forEachRdd(...your logic here..);
然后你去了,魔术!您不会再在“存储”标签中看到那些令人讨厌的MapWithStateRDD。