理想情況下,我們應用對Yarn資源的請求應該立刻得到滿足,但現實情況資源往往是有限的,特別是在一個很繁忙的叢集,一個應用資源的請求經常需要等待一段時間才能的到相應的資源。在Yarn中,負責給應用分配資源的就是Scheduler。其實排程本身就是一個難題,很難找到一個完美的策略可以解決所有的應用場景。為此,Yarn提供了多種排程器和可配置的策略供我們選擇。YARN架構如下:
- ResourceManager(RM):負責對各NM上的資源進行統一管理和排程,將AM分配空閒的Container執行並監控其執行狀態。對AM申請的資源請求分配相應的空閒Container。主要由兩個元件構成:排程器(Scheduler)和應用程式管理器(Applications Manager)。
- 排程器(Scheduler):排程器根據容量、佇列等限制條件(如每個佇列分配一定的資源,最多執行一定數量的作業等),將系統中的資源分配給各個正在執行的應用程式。排程器僅根據各個應用程式的資源需求進行資源分配,而資源分配單位是Container,從而限定每個任務使用的資源量。Scheduler不負責監控或者跟蹤應用程式的狀態,也不負責任務因為各種原因而需要的重啟(由ApplicationMaster負責)。總之,排程器根據應用程式的資源要求,以及叢集機器的資源情況,為用程式分配封裝在Container中的資源。排程器是可插拔的,例如CapacityScheduler、FairScheduler。(PS:在實際應用中,只需要簡單配置即可)
- 應用程式管理器(Application Manager):應用程式管理器負責管理整個系統中所有應用程式,包括應用程式提交、與排程器協商資源以啟動AM、監控AM執行狀態並在失敗時重新啟動等,跟蹤分給的Container的進度、狀態也是其職責。ApplicationMaster是應用框架,它負責向ResourceManager協調資源,並且與NodeManager協同工作完成Task的執行和監控。MapReduce就是原生支援的一種框架,可以在YARN上執行Mapreduce作業。有很多分散式應用都開發了對應的應用程式框架,用於在YARN上執行任務,例如Spark,Storm等。如果需要,我們也可以自己寫一個符合規範的YARN application。
- NodeManager(NM):NM是每個節點上的資源和工作管理員。它會定時地向RM彙報本節點上的資源使用情況和各個Container的執行狀態;同時會接收並處理來自AM的Container 啟動/停止等請求。ApplicationMaster(AM):使用者提交的應用程式均包含一個AM,負責應用的監控,跟蹤應用執行狀態,重啟失敗任務等。
- Container:是YARN中的資源抽象,它封裝了某個節點上的多維度資源,如記憶體、CPU、磁碟、網路等,當AM向RM申請資源時,RM為AM返回的資源便是用Container 表示的。YARN會為每個任務分配一個Container且該任務只能使用該Container中描述的資源。
1. Yarn排程器介紹
1.1. FIFO Scheduler(先進先出排程器)
FIFO Scheduler把應用按提交的順序排成一個佇列,這是一個先進先出佇列,在進行資源分配的時候,先給佇列中最頭上的應用進行分配資源,待最頭上的應用需求滿足後再給下一個分配,以此類推。FIFO Scheduler是最簡單也是最容易理解的排程器,也不需要任何配置,但它並不適用於共享叢集。大的應用可能會佔用所有叢集資源,這就導致其它應用被阻塞。在共享叢集中,更適合採用Capacity Scheduler或Fair Scheduler,這兩個排程器都允許大任務和小任務在提交的同時獲得一定的系統資源。下面“Yarn排程器對比圖”展示了這幾個排程器的區別,從圖中可以看出,在FIFO 排程器中,小任務會被大任務阻塞。
1.2.Capacity Scheduler(容量排程器)
yarn-site.xml中預設配置的資源排程器。而對於Capacity排程器,有一個專門的佇列用來執行小任務,但是為小任務專門設定一個佇列會預先佔用一定的叢集資源,這就導致大任務的執行時間會落後於使用FIFO排程器時的時間。用這個資源排程器,就可以配置yarn資源佇列,這個後面後介紹用到。
1.3. Fair Scheduler(公平排程器)
Fair排程器的設計目標是為所有的應用分配公平的資源(對公平的定義可以通過引數來設定)。在上面的“Yarn排程器對比圖”展示了一個佇列中兩個應用的公平排程;當然,公平排程在也可以在多個佇列間工作。舉個例子,假設有兩個使用者A和B,他們分別擁有一個佇列。當A啟動一個job而B沒有任務時,A會獲得全部叢集資源;當B啟動一個job後,A的job會繼續執行,不過一會兒之後兩個任務會各自獲得一半的叢集資源。如果此時B再啟動第二個job並且其它job還在執行,則它將會和B的第一個job共享B這個佇列的資源,也就是B的兩個job會用於四分之一的叢集資源,而A的job仍然用於叢集一半的資源,結果就是資源最終在兩個使用者之間平等的共享。在Fair排程器中,我們不需要預先佔用一定的系統資源,Fair排程器會為所有執行的job動態的調整系統資源。當第一個大job提交時,只有這一個job在執行,此時它獲得了所有叢集資源;當第二個小任務提交後,Fair排程器會分配一半資源給這個小任務,讓這兩個任務公平的共享叢集資源。
a) 公平排程器,就是能夠共享整個叢集的資源
b) 不用預先佔用資源,每一個作業都是共享的
c) 每當提交一個作業的時候,就會佔用整個資源。如果再提交一個作業,那麼第一個作業就會分給第二個作業一部分資源,第一個作業也就釋放一部分資源。再提交其他的作業時,也同理。。。。也就是說每一個作業進來,都有機會獲取資源。
1.4. Fair Scheduler與Capacity Scheduler區別
- 資源公平共享:在每個佇列中,Fair Scheduler可選擇按照FIFO、Fair或DRF策略為應用程式分配資源。Fair策略即平均分配,預設情況下,每個佇列採用該方式分配資源
- 支援資源搶佔:當某個佇列中有剩餘資源時,排程器會將這些資源共享給其他佇列,而當該佇列中有新的應用程式提交時,排程器要為它回收資源。為了儘可能降低不必要的計算浪費,排程器採用了先等待再強制回收的策略,即如果等待一段時間後尚有未歸還的資源,則會進行資源搶佔;從那些超額使用資源的佇列中殺死一部分任務,進而釋放資源
- 負載均衡:Fair Scheduler提供了一個基於任務數的負載均衡機制,該機制儘可能將系統中的任務均勻分配到各個節點上。此外,使用者也可以根據自己的需求設計負載均衡機制
- 排程策略靈活配置:Fiar Scheduler允許管理員為每個佇列單獨設定排程策略(當前支援FIFO、Fair或DRF三種)
- 提高小應用程式響應時間:由於採用了最大最小公平演算法,小作業可以快速獲取資源並執行完成
2.Yarn排程器配置
yarn資源排程器是在yarn-site.xml
中配置。
2.1. FairScheduler
Fair Scheduler的配置選項包括兩部分:
一部分在yarn-site.xml中,主要用於配置排程器級別的引數
一部分在一個自定義配置檔案(預設是fair-scheduler.xml)中,主要用於配置各個佇列的資源量、權重等資訊。
2.1.1 yarn-site.xml
yarn-site.xml
介紹
<!– scheduler start –>
<property>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value>
<description>配置Yarn使用的排程器外掛類名;Fair Scheduler對應的是:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</description>
</property>
<property>
<name>yarn.scheduler.fair.allocation.file</name>
<value>/etc/hadoop/conf/fair-scheduler.xml</value>
<description>配置資源池以及其屬性配額的XML檔案路徑(本地路徑)</description>
</property>
<property>
<name>yarn.scheduler.fair.preemption</name>
<value>true</value>
<description>開啟資源搶佔,default is True</description>
</property>
<property>
<name>yarn.scheduler.fair.user-as-default-queue</name>
<value>true</value>
<description>設定成true,當任務中未指定資源池的時候,將以使用者名稱作為資源池名。這個配置就實現了根據使用者名稱自動分配資源池。default is True</description>
</property>
<property>
<name>yarn.scheduler.fair.allow-undeclared-pools</name>
<value>false</value>
<description>是否允許建立未定義的資源池。如果設定成true,yarn將會自動建立任務中指定的未定義過的資源池。設定成false之後,任務中指定的未定義的資源池將無效,該任務會被分配到default資源池中。,default is True</description>
</property>
<!– scheduler end –>
2.1.2 fair-scheduler.xml
假設在生產環境Yarn中,總共有四類使用者需要使用叢集,production、spark、default、streaming。為了使其提交的任務不受影響,我們在Yarn上規劃配置了四個資源池,分別為production,spark,default,streaming。並根據實際業務情況,為每個資源池分配了相應的資源及優先順序等,default用於開發測試目的.
ResourceManager上fair-scheduler.xml配置如下:
<?xml version="1.0"?>
<allocations>
<queue name="root">
<aclSubmitApps></aclSubmitApps>
<aclAdministerApps></aclAdministerApps>
<queue name="production">
<minResources>8192mb,8vcores</minResources>
<maxResources>419840mb,125vcores</maxResources>
<maxRunningApps>60</maxRunningApps>
<schedulingMode>fair</schedulingMode>
<weight>7.5</weight>
<aclSubmitApps>*</aclSubmitApps>
<aclAdministerApps>production</aclAdministerApps>
</queue>
<queue name="spark">
<minResources>8192mb,8vcores</minResources>
<maxResources>376480mb,110vcores</maxResources>
<maxRunningApps>50</maxRunningApps>
<schedulingMode>fair</schedulingMode>
<weight>1</weight>
<aclSubmitApps>*</aclSubmitApps>
<aclAdministerApps>spark</aclAdministerApps>
</queue>
<queue name="default">
<minResources>8192mb,8vcores</minResources>
<maxResources>202400mb,20vcores</maxResources>
<maxRunningApps>20</maxRunningApps>
<schedulingMode>FIFO</schedulingMode>
<weight>0.5</weight>
<aclSubmitApps>*</aclSubmitApps>
<aclAdministerApps>*</aclAdministerApps>
</queue>
<queue name="streaming">
<minResources>8192mb,8vcores</minResources>
<maxResources>69120mb,16vcores</maxResources>
<maxRunningApps>20</maxRunningApps>
<schedulingMode>fair</schedulingMode>
<aclSubmitApps>*</aclSubmitApps>
<weight>1</weight>
<aclAdministerApps>streaming</aclAdministerApps>
</queue>
</queue>
<user name="production">
<!-- 對於特定使用者的配置:production最多可以同時執行的任務 -->
<maxRunningApps>100</maxRunningApps>
</user>
<user name="default">
<!-- 對於預設使用者配置最多可以同時執行的任務 -->
<maxRunningApps>10</maxRunningApps>
</user>
<!-- users max running apps -->
<userMaxAppsDefault>50</userMaxAppsDefault>
<!--預設的使用者最多可以同時執行的任務 -->
<queuePlacementPolicy>
<rule name="specified"/>
<rule name="primaryGroup" create="false" />
<rule name="secondaryGroupExistingQueue" create="false" />
<rule name="default" queue="default"/>
</queuePlacementPolicy>
</allocations>
引數介紹:
- minResources:最少資源保證量,設定格式為“X mb, Y vcores”,當一個佇列的最少資源保證量未滿足時,它將優先於其他同級佇列獲得資源,對於不同的排程策略(後面會詳細介紹),最少資源保證量的含義不同,對於fair策略,則只考慮記憶體資源,即如果一個佇列使用的記憶體資源超過了它的最少資源量,則認為它已得到了滿足;對於drf策略,則考慮主資源使用的資源量,即如果一個佇列的主資源量超過它的最少資源量,則認為它已得到了滿足。
- maxResources:最多可以使用的資源量,fair scheduler會保證每個佇列使用的資源量不會超過該佇列的最多可使用資源量。
- maxRunningApps:最多同時執行的應用程式數目。通過限制該數目,可防止超量Map Task同時執行時產生的中間輸出結果撐爆磁碟。
- weight:資源池權重,主要用在資源共享之時,weight越大,拿到的資源越多。比如一個pool中有20GB記憶體用不了,這時候可以共享給其他pool,其他每個pool拿多少,就是由權重決定的
- aclSubmitApps:可向佇列中提交應用程式的Linux使用者或使用者組列表,預設情況下為“*”,表示任何使用者均可以向該佇列提交應用程式。需要注意的是,該屬性具有繼承性,即子佇列的列表會繼承父佇列的列表。配置該屬性時,使用者之間或使用者組之間用“,”分割,使用者和使用者組之間用空格分割,比如“user1, user2 group1,group2”。
aclAdministerApps:允許管理任務的使用者名稱和組;一個佇列的管理員可管理該佇列中的資源和應用程式,比如可殺死任意應用程式。 - minSharePreemptionTimeout :最小共享量搶佔時間。如果一個資源池在該時間內使用的資源量一直低於最小資源量,則開始搶佔資源。
- schedulingMode/schedulingPolicy:佇列採用的排程模式,可以是fifo、fair或者drf。
管理員也可為單個使用者新增maxRunningJobs屬性限制其最多同時執行的應用程式數目。此外,管理員也可通過以下引數設定以上屬性的預設值: - userMaxJobsDefault:使用者的maxRunningJobs屬性的預設值。
- defaultMinSharePreemptionTimeout :佇列的minSharePreemptionTimeout屬性的預設值。
- defaultPoolSchedulingMode:佇列的schedulingMode屬性的預設值。
- fairSharePreemptionTimeout:公平共享量搶佔時間。如果一個資源池在該時間內使用資源量一直低於公平共享量的一半,則開始搶佔資源。
這樣,每個使用者組下的使用者提交任務時候,會到相應的資源池中,而不影響其他業務。佇列的層次是通過巢狀元素實現的。所有的佇列都是root佇列的孩子,即使沒有配到元素裡。Fair排程器中的佇列有一個權重屬性(這個權重就是對公平的定義),並把這個屬性作為公平排程的依據。在這個例子中,當排程器分配叢集7.5,1,1,0.5資源給production,spark,streaming,default時便視作公平,這裡的權重並不是百分比。注意,對於在沒有配置檔案時按使用者自動建立的佇列,它們仍有權重並且權重值為1。每個佇列內部仍可以有不同的排程策略。佇列的預設排程策略可以通過頂級元素進行配置,如果沒有配置,預設採用公平排程。儘管是Fair排程器,其仍支援在佇列級別進行FIFO排程。每個佇列的排程策略可以被其內部的 元素覆蓋,在上面這個例子中,default佇列就被指定採用fifo進行排程,所以,對於提交到default佇列的任務就可以按照FIFO規則順序的執行了。需要注意,spark,production,streaming,default之間的排程仍然是公平排程。每個佇列可配置最大、最小資源佔用數和最大可執行的應用的數量。
Fair排程器採用了一套基於規則的系統來確定應用應該放到哪個佇列。在上面的例子中, 元素定義了一個規則列表,其中的每個規則會被逐個嘗試直到匹配成功。例如,上例第一個規則specified,則會把應用放到它指定的佇列中,若這個應用沒有指定佇列名或佇列名不存在,則說明不匹配這個規則,然後嘗試下一個規則。primaryGroup規則會嘗試把應用放在以使用者所在的Unix組名命名的佇列中,如果沒有這個佇列,不建立佇列轉而嘗試下一個規則。當前面所有規則不滿足時,則觸發default規則,把應用放在default佇列中。
當然,我們可以不配置queuePlacementPolicy規則,排程器則預設採用如下規則:
<queuePlacementPolicy>
<rule name="specified" />
<rule name="user" />
</queuePlacementPolicy>
上面規則意思是除非佇列被準確的定義,否則會以使用者名稱為佇列名建立佇列。還有一個簡單的配置策略可以使得所有的應用放入同一個佇列(default),這樣就可以讓所有應用之間平等共享叢集而不是在使用者之間。這個配置的定義如下:
<queuePlacementPolicy>
<rule name="default" />
</queuePlacementPolicy>
實現上面功能我們還可以不使用配置檔案,直接設定yarn.scheduler.fair.user-as-default-queue=false,這樣應用便會被放入default 佇列,而不是各個使用者名稱佇列。另外,我們還可以設定yarn.scheduler.fair.allow-undeclared-pools=false,這樣使用者就無法建立隊列了。
當一個job提交到一個繁忙叢集中的空佇列時,job並不會馬上執行,而是阻塞直到正在執行的job釋放系統資源。為了使提交job的執行時間更具預測性(可以設定等待的超時時間),Fair排程器支援搶佔。搶佔就是允許排程器殺掉佔用超過其應占份額資源佇列的containers,這些containers資源便可被分配到應該享有這些份額資源的佇列中。需要注意搶佔會降低叢集的執行效率,因為被終止的containers需要被重新執行。可以通過設定一個全域性的引數yarn.scheduler.fair.preemption=true來啟用搶佔功能。此外,還有兩個引數用來控制搶佔的過期時間(這兩個引數預設沒有配置,需要至少配置一個來允許搶佔Container):
minSharePreemptionTimeout
fairSharePreemptionTimeout
如果佇列在minimum share preemption timeout指定的時間內未獲得最小的資源保障,排程器就會搶佔containers。我們可以通過配置檔案中的頂級元素為所有佇列配置這個超時時間;我們還可以在元素內配置元素來為某個佇列指定超時時間。
與之類似,如果佇列在fair share preemption timeout指定時間內未獲得平等的資源的一半(這個比例可以配置),排程器則會進行搶佔containers。這個超時時間可以通過頂級元素和元素級元素分別配置所有佇列和某個佇列的超時時間。上面提到的比例可以通過(配置所有佇列)和(配置某個佇列)進行配置,預設是0.5。
需要注意的是,所有客戶端提交任務的使用者和使用者組的對應關係,需要維護在ResourceManager上,ResourceManager在分配資源池時候,是從ResourceManager上讀取使用者和使用者組的對應關係的,否則就會被分配到default資源池。在日誌中出現”UserGroupInformation: No groups available for user”類似的警告。而客戶端機器上的使用者對應的使用者組無關緊要。
每次在ResourceManager上新增使用者或者調整資源池配額後,需要執行下面的命令重新整理使其生效.
yarn rmadmin -refreshQueues
yarn rmadmin -refreshUserToGroupsMappings
動態更新只支援修改資源池配額,如果是新增或減少資源池,則需要重啟Yarn叢集.
Fair Scheduer各資源池配置及使用情況,在ResourceManager的WEB監控頁面上也可以看到: http://ResourceManagerHost:8088/cluster/scheduler
2.2 Capacity Scheduler配置(預設配置)
hadoop2.7預設使用的是Capacity Scheduler容量排程器
yarn-site.xml
<property>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.capacity.CapacityScheduler</value>
</property>
Capacity 排程器允許多個組織共享整個叢集,每個組織可以獲得叢集的一部分計算能力。通過為每個組織分配專門的佇列,然後再為每個佇列分配一定的叢集資源,這樣整個叢集就可以通過設定多個佇列的方式給多個組織提供服務了。除此之外,佇列內部又可以垂直劃分,這樣一個組織內部的多個成員就可以共享這個佇列資源了,在一個佇列內部,資源的排程是採用的是先進先出(FIFO)策略。
一個job可能使用不了整個佇列的資源。然而如果這個佇列中執行多個job,如果這個佇列的資源夠用,那麼就分配給這些job,如果這個佇列的資源不夠用了呢?其實Capacity排程器仍可能分配額外的資源給這個佇列,這就是“彈性佇列”(queue elasticity)的概念。
在正常的操作中,Capacity排程器不會強制釋放Container,當一個佇列資源不夠用時,這個佇列只能獲得其它佇列釋放後的Container資源。當然,我們可以為佇列設定一個最大資源使用量,以免這個佇列過多的佔用空閒資源,導致其它佇列無法使用這些空閒資源,這就是”彈性佇列”需要權衡的地方。
假設我們有如下層次的佇列:
root
├── prod
└── dev
├── eng
└── science
下面是一個簡單的Capacity排程器的配置檔案,檔名為capacity-scheduler.xml。在這個配置中,在root佇列下面定義了兩個子佇列prod和dev,分別佔40%和60%的容量。需要注意,一個佇列的配置是通過屬性yarn.sheduler.capacity..指定的,代表的是佇列的繼承樹,如root.prod佇列,一般指capacity和maximum-capacity。
<?xml version="1.0"?>
<configuration>
<property>
<name>yarn.scheduler.capacity.root.queues(/&eae)
<value>prod,dev</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.queues</tta*e>
<value>eng,science</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.prod.capacity</name>
<value>40</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.capacity</name>
<value >60</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.maximuin-capacity</name>
<value>75</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.eng.capacity</name>
<value >50</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.science.capacity</name>
<value >50</value>
</property>
</configuration>
我們可以看到,dev佇列又被分成了eng和science兩個相同容量的子佇列。dev的maximum-capacity屬性被設定成了75%,所以即使prod佇列完全空閒dev也不會佔用全部叢集資源,也就是說,prod佇列仍有25%的可用資源用來應急。我們注意到,eng和science兩個佇列沒有設定maximum-capacity屬性,也就是說eng或science佇列中的job可能會用到整個dev佇列的所有資源(最多為叢集的75%)。而類似的,prod由於沒有設定maximum-capacity屬性,它有可能會佔用叢集全部資源。Capacity容器除了可以配置佇列及其容量外,我們還可以配置一個使用者或應用可以分配的最大資源數量、可以同時執行多少應用、佇列的ACL認證等。
關於佇列的設定,這取決於我們具體的應用。比如,在MapReduce中,我們可以通過mapreduce.job.queuename屬性指定要用的佇列。如果佇列不存在,我們在提交任務時就會收到錯誤。如果我們沒有定義任何佇列,所有的應用將會放在一個default佇列中。
注意:對於Capacity排程器,我們的佇列名必須是佇列樹中的最後一部分,如果我們使用佇列樹則不會被識別。比如,在上面配置中,我們使用prod和eng作為佇列名是可以的,但是如果我們用root.dev.eng或者dev.eng是無效的。
2.3 FIFO Scheduler
yarn-site.xml
檔案
<property>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.fifo.FifoScheduler</value>
</property>
關注公眾號:Java大資料與資料倉庫,領取資料,學習大資料技術。