Scala 为什么每个Spark任务都没有使用所有分配的内核?
假设每个执行器有36个核心,每个节点有一个执行器,3个节点有48个可用核心。我注意到的基本要点是,当我将每个任务设置为使用1个内核(默认值)时,我对workers的CPU利用率约为70%,每个执行器将同时执行36个任务(如我所料)。但是,当我将配置更改为每个任务有6个内核(Scala 为什么每个Spark任务都没有使用所有分配的内核?,scala,performance,apache-spark,concurrency,spark-dataframe,Scala,Performance,Apache Spark,Concurrency,Spark Dataframe,假设每个执行器有36个核心,每个节点有一个执行器,3个节点有48个可用核心。我注意到的基本要点是,当我将每个任务设置为使用1个内核(默认值)时,我对workers的CPU利用率约为70%,每个执行器将同时执行36个任务(如我所料)。但是,当我将配置更改为每个任务有6个内核(--conf spark.task.cpus=6)时,每个执行器一次可以减少到6个任务(正如预期的那样),但是我的CPU利用率也会下降到10%以下(出乎意料)。我假设Spark知道如何在6核上并行化工作负载 重要的实现细节是,
--conf spark.task.cpus=6
)时,每个执行器一次可以减少到6个任务(正如预期的那样),但是我的CPU利用率也会下降到10%以下(出乎意料)。我假设Spark知道如何在6核上并行化工作负载
重要的实现细节是,我在DataFrame
的一列上运行一个UDF函数,并将结果作为新列附加到该DataFrame上。这个UDF函数使用一个@transient
对象,它提供了我正在使用的机器学习算法。此UDF函数不是聚合或合并操作的一部分,它只是对列执行的map
操作,如下所示:
def myUdf = udf { ... }
val resultSet = myUdf(dataFrame.col("originalCol"))
val dataFrameWithResults = dataFrame.withColumn("originalColMetric", resultSet)
我本以为Spark会执行6myUdf
,一次处理6条记录,每个核心一条,但事实似乎并非如此。有没有办法解决这个问题(不向Spark项目提交PR),或者至少有人能解释为什么会发生这种情况
考虑到这个问题,我正在尝试增加每个任务的内核数量,以减少每个执行器所需的RAM数量。在本例中,一次执行太多任务会以指数方式增加RAM的使用量。spark.task.cpu是为每个任务分配的多个内核。当用户代码为多线程时,它用于将多个内核分配给单个任务。如果您的
udf
没有使用多个线程(不会在一个函数调用中产生多个线程),那么内核就被浪费了
一次处理6条记录
分配6个内核,spark.task.cpu
设置为1。如果要限制节点上的任务数,请减少每个节点提供的核心数
实际上,Spark可以通过在每个任务之间分割记录(根据分区)并确定每个执行者可以同时处理多少个任务,自行决定如何在多个记录上同时分割映射UDF。但是,Spark不能自动将每个核心的工作分配给每个任务。要在每个任务中使用多个核,需要编写UDF中的代码(每个任务一次(顺序)在一条记录上执行),以便在单个记录上并行该UDF中的计算。另一个选项是转换为RDD并使用
mapPartitions
,然后将包含任务/分区项的集合转换为并行集合,并将转换映射到并行集合中的每个项。