Spark数据帧saveAsTable使用单个任务

时间:2016-01-12 00:40:11

标签: scala apache-spark

我们有一个管道,初始阶段可以适当扩展 - 每个人使用几十个工人。

最后阶段之一是

dataFrame.write.format(outFormat).mode(saveMode).
partitionBy(partColVals.map(_._1): _*).saveAsTable(tname)

在这个阶段,我们最终得到了一个单个工作者。这显然不适用于我们 - 实际上工作人员耗尽了磁盘空间 - 而且非常慢。

enter image description here

为什么该命令最终仅在单个worker / single任务上运行?

更新输出格式为parquet。分区列的数量不会影响结果(尝试了一列和多列)。

以下条件的另一次更新 (如下面的答案所示):

  • coalescepartitionBy语句
  • window / analytic functions
  • Dataset.limit
  • sql.shuffle.partitions

1 个答案:

答案 0 :(得分:1)

该问题不太可能与saveAsTable有关。

阶段中的单个任务表示输入数据(DatasetRDD)只有一个分区。这与存在多个任务但一个或多个任务具有明显更高的执行时间(通常对应于包含正偏键的分区)的情况形成对比。另外,您应该混淆CPU利用率低的单个任务方案。前者通常是由于IO吞吐量不足(CPU等待时间较长是最明显的迹象)的结果,但是在极少数情况下,可以追溯到使用具有低级同步原语的共享对象。

由于标准数据源在写入时不会对数据进行混洗(包括使用partitionBybucketBy选项的情况),因此可以安全地假设数据已在上游代码中重新分区。通常,这意味着发生以下情况之一:

  • 已使用coalesce(1)repartition(1)将数据显式移动到单个分区。
  • 数据已隐式移动到单个分区,例如:

    • Dataset.limit
    • 具有缺少PARTITION BY子句的窗口定义的窗口函数应用程序。

      df.withColumn(
        "row_number", 
        row_number().over(Window.orderBy("some_column"))
      )
      
    • sql.shuffle.partitions选项设置为1,并且上游代码包括对Dataset的非本地操作。

    • Dataset是应用全局聚合函数(无GROUP BY盲注)的结果。除非函数是非归约的(collect_list或类似的),否则通常这不是问题。

虽然没有证据表明这是问题所在,但在一般情况下,您也应该可能,数据仅包含单个分区,一直到源为止。通常在提取using JDBC source时输入,但是第三方格式可以表现出相同的行为。

要确定问题的根源,您应该检查输入Datasetexplain(true))的执行计划,或者检查Spark Web UI的SQL选项卡。