Spark On YARN內存和CPU分配

本篇博客參考:http://blog.cloudera.com/blog/2015/03/how-to-tune-your-apache-spark-jobs-part-2/ 

軟件版本:

CDH:5.7.2,JDK:1.7;

問題描述:

在使用Spark On YARN時(無論是Client模式或者是Cluster模式,當然下面會有這種模式的對比區別),可以添加諸如:
--executor-memory 8G --executor-cores 5 --num-executors 20
等等這樣的參數,但是這個和我們平常理解的感覺有誤,或者說不直觀,怎麼說呢?
比如一個6節點(NodeManager)的集羣,每個節點配置爲:16 CPU核,64G內存,那麼一般很容易提交代碼的時候寫成如下配置:
--num-executors 6 --executor-cores 15 --executor-memory 63G
但是這樣配置後,你會發現,在8088端口的YARN監控上得到的不是你想得到的資源分配,那正確的配置應該是怎樣的呢?

前備知識:

1. YARN NodeManager資源

NodeManager所在的機器如果是16核、64G,那麼設置如下參數(這兩個參數是NodeManager能分配的最大內存和最大cpu):
yarn.nodemanager.resource.memory-mb
yarn.nodemanager.resource.cpu-vcores
最好是小一點,比如設置內存爲63G,核心爲15,因爲需要分配一些資源給系統以及後臺Hadoop進程。當然,如果每個機器是6核,6G內存,那可以分配到5核以及5.5G內存左右;在原文中,說CDH機器可以自動的分配,不過我看到CDH集羣設置這兩個參數只是其能最大的值,也就是機器自身的資源。比如我的6核,6G內存,其配置如下:

(當然,默認是8G內存,8核CPU的)

2. Spark On YARN Client 和Cluster

Spark提交任務首先由客戶端(CLient)生成一個Spark Driver,Spark Driver在YARN的NOdeManager中生成一個ApplicationMaster,ApplicationMaster向YARN Resourcemanager申請資源(這些資源就是NodeManager封裝的Container,其中包含內存和cpu),接着Spark Driver調度並運行任務;那麼Client和CLuster過程如下:

其中,左邊是CLient模式,右邊是Cluster模式,也就是說其實CLuster模式下,提交任務後,CLient可以離開了,而Client模式下,Client不可以離開;
另外,不管CLient或CLuster模式下,ApplicationMaster都會佔用一個Container來運行;而Client模式下的Container默認有1G內存,1個cpu核,Cluster模式下則使用driver-memory和driver-cpu來指定;
但是這裏有個問題,在Client模式下,這裏的默認配置:

是512M的,但是參考博客裏面說CDH裏面這個默認是1G的(這裏應該是1G的,不然的話,後面實驗對應不到)

3. Spark On YARN資源申請

1. 用戶通過executor-memory設置內存;
2. 經過spark.yarn.exeuctor.memoryOverhead的加持,申請的內存變爲 executor-memory + max (384 , 0.1 * executor-memory) ;這裏的384 和0.1(原文中這個值是0.07,這個需要注意)是參考下面的參數來的:

3. NodeManager在向上申請資源的時候會經過參數:
yarn.scheduler.minimum-allocation-mb // defalut 1G 
yarn.scheduler.increment-allocation-mb // default 512M
的加持,向上取整爲2中的倍數,並且最接近2中的數值。比如說--executor-memory是3G,那麼2中的值就是3G+ max(384 , 0.1 *3 *1024) = 3G + 384m ~ 3.5G ,所以NodeManager申請的資源應該就是3.5G(3584m),而不是3456m(3*1024+384)。

另外:
executor-cores其實是設置並行的個數的,由於HDFS的bug,executor-cores建議設置爲5或以下;

實驗及如何設置資源分配:

1. 問題解答:

那麼,回到最開始的問題,6個節點(NodeManager),每個64G內存,16核如果要使用儘可能多的集羣資源,怎麼分配:
1. 首先,去掉節點系統使用1G內存1核cpu,那麼還剩63G內存,15核cpu;
2. 加入executor-cpus設置爲5,也就是建議值的最大,那麼每個節點可以分配3個Container ,即 15 /5= 3 個Executor;
3. 哪每個executor內存呢? 63/3 = 21G 內存,21G - max(384 ,0.1 *21G) = 18.9G ; 那麼executor-memory應該設置爲多少呢?這個值應該是18.5G,爲什麼是這個呢?
a. 第一,這個值需要是512M的倍數;
b,第二,xG + max(384m,0.1 * xG) < 21 G, 這個x 最大就是18.5G;
說道這裏,需要說明一點,在參考的鏈接中參數0.1不是0.1,而是0.07,所以算的的executor-memory是19G,這個需要注意;
4. 那有多少個executor呢? 有人說這還不好算:6個節點 ,每個節點3executor,所以一共是18個;這個不對;
因爲需要有一個container來部署ApplicationMaster,所以有個節點其資源就會減少,這也就是說在ApplicationMaster所在的節點上最多只能有2個executor,所以最終的參數是:
--num-executors 17 --executor-cores 5 --executor-memory 18944m
因爲這個參數不能識別小數點,所以不能寫成18.5G(注意這個值和原文中是不一樣的,如果0.1參數在CDH集羣中的默認值是0.07,那麼就是原文的答案);

