SparkSQL常用性能優化

一、代碼優化

1.在數據統計的時候選擇高性能算子。

例如Dataframe使用foreachPartitions將數據寫入數據庫,不要每個record都去拿一次數據庫連接。通常寫法是每個partition拿一次數據庫連接。

      /**
        * 將統計結果寫入MySQL中
        * 代碼優化:
        * 在進行數據庫操作的時候,不要每個record都去操作一次數據庫
        * 通常寫法是每個partition操作一次數據庫
        **/
      try {
        videoLogTopNDF.foreachPartition(partitionOfRecords => {
          val list = new ListBuffer[DayVideoAccessStat]
          partitionOfRecords.foreach(info => {
            val day = info.getAs[String]("day")
            val cmsId = info.getAs[Long]("cmsId")
            val times = info.getAs[Long]("times")

            list.append(DayVideoAccessStat(day, cmsId, times))
          })
          StatDao.insertDayVideoTopN(list)
        })
      }catch{
        case e:Exception =>e.printStackTrace()
      }
2.寫數據庫的時候,關閉自動提交,不要每條提交一次,自己手動每個批次提交一次。

 var connection:Connection = null
    var pstmt : PreparedStatement = null
    try{
      connection = MySQLUtils.getConnection()

      connection.setAutoCommit(false)//關閉自動提交
      val sql = "insert into day_video_access_topn_stat(day,cms_id,times) values(?,?,?)"
      pstmt = connection.prepareStatement(sql)

      for(ele <- list){
        pstmt.setString(1,ele.day)
        pstmt.setLong(2,ele.cmsId)
        pstmt.setLong(3,ele.times)
        //加入到批次中,後續再執行批量處理 這樣性能會好很多
        pstmt.addBatch()
      }
      //執行批量處理
      pstmt.executeBatch()

      connection.commit() //手工提交

    }catch {
      case e :Exception =>e.printStackTrace()
    }finally {
      MySQLUtils.release(connection,pstmt)
    }
3.複用已有的數據。

三個統計方法都是隻要當天的視頻數據,所以在調用方法前過濾出當天視頻數據,緩存到內存中。

然後傳到三個統計方法中使用。

不要在每個統計方法都去做一次相同的過濾。

val logDF = spark.read.format("parquet")
      .load("file:///F:\\mc\\SparkSQL\\data\\afterclean")
    val day = "20170511"


    /**
      * 代碼優化:複用已有數據
      * 既然每次統計都是統計的當天的視頻,
      * 先把該數據拿出來,然後直接傳到每個具體的統計方法中
      * 不要在每個具體的統計方法中都執行一次同樣的過濾
      *
      * 用$列名得到列值,需要隱式轉換 import spark.implicits._
      * */
    import spark.implicits._
    val dayVideoDF = logDF.filter($"day" ===day&&$"cmsType"==="video")
    /**
      * 將這個在後文中會複用多次的dataframe緩存到內存中
      * 這樣後文在複用的時候會快很多
      *
      * default storage level (`MEMORY_AND_DISK`).
      * */
    dayVideoDF.cache()

    //logDF.printSchema()
    //logDF.show()

    StatDao.deletaDataByDay(day)

    //統計每天最受歡迎(訪問次數)的TopN視頻產品
    videoAccessTopNStatDFAPI(spark,dayVideoDF)

    //按照地勢統計每天最受歡迎(訪問次數)TopN視頻產品 每個地市只要最後歡迎的前三個
    cityAccessTopNStat(spark,dayVideoDF)

    //統計每天最受歡迎(流量)TopN視頻產品
    videoTrafficsTopNStat(spark,dayVideoDF)

    //清除緩存
    dayVideoDF.unpersist(true)
二、集羣存儲格式選擇

    列式/行式存儲簡介

這裏建議選擇用parquet格式,之前公司中用的也是這種格式。

三、集羣壓縮格式選擇

Hadoop壓縮實現分析

Spark中選擇用哪個方式壓縮文件

SparkSession.builder().config("spark.sql.parquet.compression.codec",snappy).getOrCreate()默認是snappy。

四、參數優化

1.並行度:spark.sql.shuffle.partitions

一個partitions相當於一個task。這是配置當shuffle數據去join或者聚合的時候的partitions的數量。200一般情況下在生產上是不夠的,需要做相應的調整。

調整並行度的方式

bin/spark-submit --class XXX.XXX.XX --name XXX --master local[2] --conf spark.sql.shuffle.partitions=230 XXX.jar

2.不必要的情況下,關閉分區字段類型自動推導

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章