Spark Core中解決group by造成的數據傾斜問題

        在大數據開發中,我們可能會遇到大數據計算中一個最棘手的問題——數據傾斜,此時Spark作業的性能會比期望差很多。數據傾斜調優,就是使用各種技術方案解決不同類型的數據傾斜問題,以保證Spark作業的性能。該篇博客參考美團的spark高級版,修改了代碼使用了scala寫的。

       這個方案的核心實現思路就是進行兩階段聚合。第一次是局部聚合,先給每個key都打上一個隨機數,比如10以內的隨機數,此時原先一樣的key就變成不一樣的了,比如(hello, 1) (hello, 1) (hello, 1) (hello, 1),就會變成(1_hello, 1) (1_hello, 1) (2_hello, 1) (2_hello, 1)。接着對打上隨機數後的數據,執行reduceByKey等聚合操作,進行局部聚合,那麼局部聚合結果,就會變成了(1_hello, 2) (2_hello, 2)。然後將各個key的前綴給去掉,就會變成(hello,2)(hello,2),再次進行全局聚合操作,就可以得到最終結果了,比如(hello, 4)。

    方案實現原理:將原本相同的key通過附加隨機前綴的方式,變成多個不同的key,就可以讓原本被一個task處理的數據分散到多個task上去做局部聚合,進而解決單個task處理數據量過多的問題。接着去除掉隨機前綴,再次進行全局聚合,就可以得到最終的結果。具體原理見下圖。

package com.qf.bigdata.test

import scala.util.Random
import org.apache.spark.{SparkConf, SparkContext}

/**
  * 測試
  *       spark中groupby 產生的數據傾斜問題
  *
  *       解決方案
  */
object TestGroupBy {
  def main(args: Array[String]): Unit = {
    val conf=new SparkConf().setAppName("Demo").setMaster("local[2]")
    val sc=new SparkContext(conf)

    //準備數據
    val array=new Array[Int](10000)
    for (i <- 0 to 9999){
      array(i)=new Random().nextInt(10)
    }

    //生成一個rdd
    val rdd=sc.parallelize(array)
    //數據量很大就先取樣
    //rdd.sample(false,0.1)

    //所有key加一操作
    val maprdd=rdd.map((_,1))
    //沒有加隨機前綴的結果
    println("沒有加隨機前綴的結果(沒有經過處理的rdd)++++++++++++++++++++++++")
    maprdd.countByKey.foreach(print)

    println("兩階段聚合(局部聚合+全局聚合)處理數據傾斜++++++++++++++++++++++++")
    //兩階段聚合(局部聚合+全局聚合)處理數據傾斜

    //加隨機前綴
    val prifixrdd=maprdd.map(x=>{
      val prifix=new Random().nextInt(10)
      (prifix+"_"+x._1,x._2)
    })

    //加上隨機前綴的key進行局部聚合
    val tmprdd=prifixrdd.reduceByKey(_+_)

    //去除隨機前綴
    val newrdd=tmprdd.map(x=> (x._1.split("_")(1),x._2))

    //最終聚合
    newrdd.reduceByKey(_+_).foreach(print)
  }
}

這樣,數據傾斜的問題就解決了。

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