Spark转换的执行顺序似乎是任意的。
我们有2个RDD,其中包含我们分类的相关事件。多个分类器应用于rdd1,但是为了简洁起见,我仅描述发生问题的部分。
伪代码类似于:
total_count = rdd1.size
// filter1
(organics, duplicates) = Deduplicate rdd1 events (classify events as organic and duplicates)
duplicates.persist(DISK_ONLY)
rdd1 = organics
if (specific_client) {
// filter2
Load rdd2 Events
Join rdd1 and rdd2
(organics, invalid) = Classify rdd1 events according to joined information from rdd2
invalid.persist(DISK_ONLY)
}
Check total_count == size(organics + invalid + duplicates) // here it fails
我们遇到的问题是,在某些运行中,通过大小检查会通过,而在某些情况下会失败。查看执行时间表,我们注意到在filter2 之后执行filter1时,它失败。并且当失败时,右手的大小总是大于初始total_count
。
当代码指示filter1的输出是filter2的输入时,为什么Spark会在filter2之后安排filter1的执行?
在filter2之后执行filter1时,为什么所有零件的计数返回的元素数都比装入的要多? (我怀疑是加入通话)
奇怪的是,当我们在单个节点上本地运行代码时,它从未失败。当我们通过Spark shell连接到AWS EMR时,它从未失败。仅当在具有4个工作节点的AWS EMR集群上作为常规Spark作业运行时,该操作才会失败。
论坛建议我们应该以某种方式强制Spark在filter2之前计算filter1。以下操作无效:
organics.persist(MEMORY_ONLY | DISK_ONLY)
organics.cache()
organics.count()
organics.checkpoint()
organics.persist(DISK_ONLY)
其工作方式是在filter1之后调用organics.persist(DISK_ONLY)
,然后调用organics.count
。但是,我们不确定这是否是最佳解决方案,因为它看起来很暴力并且会导致数据混排。
所以总结一下。
persist
+ count
是执行转换顺序的最佳解决方案吗?