本地Java数据结构在Spark Map调用中导致OOM错误

时间:2018-06-21 15:23:19

标签: apache-spark

我正在尝试在约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;
    }
}

1 个答案:

答案 0 :(得分:0)

bigLocalMap有多大?引用它(通过闭包)的方式要求将其序列化并发送给每个内核的每个执行器。相反,您应该将其作为广播变量传递。

通常的想法是,您可以在所有执行器上注册希望访问的数据,而spark将确保有效地传输数据,并且每个执行器仅存储一次。如果您将执行程序配置为具有多个核心,则使用闭包方法最终将导致重复。

参考: https://spark.apache.org/docs/latest/rdd-programming-guide.html#broadcast-variables

如果您仍然没有足够的内存,我将查看您的内存设置。一些解决这个问题的候选人将是:

  • 减少每个执行器的内核数(减少使用内存的同时任务)
  • 通过设置spark.default.parallelismspark.sql.shuffle.partitions(仅在第一次改组后才生效)或通过显式调用重新分区来增加分区数。较小的任务将减少内存压力。
  • 如果您有足够的资源,请通过spark.executor.memory设置增加为执行者提供的RAM数量