SparkSQL优化分析--saveAsTable

环境 spark2.4.8 on yarn(hadoop2.4.5)

优化后

package com.bl.bigdata.cdp.execservice.service.batch.schedule.common

import com.bl.bigdata.cdp.execservice._
import com.bl.bigdata.cdp.execservice.utils.business.TableUtils
import com.bl.bigdata.cdp.execservice.utils.third.{DateUtil, Slf4jLogger}
import org.apache.spark.sql.functions.rand
import org.apache.spark.sql.{SaveMode, SparkSession}

object StoreUserLabels extends Slf4jLogger {

  def main(args: Array[String]): Unit = {
    val sparkConf = getSparkConf()
    implicit val spark: SparkSession = createSparkSession(sparkConf)

    buildStoreLabel

    spark.stop()
  }

  private def buildStoreLabel()(implicit spark: SparkSession) = {
    import spark.{sql, table}
    import spark.implicits._

    val latestDate = DateUtil.getCurrentDate()

    sql(
      s"""
         |SELECT member_id id, label, store_id
         |FROM (
         |SELECT member_id member_id, tagdetailid2 label, storelabel2 store_id FROM userlibrary.cdp_purchase_1 WHERE cdate='$latestDate' AND tagstorelabel3 IS NOT NULL AND storelabel2 IS NOT NULL
         |UNION ALL
         |SELECT member_id member_id, tagdetailid2 label, storelabel2 store_id FROM userlibrary.cdp_purchase_2 WHERE cdate='$latestDate' AND tagstorelabel3 IS NOT NULL AND storelabel2 IS NOT NULL
         |UNION ALL
         |SELECT member_id member_id, tagdetailid2 label, storelabel2 store_id FROM userlibrary.cdp_purchase_3 WHERE cdate='$latestDate' AND tagstorelabel3 IS NOT NULL AND storelabel2 IS NOT NULL
         |UNION ALL
         |SELECT member_id member_id, tagdetailid2 label, storelabel2 store_id FROM userlibrary.cdp_population WHERE cdate='$latestDate' AND tagdetailid2 IS NOT NULL AND storelabel2 IS NOT NULL
         |UNION ALL
         |SELECT member_id id, tagdetailid2 label, 's50' store_id FROM userlibrary.cdp_ubt WHERE cdate='$latestDate'
         |) t
         |GROUP BY store_id, member_id, label
         |""".stripMargin).
      repartition($"store_id", $"id").
      createOrReplaceTempView("tv_store_user_label")

    sql(
      """
        |SELECT id, label, -1 value, store_id
        |FROM tv_store_user_label
        |""".stripMargin).
      groupBy("store_id", "id").
      pivot("label").
      max("value").repartition($"store_id", rand).
      createOrReplaceTempView("tv_user_labels")

    sql(
      """
        |SELECT member_id id, black_flag
        |FROM procdata.cdp_member_info
        |WHERE black_flag='1'
        |""".stripMargin).
      createOrReplaceTempView("tv_user_black_flag")

    sql(
      """
        |SELECT /*+ BROADCAST(b) */  IF(black_flag IS NULL,0, CAST(black_flag AS INT)) AS black_flag,  u.*
        |FROM tv_user_labels u
        |LEFT JOIN tv_user_black_flag b
        |ON u.id=b.id
        |""".stripMargin).
      createOrReplaceTempView("store_user_labels_black_flag")

    sql(s"DROP TABLE IF EXISTS test.store_user_labels_tmp")

    table("store_user_labels_black_flag").
      where("1=2").
      write.
      partitionBy("store_id").
      saveAsTable("test.store_user_labels_tmp")

    table("store_user_labels_black_flag").
      // coalesce(69).
      repartition(69, $"store_id", rand).
      write.
      mode(SaveMode.Overwrite).
      partitionBy("store_id").
      parquet("/user/hive/warehouse/test.db/store_user_labels_tmp")

    spark.sql("MSCK REPAIR TABLE test.store_user_labels_tmp")

    TableUtils.renameAndRetainPhysicsTable("test.store_user_labels_tmp", "test.store_user_labels")
  }
}

