Spark優化總結

Spark優化

主要分爲兩個方面的優化,一是代碼邏輯的優化,二是資源配置的優化

1.代碼邏輯

1.1.RDD優化

RDD優化主要也有兩個方面的考慮,一是RDD的複用,二是RDD的持久化。那麼主要針對RDD的持久化進行說明。在Spark中多次對同一個RDD執行算子時,每次都會對這個RDD的父RDD重新計算一次,所以要避免這種重複計算的資源浪費,那麼就需要對RDD進行持久化。

Memory_Only 內存
Memory_Only_2 內存+數據備份
Memory_Only_Ser

內存+序列化

Memory_And_Disk 內存+磁盤
Memory_And_Disk_2 內存+磁盤+備份
Memory_And_Disk_Ser 內存+磁盤+序列化
Disk_Only 磁盤

1.2.並行度優化

基本概念:

  • CPU核數

一臺服務器有兩顆CPU,每顆CPU是16核,一顆CPU的超線程數是2,所以:

假設我們的集羣是100臺服務器那麼:

總核數 = 100 * 2 * 16 = 3200

總的邏輯CPU數 = 100 * 2 * 16 * 2 = 6400

  • RDD分區

默認參數:spark.files.maxPartitionBytes = 128 M,就是說當一個文件大小超過128M纔會拆成兩個分區,而當SparkContext創建後會生成兩個參數

sc.defaultParallelism = spark.default.parallelism

sc.defaultMinPartitions = min(spark.default.parallelism,2)

也就是說,我們可以根據這兩個參數來推算RDD的分區數量。當讀取本地文件時:默認RDD分區公式: max(本地file的分片數, sc.defaultMinPartitions)。當讀取HSFS文件時:默認RDD分區公式:max(hdfs文件的block數目, sc.defaultMinPartitions)

 

Spark並行度:

Spark並行度就是每個Spark作業中各個Stage中所有task的數量,也就表示了Spark作業在各個階段的並行度,需要知道的是DAGScheduler會根據Spark作業中是否存在Shuffle Dependency來劃分Stage,然後爲每個Stage中的Task組成TaskSet交給TaskScheduler,那麼TaskScheduler會將TaskSet發送到Executor進行處理,當Executor接受到TaskSet之後進行反序列化之後把這些Task封裝到TaskRunner的線程中執行。Spark並行度是由參數spark.default.parallelism所控制的,而默認的並行度分爲這麼幾種:

  • 本地模式

在local[n]模式下:spark.default.parallelism = n

  • 集羣

在Sandalone/Yarn模式下:spark.default.parallelism = 所有Executor數乘以每個Executor的core數,也就是所有Executor總的core數

 

總結:

比如:集羣規模是100臺,每臺服務器兩顆CPU,每顆CPU16核,那麼總的CPUcores就是6400個,如果在計算的任何stage中使用的並行task的數量沒有足夠多,那麼集羣資源是無法被充分利用。所以爲了充分利用系統資源儘可能提高。

  • 參數一:num-executors

該參數用於設置Spark作業總共需要用多少個Executor來執行

  • 參數二:executor-cores

該參數用於設置每個Executor進程的CPU core數量

  • 參數三:spark.default.parallelism

該參數用於設置每個Stage默認的Task數量

 

補充:

每個幾點可以啓動一個或多個Executor,每個Executor由一個或多個core組成,每個core只能執行一個task,每個task執行的結果產生一個目標partition


1.3.廣播變量

廣播變量其實就是將ReduceJoin轉化爲MapJoin,這樣做的好處就是將Reduce端每個Task獲取一份副本,轉化爲一個Executor獲取一份副本,直接減少了內存開銷,同時也避免了數據傾斜

def broadcastVal(sc: SparkContext): Unit = {
    val kv = Map(("a",1),("b",2))
    val bc = sc.broadcast(kv)
    val rdd = sc.textFile("D:/io/input/txt/rdd.txt").flatMap(_.split("\\s+"))
    rdd.foreach{
        e=>{
            if (bc.value.contains(e)) {
                println(e)
            }
        }
    }
}

通常來說只會將數據進行廣播,RDD並不能廣播,如果想將RDD廣播出去的話,可以將RDD拉回到Driver然後將RDD的數據在廣播出去

1.4.Kryo序列化

從Spark 2.0.0版本開始,簡單類型、簡單類型數組、字符串類型的Shuffling RDDs 已經默認使用Kryo序列化方式了。或者手動指定conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer"); 

1.5.本地化等待時長

1.6.算子優化

1.6.1.mapPartitions
1.6.2.foreachPartition
1.6.3.filter&coalesce
1.6.4.repartition
1.6.5.reduceByKey

2.資源配置

2.1.最優資源配置

--num-executors executor個數
--driver-memory Driver內存
--executor-cores ExecutorCPU數量
--executor-memory Executor內存

2.2.shuffle優化

2.2.1.Map緩衝區

默認32KB,手動指定:conf.set("spark.shuffle.file.buffer", "64")

2.2.2.Reduce緩衝區

默認48M,手動指定:conf.set("spark.reducer.maxSizeInFlight", "96")

2.2.3.Reduce重試次數

默認3次,手動指定:conf.set("spark.shuffle.io.maxRetries", "6")

2.2.4.Reduce等待間隔

默認5s,手動指定:conf.set("spark.shuffle.io.retryWait", "60s")

2.2.5.SortShuffle

默認200,手動指定:conf.set("spark.shuffle.sort.bypassMergeThreshold", "400")

2.3.JVM優化

對於JVM調優,首先應該明確,major gc/minor gc,都會導致JVM的工作線程停止工作,即stop the world

Spark 1.6 之後引入的統一內存管理機制,與靜態內存管理的區別在於存儲內存和執行內存共享同一塊空間,可以動態佔用對方的空閒區域,統一內存管理的堆內內存結構

2.3.1.Cache內存佔比

靜態內存管理機制:默認0.6,手動指定:conf.set("spark.storage.memoryFraction", "0.4")

統一內存管理機制:無需手動調節(動態佔用機制)

2.3.2.Executor對外內存

默認300M,手動指定:--conf spark.yarn.executor.memoryOverhead=2048

2.3.3.連接時長

默認60s,手動指定:--conf spark.core.connection.ack.wait.timeout=300

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