减少Spark聚合中的随机磁盘使用量

时间:2017-11-07 13:10:41

标签: scala apache-spark apache-spark-sql

我在hive中有一个100 GB大小的表。我试图分组,计数功能和存储结果作为蜂巢表...我的硬盘有600 GB的空间,到时间工作达到70%所有的磁盘空间都被占用。

所以我的工作失败了...我怎样才能最小化shuffle数据写入

hiveCtx.sql("select * from gm.final_orc")
  .repartition(300)
  .groupBy('col1, 'col2).count
  .orderBy('count desc)
  .write.saveAsTable("gm.result")

spark_memory

1 个答案:

答案 0 :(得分:0)

在基于云的执行环境中,添加更多磁盘通常是一种非常简单且便宜的选择。如果您的环境不允许这样,并且您已经验证了shuffles settings是合理的,例如,压缩(默认情况下已启用)未更改,那么只有一个解决方案:实施您自己的分阶段map-reduce使用可以通过sum重新汇总计数的事实。

  1. 以任何看似合适的方式对数据进行分区(按日期,按目录,按文件数等)。
  2. col1col2执行计数,作为单独的Spark操作。
  3. 重新分组并重新聚合。
  4. 排序。
  5. 为简单起见,我们假设col1是一个整数。以下是我如何将处理分解为8个单独的作业,重新聚合其输出。如果col1不是整数,您可以对其进行哈希处理,也可以使用其他列。

    def splitTableName(i: Int) = s"tmp.gm.result.part-$i"
    
    // Source data
    val df = hiveCtx.sql("select col1, col2 from gm.final_orc")
    
    // Number of splits
    val splits = 8
    
    // Materialize partial aggregations
    val tables = for {
      i <- 0 until splits
      tableName = splitTableName(i)
      // If col1 % splits will create very skewed data, hash it first, e.g.,
      // hash(col1) % splits. hash() uses Murmur3.
      _ = df.filter('col1 % splits === i)
        // repartition only if you need to, e.g., massive partitions are causing OOM
        // better to increase the number of splits and/or hash to un-skew skewed data
        .groupBy('col1, 'col2).count
        .write.saveAsTable(tableName)
    } yield hiveCtx.table(tableName)
    
    // Final aggregation
    tables.reduce(_ union _)
      .groupBy('col1, 'col2)
      .agg(sum('count).as("count"))
      .orderBy('count.desc)
      .write.saveAsTable("gm.result")
    
    // Cleanup temporary tables
    (0 until splits).foreach { i =>
      hiveCtx.sql(s"drop table ${splitTableName(i)}")
    }
    

    如果col1col2如此多样化和/或大到部分聚合存储导致磁盘空间问题,那么您必须考虑以下其中一项:

    • 较小的分割数通常会占用较少的磁盘空间。

    • col1进行排序会有所帮助(因为Parquet运行长度编码),但这会降低执行速度。

    • 如何创建独立的拆分,例如,查找col1的不同值,将其划分为组。

    如果您的磁盘空间极短,则必须实施多步重新聚合。最简单的方法是一次生成一个拆分并保持运行的聚合。执行速度会慢很多,但会占用更少的磁盘空间。

    希望这有帮助!