/*
export SPARK_HOME=/opt/spark-2.4.8-212

$SPARK_HOME/bin/spark-submit --master yarn --deploy-mode cluster \
--class com.bl.bigdata.cdp.execservice.service.batch.schedule.common.StoreUserLabels8 \
--name cdp_StoreUserLabels_wsw6 --executor-cores 6 --executor-memory 33g --driver-memory 26g --conf spark.driver.maxResultSize=25g \
--conf spark.sql.pivotMaxValues=2900 \
--conf spark.network.timeout=3600 --conf spark.executor.heartbeatInterval=10000 \
--conf spark.sql.shuffle.partitions=248 \
--conf spark.default.parallelism=248 \
--conf spark.dynamicAllocation.enabled=true --conf spark.shuffle.service.enabled=true \
--conf spark.dynamicAllocation.minExecutors=3 --conf spark.dynamicAllocation.maxExecutors=16 \
--conf spark.dynamicAllocation.initialExecutors=9 \
--conf spark.shuffle.memoryFraction=0.4 \
~/sven/cdpsupport.jar

问题点:

1 shuffle时大量数据
2 数据倾斜严重

优化点:

1 增加并行执行数量
2 修改动态资源提交
3 增加shuffle聚合内存
4 saveAsTable功能优化
5 join操作改为left join操作,但这个left join实际是broadcast
6 合并操作减少stage
7 repartition 操作修改为coalesce
8 适当进行干预,尽量防止数据倾斜
9 减少shuffle聚合操作后数据溢写到磁盘

参考:

6) spark.default.parallelism
参数说明:该参数用于设置每个stage的默认task数量。这个参数极为重要,如果不设置可能会直接影响你的Spark作业性能。

参数调优建议:如果不设置这个参数, Spark自己根据底层HDFS的block数量来设置task的数量,默认是一个HDFS block对应一个task。Spark官网建议的设置原则是,设置该参数为num-executors * executor-cores的2~3倍较为合适,此时可以充分地利用Spark集群的资源。针对数据交换的场景,建议此参数设置为1-10。

7) spark.storage.memoryFraction
参数说明:该参数用于设置RDD持久化数据在Executor内存中能占的比例,默认是0.6。也就是说,默认Executor 60%的内存,可以用来保存持久化的RDD数据。根据你选择的不同的持久化策略,如果内存不够时,可能数据就不会持久化,或者数据会写入磁盘。

参数调优建议:如果Spark作业中,有较多的RDD持久化操作,该参数的值可以适当提高一些,保证持久化的数据能够容纳在内存中。避免内存不够缓存所有的数据,导致数据只能写入磁盘中,降低了性能。但是如果Spark作业中的shuffle类操作比较多,而持久化操作比较少,那么这个参数的值适当降低一些比较合适。如果发现作业由于频繁的gc导致运行缓慢(通过spark web ui可以观察到作业的gc耗时),意味着task执行用户代码的内存不够用,那么同样建议调低这个参数的值。针对数据交换的场景,建议降低此参数值到0.2-0.4。

8) spark.shuffle.memoryFraction
参数说明:该参数用于设置shuffle过程中一个task拉取到上个stage的task的输出后,进行聚合操作时能够使用的Executor内存的比例,默认是0.2。也就是说,Executor默认只有20%的内存用来进行该操作。shuffle操作在进行聚合时,如果发现使用的内存超出了这个20%的限制,那么多余的数据就会溢写到磁盘文件中去,此时就会极大地降低性能。

参数调优建议:如果Spark作业中的RDD持久化操作较少,shuffle操作较多时,建议降低持久化操作的内存占比,提高shuffle操作的内存占比比例,避免shuffle过程中数据过多时内存不够用,必须溢写到磁盘上,降低了性能。如果发现作业由于频繁的gc导致运行缓慢,意味着task执行用户代码的内存不够用,那么同样建议调低这个参数的值。针对数据交换的场景,建议此值设置为0.1或以下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大怀特

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值