为什么每个Spark任务都没有使用所有分配的核心?

时间:2018-01-04 22:26:28

标签: scala performance apache-spark concurrency spark-dataframe

假设每个执行器有36个核心,每个节点有一个执行器,3个节点,每个节点有48个核心可用。我注意到的基本要点是,当我将每个任务设置为使用1个核心(默认值)时,我对工作人员的CPU利用率约为70%,每个执行者将同时执行36个任务(正如我所希望的那样)预期)。但是,当我将配置更改为每个任务有6个核心(--conf spark.task.cpus=6)时,每个执行程序(按预期方式)一次下降到6个任务,但我的CPU利用率也降至10%以下(意外) )。我原以为Spark会知道如何在6个核心上并行化工作负载。

重要的实现细节是我在DataFrame的列上运行UDF函数,并将结果作为新数据列附加到该数据帧上。此UDF函数使用@transient对象,该对象提供我正在使用的机器学习算法。此UDF函数不是聚合或合并操作的一部分,它只是对列实现的map操作,如下所示:

def myUdf = udf { ... }

val resultSet = myUdf(dataFrame.col("originalCol"))
val dataFrameWithResults = dataFrame.withColumn("originalColMetric", resultSet)

我原本预计Spark会执行6 myUdf一次处理6条记录,每个核心一条记录,但事实并非如此。有没有办法解决这个问题(没有向Spark项目提交PR),或者至少有人可以解释为什么会发生这种情况?

预见到这个问题,我尝试增加每个任务的核心数量,以减少每个执行程序所需的RAM量。在这种情况下,一次执行太多任务会以指数方式增加RAM使用率。

1 个答案:

答案 0 :(得分:1)

spark.task.cpus是为每个任务分配的个核心。在用户代码是多线程的情况下,它用于为单个任务分配多个核心。如果你的udf没有使用多个(不会在单个函数调用中产生多个线程)线程,那么核心就会被浪费掉。

  

一次处理6条记录

分配6个核心,spark.task.cpus设置为1.如果要限制节点上的任务数,请减少每个节点提供的核心数。

基本上,Spark可以通过在每个任务(根据分区)之间拆分记录并确定每个Executor可以处理多少个并发任务来自行确定如何分离出多个记录上的UDF映射。但是,Spark无法自动拆分每个Core每个任务的工作量。为了在每个任务中使用多个核心,需要编写UDF中的代码(每个任务一次(按顺序)执行一条记录),以便在单个记录中并行化该UDF中的计算。