Spark配置介紹
-
Spark中的配置選項在四個地方可以進行配置,其中優先順序如下:
SparkConf(程式碼) > spark-submit 或 spark-shell 命令列引數 > spark-defaults.conf > spark-env.sh > 預設值
-
在程式碼中配置的為靜態配置,在spark-submit提交和spark-default.conf設定的引數為動態配置
-
spark的屬性大致分為兩種型別:
- 部署相關 如spark.driver.memory,spark.executor.instances,在sparkConfig中可能不起作用,用配置檔案和命令列設定
- Spark執行時控制相關 如spark.task.maxFailures,任何方式都可配置
-
各種配置項的配置建議:
- 硬體資源類的(資源供給類:CPU、記憶體、磁碟、網路),spark-defaults.conf統一設定;
- 全域性服務類的(比如動態擴容、External shuffle services,安全,壓縮,Spark UI,等等),spark-defaults.conf統一設定;
- 任務粒度的配置(如Task重試、locality wait、是否推斷speculative task,等等),用命令列,或是SparkConf,推薦用SparkConf,命令列不好管理
個人實踐:在spark-env.sh中配置叢集需要的配置;在spark-default.conf中配置job需要的配置,提交job時指定配置檔案或適用預設配置檔案spark-default.conf
一、CPU配置項
cpu的利用率由兩個方面決定,要充分利用cpu要兩方面資源相匹配
- 系統資源方面:叢集、executor中的cpu核數
- 資料資源方面:資料分片的個數
cpu併發度(每個executor能併發執行幾個task)
# 叢集內滿配cpu核數
spark.cores.max
# 單個Executor內cpu核數,standalone模式預設會使用全部核
spark.executor.cores
# 單個task計算任務消耗cpu核數,預設為1且不能小於1,大於1時是task任務為多執行緒的(大部分時候不必設定)
spark.task.cpus
資料並行度引數如下(將資料劃分為多少塊):
# 未指定分割槽數時RDD預設並行度
spark.default.parallelism
# SparkSQL框架下,資料關聯、聚合操作時Reducer 在shuffle reduce階段預設的並行度
spark.sql.shuffle.partitions
併發度=任務數=(spark.executor.cores)/(spark.task.cpus)
併發度基本由 spark.executor.cores 引數敲定,因為spark.task.cpus通常為1,且不能小於1,可以大於1(為了應對需要多個執行緒才能執行的任務)
Executor數=(spark.cores.max)/(spark.executor.cores)
以上是都是在standalone模式下的配置項,在yarn叢集中可直接指定executor個數:
# 在yarn叢集中指定executor的個數
spark.executor.instances
例子:在kafka中的分割槽數就是spark拉取資料的並行度度,在拉取clickhouse資料時指定的numPartitions就是資料的並行度。
建議:將資料並行度設定為cpu核數的2-3倍,以充分利用cpu,否則可能會導致task傾斜的問題(一些executor十分繁忙另外一些executor卻沒有在執行)。將分割槽數(資料並行度)調高也會將資料的分片大小減小,使每個分片執行的更快,但太高的並行度會導致排程花費較多時間。
二、記憶體配置項
Spark 會區分堆內記憶體(On-heap Memory)和堆外記憶體(Off-heap Memory)
堆內記憶體的申請與釋放統一由 JVM 管理,堆外記憶體是 Spark 通過呼叫 Unsafe 的 allocateMemory 和 freeMemory 方法直接在作業系統記憶體中申請、釋放記憶體空間
慎用堆外記憶體,官方推薦只用堆內記憶體。堆內外空間互相隔離,堆內、堆外是以Job為粒度劃分的,也就是說,同一個Job,要麼全用堆外,要麼全用堆內。堆外、堆內的記憶體空間,是不能在同一個Job之內共享的。
堆外記憶體相關設定:
spark.memory.offHeap.enabled 預設false
spark.memory.offHeap.size 預設為0
堆外記憶體僅供瞭解,只使用堆內記憶體即可
堆內記憶體相關設定:
# 每個executor的記憶體絕對值大小,預設1g
spark.executor.memory
# 除使用者記憶體外的計算和儲存記憶體所佔比例,預設0.6
spark.memory.fraction
# 計算和和儲存記憶體中儲存記憶體所佔比例,預設0.5
spark.memory.storageFraction
-
Reserved Memory:固定為300MB,不受開發者控制,它是 Spark預留的、用來儲存各種Spark內部物件的記憶體區域;
-
User Memory:用於儲存開發者自定義的資料結構,例如RDD運算元中引用的陣列、列表、對映等等
-
Execution Memory:用來執行分散式任務。分散式任務的計算,主要包括資料的轉換、過濾、對映、排序、聚並歸併等環節,而計算環節的記憶體消耗,統統來自Executor Memory
-
Storage Memery:用於快取分散式資料集,比如RDD Cache、廣播變數等等。RDD Cache指的是RDD物化到記憶體中的副本。在果同一個RDD被引用多次,那麼把這個RDD快取到內大幅提升作業的執行效能。
舉例:
記憶體 | 大小 |
---|---|
spark.executor.memory | 20GB |
spark.memory.offHeap.size | 10GB |
spark.memory.fraction | 0.8 |
spark.memory.storageFraction | 0.6 |
堆內記憶體:
Reserved Memory大小:300M
User Memory大小:20 x(1-0.8)= 4GB
Storage Memeory大小:20 x 0.8 x 0.6 = 9.6 GB
Execution Memory大小:20 x 0.8 x (1-0.6)= 6.4GB
堆外記憶體:
Storage Memeory大小:10 x 0.6 = 6GB
Execution Memory大小:10 x 0.4 = 4GB
在spark1.6版本之後,記憶體靜態劃分轉換為動態管理記憶體,即 Execution Memory和Storage Memery可相互搶佔,搶佔規則如下(Execution Memeory更重要原則):
- 如果對方的記憶體空間有空閒,雙方可以互相搶佔
- 對於Storage Memory搶佔的 Execution Memory部分,當分散式任務有計算需要時Storage Memory必須立即歸還搶佔的記憶體,涉及的存資料要麼落盤、要麼清除
- 對於 Execution Memory搶佔的 Storage Memory部分,即便 Storage Memory有收回記憶體的需要,也必須要等到分散式任務執行完畢才能釋放。
調優建議:
-
spark.memory.fraction可以儘可能調大,spark中使用者記憶體用不了太多,主要使用計算和儲存記憶體
-
ETL(Extract、Transform、Load)作業,業務抽取、轉換、載入,資料只處理一次,不需要快取,儲存記憶體的比率適當降低;機器學習、圖計算反覆使用資料,計算記憶體比率適當增大
-
資料分片的大小與executor中每個核分得的記憶體大小基本相同
三、磁碟配置項
在Spark執行過程中會產生日誌和在shuffle過程中會產生中間檔案,將這些檔案存放在固態硬碟上會使Spark擁有更好的效能
配置在spark-env.sh中,服務級別的配置
# spark暫存空間目錄,存放map輸出檔案和RDDs,支援","分隔的多個目錄。shuffle輸出的檔案
SPARK_LOCAL_DIRS=
# spark的worker工作目錄,暫存空間存放全部日誌,預設SPARK_HOME/work
SPARK_WORKER_DIR=
配置在spark-defaults.conf或sparkConf中,任務級別的配置,會被SPARK_LOCAL_DIRS設定的目錄覆蓋
# spark暫存空間目錄,用來改善Shuffle中間檔案儲存,以及RDD Cache磁碟儲存
spark.local.dir 目錄
四、cache
在Spark計算過程中善用cache會極大提高效能,對重複使用的資料建議新增cache,而對只使用一兩次的資料不建議新增cache,否則不僅浪費記憶體空間而且會降低Spark執行效率
使用的建議:
- 如果 RDD/DataFrame/Dataset 在應用中的引用次數為 1,就堅決不使用 Cache
- 如果引用次數大於 1,且執行成本佔比超過 30%,應當考慮啟用 Cache
Cache table
# 建立臨時檢視再cache
df.createTempView("table_name")
spark.sql("cache tabel table_name")
CACHE [ LAZY ] TABLE table_identifier
[ OPTIONS ( 'storageLevel' [ = ] value ) ] [ [ AS ] query ]
-
LAZY可選,加了之後不立刻快取,當第一次使用的時候快取。不加預設立刻快取
-
OPTIONS儲存級別,預設MEMORY_AND_DISK
SER 字樣的表示以序列化方式儲存,不帶 SER 則表示採用物件值,序列化儲存(二進位制儲存)會節省儲存空間,但是消耗計算資源最常用MEMORY_ONLY 和 MEMORY_AND_DISK,它們分別是 RDD 快取和 DataFrame 快取的預設儲存級別。這兩種儲存級別都是先嚐試把資料快取到記憶體, MEMORY_AND_DISK在記憶體不足時將資料快取到磁碟
-
query 將查詢結果快取,如將testData表中查到的結果快取為testCache表
CACHE TABLE testCache OPTIONS ('storageLevel' 'DISK_ONLY') SELECT * FROM testData;
Cache運算元
df.cache.count
cache操作時惰性操作,只有action運算元時才觸發計算
只有 count 才會觸發快取的完全物化,而 first、take 和 show 這 3 個運算元只會把涉及的資料物化,例如first只快取1條資料,show只快取20條資料
在此只介紹了Spark硬體方面的部分調優方法,此外還有SparkSQL、Shuffle、廣播變數等方面的調優方法
本文參考極客時間中《零基礎入門Spark》《Spark效能調優實戰》