Spark作業不知道該如何分配資源怎麼辦?
前幾天有好幾個朋友問我關於spark作業分配資源的問題:即在提交作業的時候,不知道該分配多少資源比較好?我的回答是 靠經驗 ,仔細想想靠經驗這等於不是沒說嗎,總有一些方法論或者思路的吧。所以就有了這篇文章,下筆的時候著實是不知道該怎麼寫,所以在網上搜索了一下,看看大佬們是怎麼回答的。趕巧了不是,還真發現3年前就有人問過這個問題。
看了下評論,我感覺我能看懂,但不知道朋友們是否能看懂,所以我想還是要再詳細囉嗦一下吧
首先呢,spark官網給我們提供了一些硬體層面的建議,先上鍊接http://spark.apache.org/docs/latest/hardware-provisioning.html。
但是這個文章並沒有很細粒度介紹應用級別該如何分配資源。不過涉及到的幾個方向可以參考一下,比如 記憶體,CPU 。
首先來複習一下spark涉及到這兩塊部分引數如下:
--num-executors/(SparkSQL中是spark.executor.instances 引數) |
該引數代表了作業使用的總共executor個數 |
--driver-memory/(SparkSQL配置的是spark.driver.memory引數) |
該引數代表了Driver端所消耗的記憶體,通常Driver端不會消耗太多資源,所以不需要給太多資源。 |
--executor-memory(SparkSQL配置的是spark.executor.memory引數) |
該引數代表了每個executor所佔用的記憶體 |
--executor-cores/(SparkSQL配置的是spark.executor.cores引數) |
該引數代表了一個executor中能夠並行執行的task數(注意並行和併發的區別!) |
通常一個Spark作業所消耗的總記憶體數>=(spark.executor.instances)*(spark.exector.memory);
所佔用的CPU個數>=(spark.executor.instances)*(spark.exector.cores)。
這裡之所以要用大於,是因為AppMaster也要佔用資源的!扯到AppMaster,那需要再複習一下Yarn部分的兩個引數:
yarn.nodemanager.resource.memory-mb |
該引數表示的是nm可供Yarn使用最大可用記憶體 |
yarn.nodemanager.resource.cpu-vcores |
該引數表示的是nm可供yarn使用的最大虛擬cpu數量 |
一般在實際生產環境中,yarn可分配的總資源肯定是已經分配好了的。甚至是會有單獨的spark作業佇列(這裡也要看yarn的排程模式,是fair,還是fifo,還是capacity)。
我們這裡先舉個例子來說明下:假設我們有一個裸叢集,共有6個節點,每個節點都是16c 64g的配置(真實情況下每個節點的配置可能是參差不齊的)。
但是我們不可能把所有的資源全分配到yarn上,還是要留一部分作為系統運轉的,那麼每個節點留1C 1G 好了,採取極限的方式。最後每個節點可供yarn分配的資源如下:
yarn.nodemanager.resource.memory-mb=63g
yarn.nodemanager.resource.cpu-vcores=15
那麼總資源就是all_memory=63*6=378g;all_cpu=6*15=90c
我們假設每個Executor並行度為5,那麼就需要90/5=18個executor,但是需要留一個給AppMaster,所以--num-exectors=17;剛才算下來總共需要18個Executor,一共6個節點,平均每個節點是啟動3個exector,一個節點是63g,那麼每個executor可佔用記憶體就是21g,請注意哦:每個executor並不是把21g全部給作業用,還要留一部分資源用來儲存棧,buffer之類的開銷以此來保證穩定性,也就是常說的堆外記憶體,通過spark.executor.memoryOverhead引數來設定這塊的開銷,其值=max(384mb,0.1*executorMemory)。因此這部分堆外記憶體=max(384mb,0.1*21)~=2g。那麼堆內記憶體=21-2=19g。
這裡用表格來彙總一下:
也就是說在提交作業的時候,其引數配置值不能大於以下值(這裡的例子是假設把資源全給你的任務去用!):
--executor-cores / spark.executor.cores = 5 --executor-memory / spark.executor.memory = 19 --num-executors / spark.executor.instances = 17
節點數 |
記憶體/每節點 |
CPU/每節點 |
Yarn可分配最大記憶體數 |
Yarn可分配最大CPU |
假設每個executor並行度數 |
總executor數 |
實際幹活的executor數 |
每個節點可啟動的executor數 |
每個executor佔用的記憶體 |
堆外記憶體 |
實際幹活所用到的記憶體 |
6 |
64g |
16C |
63g*6=378g |
15C*6=90C |
5 |
90C/5=18 |
18-1=17 |
18/6=3 |
63g/3=21g |
max(384mb,0.1*21g)=2g |
21g-2g=19g |
9 |
90c/9=10 |
10-1=9 |
10/6~=2 |
63g/~=2~=37g |
max(384mb,0.1*37g)=3g |
37g-3=34g |
可能有朋友會困惑,為什仫每個executor並行度設定為5,當然也可以調大。如果調大每個executor的並行度,也相當於是提高了並行能力,這樣的話就減少了task來回輪詢的次數,比如你有100個task,每個executor執行20個task,那麼要輪詢5次;如果每個executor設定50個task,那麼要輪詢2次;這樣一來就會增大每個executor所持有的記憶體。
其實可以按照前面論壇裡提到的一種評估方式就是按照task數量來倒推,官方建議一個cpu core是處理2~3個task。
那麼假設有100個task,最多需要50c,還是按照上面的例子,這個時候就要看你是採取每個節點均攤的方式呢,還是某幾個節點集中處理。採取何種方式還要結合你實際處理的資料量和計算複雜邏輯(因為這裡還要思考網路消耗和本地化計算,每個節點的負載情況等等因素),當然通常情況下是採取均攤的方式,那麼每個節點大概會使用8c。那麼每個節點啟動幾個executor呢?是啟動一個executor,還是2個executor,每個executor,每個executor大概佔用多大記憶體呢?這個時候就要看你的程式碼邏輯是計算多一些還是快取多一些。這裡就涉及到記憶體模型的東西了,不知道記憶體模型的朋友再複習一下我原來寫的文章: Tungsten On Spark-記憶體模型設計
儘管以上資源分配都已經評估好了,但並不代表後續不需要優化了,不然網上怎麼會有那麼多優化文章,同時還要注意團隊協作資源,不能把所有的資源都給你用,不然別人還怎麼幹活?
所以還要在你評估的資源上再縮減一部分,這樣一來一回可能需要不斷的調整,這也是為什仫很多人問到怎麼分配資源的時候,都會說一句靠經驗!
小編覺得這玩意真的是沒有公式可套用的。
如果你有更好的分配資源的方法論或者有哪裡寫的不對的地方,歡迎大佬聯絡我分享給其他小夥伴們。
如果你有其他困擾的問題,歡迎騷擾我~
參考:
-
spark官網
-
http://bbs.csdn.net/topics/392153088