【總結】Spark任務的core,executor,memory資源配置方法

文章地址:http://www.javashuo.com/article/p-yknrkwpr-hn.html
執行Spark任務,資源分配是很重要的一方面。若是配置不許確,Spark任務將耗費整個集羣的機緣致使其餘應用程序得不到資源。node

怎麼去配置Spark任務的executors,cores,memory,有以下幾個因素須要考慮:多線程

  • 數據量
  • 任務完成時間點
  • 靜態或者動態的資源分配
  • 上下游應用

Spark應用當中術語的基本定義:併發

  • Partitions : 分區是大型分佈式數據集的一小部分。 Spark使用分區來管理數據,這些分區有助於並行化數據處理,而且使executor之間的數據交換最小化
  • Task:任務是一個工做單元,能夠在分佈式數據集的分區上運行,並在單個Excutor上執行。並行執行的單位是任務級別。單個Stage中的Tasks能夠並行執行
  • Executor:在一個worker節點上爲應用程序建立的JVM,Executor將巡行task的數據保存在內存或者磁盤中。每一個應用都有本身的一些executors,單個節點能夠運行多個Executor,而且一個應用能夠跨多節點。Executor始終伴隨Spark應用執行過程,而且以多線程方式運行任務。spark應用的executor個數能夠經過SparkConf或者命令行 –num-executor進行配置
  • Cores:CPU最基本的計算單元,一個CPU能夠有一個或者多個core執行task任務,更多的core帶來更高的計算效率,Spark中,cores決定了一個executor中並行task的個數
  • Cluster Manager:cluster manager負責從集羣中請求資源

cluster模式執行的Spark任務包含了以下步驟:分佈式

  1. driver端,SparkContext鏈接cluster manager(Standalone/Mesos/Yarn)
  2. Cluster Manager在其餘應用之間定位資源,只要executor執行而且可以相互通訊,可使用任何Cluster Manager
  3. Spark獲取集羣中節點的Executor,每一個應用都可以有本身的executor處理進程
  4. 發送應用程序代碼到executor中
  5. SparkContext將Tasks發送到executors

以上步驟能夠清晰看到executors個數和內存設置在spark中的重要做用。ide

如下將嘗試理解優化spark任務的最佳方式:oop

  1. 靜態分配:配置值從spark-submit中體現
  2. 動態分配:從數據量和計算需求上衡量資源需求,並在使用後釋放掉,這樣可讓其餘應用重複利用資源

靜態分配

如下按不一樣例子討論驗證不一樣參數和配置組合性能

例子1
硬件資源: 6 節點,每一個節點16 cores, 64 GB 內存
每一個節點在計算資源時候,給操做系統和Hadoop的進程預留1core,1GB,因此每一個節點剩下15個core和63GB
內存。
core的個數,決定一個executor可以併發任務的個數。因此一般認爲,一個executor越多的併發任務可以獲得更好的性能,但有研究顯示一個應用併發任務超過5,致使更差的性能。因此core的個數暫設置爲5個。
5個core是代表executor併發任務的能力,並非說一個系統有多少個core,即便咱們一個CPU有32個core,也設置5個core不變。
executor個數,接下來,一個executor分配 5 core,一個node有15 core,從而咱們計算一個node上會有3 executor(15 / 5),而後經過每一個node的executor個數獲得整個任務能夠分配的executors個數。
咱們有6個節點,每一個節點3個executor,6 × 3 = 18個executors,額外預留1個executor給AM,最終要配置17個executors。
最後spark-submit啓動腳本中配置 –num-executors = 17
memory,配置每一個executor的內存,一個node,3 executor, 63G內存可用,因此每一個executor可配置內存爲63 / 3 = 21G
從Spark的內存模型角度,Executor佔用的內存分爲兩部分:ExecutorMemory和MemoryOverhead,預留出MemoryOverhead的內存量以後,纔是ExecutorMemory的內存。
MemoryOverhead的計算公式: max(384M, 0.07 × spark.executor.memory)優化

所以 MemoryOverhead值爲0.07 × 21G = 1.47G > 384Mspa

最終executor的內存配置值爲 21G – 1.47 ≈ 19 GB操作系統

至此, Cores = 5, Executors= 17, Executor Memory = 19 GB


例子2
硬件資源:6 node,32 core / node ,64G RAM / node
core個數:5,與例子1中描述具體緣由相同
每一個node的executor個數是 32 / 5 = 6
executor總個數: 6 node × 6 executor - 1 (AM) = 35
executor memory:
每一個node的內存 = 63G(1G留給系統應用) / 6 ≈ 10
MemoryOverhead = 0.07 × 10G = 700M 約等於 1G
ExecutorMemory = 10 G - 1 G = 9 GB

最終 Cores = 5, Executors = 5, Executor Memory = 9 GB


例子3
硬件資源: 6 節點,每一個節點16 cores, 64 GB 內存
例子1和2的場景,都是從固定的core數量,計算executor和memory的數量。
基於例子1,假設memory不須要19G,而僅須要10G內存就足夠數據計算,此時core, executor,memory按以下計算方式:
core個數據:5
每一個node的executor個數:15 / 3 = 5
按照例子1計算方式,這個階段的內存使用21G,除去MemoryOverhead的內存佔用,剩下19G。當咱們10G內存就足夠的場景下,不能使用 63G / 10G = 6個executor。由於 6 exector × 5 core = 30 core,每一個node要有30core,而例子1硬件配置是16core。這樣咱們就須要修改每一個executor的core配置。

接下來,將core的個數從5改成3,每一個node有5個executor,一共應該有 5 executor * 6 node - 1(AM佔用的core) = 29 ,memory則 63G / 5 ≈ 12
MemoryOverhead = 0.07 × 12G = 840M 約等於 1G
ExecutorMemory = 12 G - 1 G = 11 GB

最終 Core = 3,Executor = 29,Executor Memory = 11G

動態分配

若是採用動態分配策略,executer的個數上限是無窮大。這就意味着Spark任務在須要資源的狀況下,會佔用到集羣左右資源,集羣中會有其餘應用也須要資源運行,因此咱們須要在集羣層面上對core進行分配控制。

這就意味着咱們在基於用戶訪問基礎上,在基於YARN的任務中進行分配core,咱們建立一個spark_user,分配min max的core個數,這些core從YARN中剝離,區別於其餘基於YARN調度應用(例如Hadoop等)

爲了理解動態資源分配,首先須要瞭解一些屬性配置項:

spark.dynamicAllocation.enabled : 設置爲true,意味着咱們不關心executor的個數,考慮用到動態資源分配策略,在stage階段會有一下區別:

以多少個executor啓動Spark任務?

spark.dynamicAllocation.initialExecutors:初始化executor個數

怎樣動態控制executor的個數?
咱們經過spark-submit的方式初始化executor個數,根據負載狀況,任務在min(
spark.dynamicAllocation.minExecutors)和max(
spark.dynamicAllocation.maxExecutors)之間決定executor個數。

何時獲取一個新的executor和放棄一個executorspark.dynamicAllocation.schedulerBacklogTimeout :依靠這個參數,決定咱們何時獲取一個新的executor,每輪任務executor個數較前一輪將逞指數增加,好比第一輪1個executor,後續添加2,4,8個executor的方式,在某些特定場景下,將使用max(spark.dynamicAllocation.maxExecutors)個executor。spark.dynamicAllocation.executorIdleTimeout :executor空閒的時間,超時以後,將executor移除

相關文章
相關標籤/搜索