假设每个执行器有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使用率。
答案 0 :(得分:1)
spark.task.cpus
是为每个任务分配的个核心。在用户代码是多线程的情况下,它用于为单个任务分配多个核心。如果你的udf
没有使用多个(不会在单个函数调用中产生多个线程)线程,那么核心就会被浪费掉。
一次处理6条记录
分配6个核心,spark.task.cpus
设置为1.如果要限制节点上的任务数,请减少每个节点提供的核心数。
基本上,Spark可以通过在每个任务(根据分区)之间拆分记录并确定每个Executor可以处理多少个并发任务来自行确定如何分离出多个记录上的UDF映射。但是,Spark无法自动拆分每个Core每个任务的工作量。为了在每个任务中使用多个核心,需要编写UDF中的代码(每个任务一次(按顺序)执行一条记录),以便在单个记录中并行化该UDF中的计算。