Spark作業不知道該如何分配資源怎麼辦?

語言: CN / TW / HK

前幾天有好幾個朋友問我關於spark作業分配資源的問題:即在提交作業的時候,不知道該分配多少資源比較好?我的回答是 靠經驗 ,仔細想想靠經驗這等於不是沒說嗎,總有一些方法論或者思路的吧。所以就有了這篇文章,下筆的時候著實是不知道該怎麼寫,所以在網上搜索了一下,看看大佬們是怎麼回答的。趕巧了不是,還真發現3年前就有人問過這個問題。

看了下評論,我感覺我能看懂,但不知道朋友們是否能看懂,所以我想還是要再詳細囉嗦一下吧

首先呢,spark官網給我們提供了一些硬體層面的建議,先上鍊接https://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官網

  • https://bbs.csdn.net/topics/392153088