2. 5節點,6核cpu,6G內存怎麼分配1

1. 去掉節點系統內存512M,1核cpu;還剩5核cpu,5.5G內存;
2. 如果每個executor的executor-cpus設置爲5,那麼也就是說每個節點有1個executor;
3. 這樣子的話,executor-memory就應該設置爲5G , 5G + max(384, 0.1 * 5G ) = 5.5G   ~ 5.5G ,這樣子分配剛剛好;
4. executor就應該設置爲4 ,因爲其中一個NodeManager分配了ApplicationMaster,那麼其就不能生成一個executor了;
啓動參數爲:
spark-shell --master yarn  --deploy-mode client --executor-memory 5G --executor-cores 4 --num-executors 4
5. 驗證:
a. 首先看資源分配:
container個數5個?
這個怎麼來的,明明申請了4個executor,每個executor對應一個container,那就是4個container,怎麼會多一個呢?其實這個就是啓動ApplicationMaster的container;
cpu核有17個? 
4*4 = 16 ,另外一個當然就是啓動ApplicationMaster的資源了;
內存23552m ?
 4 *5 *1024 = 20480,這不對呀,還差好多呢,那實際是怎麼計算的呢?實際的計算方式應該是:
4* (5G + max(384m , 0.1 * 5G )) * 1024 + 1024 = 23552 ;   其中,最後一個加的就是啓動ApplicationMaster默認的1G內存;

b. 看日誌:


看日誌其實這個過程就更加清晰了;
首先,可以看到4個container;其次內存是5632m = (5G + 0.1 *5G )* 1024。

3. 5節點,6核cpu,6G內存怎麼分配2

除了2中的分配方式,有沒有其他分配方式呢?如果每個executor-cpus是1呢?
1. executor-cpus=1 ; 那麼每個節點就可以分5個executor;
2. 所以每個節點可以分 5.5G/ 5 = 1.1G ,所以最大隻能1.1G,內存,而且NodeManager申請的資源只能是512M的整數倍,所以最大是1024M,那麼executor-memory + max( 384, 0.1 * executor-memory) = 1024M ,那麼executor-memory就等於640;
3. 有多少個executor呢? 4 * 5 = 20 ,運行ApplicationMaster節點的有多少個呢,去掉ApplicationMaster的資源1G內存,1cpu還剩4.5G內存,4cpu核,申請4個executor是可以的,所以一共就有 4* 5 + 4 = 24個container;
參數:
spark-shell --master yarn  --deploy-mode client --executor-memory 640m --executor-cores 2 --num-executors 24 

4. 驗證:




4. 5節點,6核cpu,6G內存怎麼分配3

除了2、3中的分配方式,有沒有其他分配方式呢?如果每個executor-cpus是2呢?
1. executor-cpus=2 ; 那麼每個節點就可以分2個executor(5/2 ~ 2 ,只能往低約等於);
2. 所以每個節點可以分 5.5G/ 2 = 2.75G ,所以最大隻能2.75G,內存,而且NodeManager申請的資源只能是512M的整數倍,所以最大是2.5G,那麼executor-memory + max( 384, 0.1 * executor-memory) ~ 2.5G ,那麼executor-memory就等於2176;
3. 有多少個executor呢? 4 * 2 = 8 ,運行ApplicationMaster節點的有多少個呢,去掉ApplicationMaster的資源1G內存,1cpu還剩4.5G內存,4cpu核,只能申請1個executor是可以的,所以一共就有 4* 2 + 1 = 9個container;
參數:
spark-shell --master yarn  --deploy-mode client --executor-memory 2176m --executor-cores 2 --num-executors 9

4. 驗證:




5. 5節點,6核cpu,6G內存怎麼分配4

但是,如果上一個分配中的第2中分配的內存是executor-memory + max( 384, 0.1 * executor-memory) ~ 2G, 那麼executor-memory= 1664m;這個時候有多少個container呢?
運行ApplicationMaster的這時就可以運行2個executor了,所以一共有10個executor;
參數:
spark-shell --master yarn  --deploy-mode client --executor-memory 1664m --executor-cores 2 --num-executors 10
驗證:


總結:

1. Spark On YARN資源分配沒有Spark StandAlone的那麼明確,過程有點複雜;
2. 國外的文章參考價值還是蠻大的,畢竟很多技術都是從國外傳過來的,google以後都不能用了,咋辦?


分享,成長,快樂

腳踏實地,專注

轉載請註明blog地址:http://blog.csdn.NET/fansy1990




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