我正在尝试在约150万个条目的mapToPair
上运行javaPairRDD
函数。在通话之外,我有一个本地定义的Java Map
。如果我访问Map
函数中的mapToPair
,则程序内存不足。如果我没有访问Map
,那么即使我在代码的主循环中访问该映射,它也会成功执行。对为什么会发生这种情况有任何想法吗?我的假设是,访问匿名函数内的Map
会导致Spark重复很多次。
我以16个线程在本地模式下运行Spark。对于从16到4000个数据分区的任何内容,都会出现此问题。
代码示例:
工作代码:
JavaPairRDD<Integer, CustomObject> pairRDD = createRDD();
while(loop_condition = true) {
Map<Integer, CustomObject> bigLocalMap = createMap();
System.out.println(bigLocalMap.size());
pairRDD = pairRDD.mapToPair(pair -> {
return pair;
}
}
无效代码
JavaPairRDD<Integer, CustomObject> pairRDD = createRDD();
while(loop_condition = true) {
Map<Integer, CustomObject> bigLocalMap = createMap();
pairRDD = pairRDD.mapToPair(pair -> {
System.out.println(bigLocalMap.size());
return pair;
}
}
答案 0 :(得分:0)
bigLocalMap
有多大?引用它(通过闭包)的方式要求将其序列化并发送给每个内核的每个执行器。相反,您应该将其作为广播变量传递。
通常的想法是,您可以在所有执行器上注册希望访问的数据,而spark将确保有效地传输数据,并且每个执行器仅存储一次。如果您将执行程序配置为具有多个核心,则使用闭包方法最终将导致重复。
参考: https://spark.apache.org/docs/latest/rdd-programming-guide.html#broadcast-variables
如果您仍然没有足够的内存,我将查看您的内存设置。一些解决这个问题的候选人将是:
spark.default.parallelism
和spark.sql.shuffle.partitions
(仅在第一次改组后才生效)或通过显式调用重新分区来增加分区数。较小的任务将减少内存压力。spark.executor.memory
设置增加为执行者提供的RAM数量