Yarn排程佇列
1 概述
在Yarn中,負責給應用分配資源的是Scheduler,並提供了多種排程器和可配置的策略供選擇。
在Yarn中有是三種排程器可以選擇:FIFO Scheduler,Capacity Scheduler,Fair Scheduler。
FIFO Scheduler把應用按提交的順序排成一個佇列,這是一個先進先出佇列,在進行資源分配的時候,先給佇列中最頭上的應用分配資源,待最頭上的應用需求滿足後再給下一個分配,以此類推。
FIFO Scheduler是最簡單也是最容易理解的排程器,不需要任何配置,但其不適用於共享叢集。大的應用可能會佔用所有叢集資源,這就導致其它應用被阻塞。在共享叢集中,更適合採用Capacity Scheduler或Fair Scheduler,這兩種排程器都允許大任務和小任務在提交的同時獲得一定的資源。
下面 Yarn排程器對比圖 展示了這幾個排程器的區別,從圖中可以看出,在FIFO排程器中,小任務會被大任務阻塞。
而對於Capacity排程器,有一個專門的佇列用來執行小任務,但是為小任務專門設定一個佇列會佔用一定的叢集資源,這就導致大任務的執行時間會落後於使用FIFO排程器時的時間。
在Fair排程器中,我們不需要預先佔用一定的系統資源,Fair排程器會為所有執行的job動態的調整系統資源。如下圖所示,當第一個大job提交時,只有這一個job在執行,此時它獲得了所有叢集資源;當第二個小任務提交後,Fair排程器會分配一半資源給這個小任務,讓這兩個任務公平的共享叢集資源。
需要注意的是,在下圖Fair排程器中,從第二個任務提交到獲得資源會有一定的延遲,因為它需要等待第一個任務釋放佔用的Container。小任務執行完成以後也會釋放自己佔用的資源,大任務又獲得了全部的系統資源。最終的效果就是Fair排程器既得到了高資源的利用率又能保證小任務的及時執行。

Yarn排程器對比.png
2 Capacity Scheduler 的配置
2.1 介紹
Capacity 排程器允許多個組織共享整個叢集,每個組織可以獲得叢集的一部分計算能力。通過為每個組織分配專門的佇列,然後再為每個佇列分配一定的叢集資源,這樣整個叢集就可以通過設定多個佇列的方式給多個組織提供服務了。除此之外,佇列內部又可以垂直劃分,這樣一個組織內部的多個成員就可以共享這個佇列資源了,在一個佇列內部,資源的排程是採用的是先進先出(FIFO)策略。
通過上面那幅圖,我們已經知道一個job可能使用不了整個佇列的資源。然而如果這個佇列中執行多個job,如果這個佇列的資源夠用,那麼就分配給這些job,如果這個佇列的資源不夠用了呢?其實Capacity排程器仍可能分配額外的資源給這個佇列,這就是“彈性佇列”(queue elasticity)的概念。
在正常的操作中,Capacity排程器不會強制釋放Container,當一個佇列資源不夠用時,這個佇列只能獲得其它佇列釋放後的Container資源。當然,我們可以為佇列設定一個最大資源使用量,以免這個佇列過多的佔用空閒資源,導致其它佇列無法使用這些空閒資源,這就是”彈性佇列”需要權衡的地方。
2.2 CS配置
該排程器預定義了一個root佇列,所有隊裡都是該佇列的子佇列。
<property> <name>yarn.scheduler.capacity.root.queues</name> <value>a,b,c</value> <description>The queues at the this level (root is the root queue). </description> </property> <property> <name>yarn.scheduler.capacity.root.a.queues</name> <value>a1,a2</value> <description>The queues at the this level (root is the root queue). </description> </property> <property> <name>yarn.scheduler.capacity.root.b.queues</name> <value>b1,b2,b3</value> <description>The queues at the this level (root is the root queue). </description> </property>
在配置root下面的子佇列時使用逗號隔開,同時在定義層級佇列時使用叫做 queue path 來表明,如 yarn.scheduler.capacity.root.a.queues 。各個子佇列都可以使用百分比來表示佔用父佇列資源的比例,如未配置,則表示可以佔用到父佇列資源的全部資源。同時還可以配置一個使用者可以分配的最大資源數、可以同時執行多少個應用等。
排程器中的配置修改後可以使用admin進行動態重新整理。
3 Fair Scheduler
Fair排程器的設計目標是為所有的應用分配公平的資源(對公平的定義可以通過引數來設定),使用者在各自佇列執行中逐漸資源變得平分。
3.1 佇列配置
Fair排程器的配置檔案位於類路徑下的fair-scheduler.xml檔案中,這個路徑可以通過yarn.scheduler.fair.allocation.file屬性進行修改。若沒有這個配置檔案,Fair排程器採用的分配策略,排程器會在使用者提交第一個應用時為其自動建立一個佇列,佇列的名字就是使用者名稱,所有的應用都會被分配到相應的使用者佇列中。
我們可以在配置檔案中配置每一個佇列,並且可以像Capacity 排程器一樣分層次配置佇列。比如,參考capacity-scheduler.xml來配置fair-scheduler:

FS配置示例.png
佇列的層次是通過巢狀<queue>元素實現的。所有的佇列都是root佇列的孩子,即使我們沒有配到<root>元素裡。在這個配置中,我們把dev佇列有分成了eng和science兩個佇列。
Fair排程器中的佇列有一個權重屬性(這個權重就是對公平的定義),並把這個屬性作為公平排程的依據。在這個例子中,當排程器分配叢集40:60資源給prod和dev時便視作公平,eng和science佇列沒有定義權重,則會被平均分配。這裡的權重並不是百分比,我們把上面的40和60分別替換成2和3,效果也是一樣的。注意,對於在沒有配置檔案時按使用者自動建立的佇列,它們仍有權重並且權重值為1。
每個佇列內部仍可以有不同的排程策略。佇列的預設排程策略可以通過頂級元素<defaultQueueSchedulingPolicy>進行配置,如果沒有配置,預設採用公平排程。
儘管是Fair排程器,其仍支援在佇列級別進行FIFO排程。每個佇列的排程策略可以被其內部的<schedulingPolicy> 元素覆蓋,在上面這個例子中,prod佇列就被指定採用FIFO進行排程,所以,對於提交到prod佇列的任務就可以按照FIFO規則順序的執行了。需要注意,prod和dev之間的排程仍然是公平排程,同樣eng和science也是公平排程。
同時Fair排程器採用了一套基於規則的系統來確定應用應該放到哪個佇列。在上面的例子中,<queuePlacementPolicy> 元素定義了一個規則列表,其中的每個規則會被逐個嘗試直到匹配成功。例如,上例第一個規則specified,則會把應用放到它指定的佇列中,若這個應用沒有指定佇列名或佇列名不存在,則說明不匹配這個規則,然後嘗試下一個規則。primaryGroup規則會嘗試把應用放在以使用者所在的Unix組名命名的佇列中,如果沒有這個佇列,不建立佇列轉而嘗試下一個規則。當前面所有規則不滿足時,則觸發default規則,把應用放在dev.eng佇列中。
上面規則可以歸結成一句話,除非佇列被準確的定義,否則會以使用者名稱為佇列名建立佇列,還有一個簡單的配置策略可以使得所有的應用放入同一個佇列(default),這樣就可以讓所有應用之間平等共享叢集而不是在使用者之間。直接設定yarn.scheduler.fair.user-as-default-queue=false,這樣應用便會被放入default 佇列,而不是各個使用者名稱佇列。另外,我們還可以設定yarn.scheduler.fair.allow-undeclared-pools=false,這樣使用者就無法建立隊列了。
儘管上面的配置中沒有展示,每個佇列仍可配置最大、最小資源佔用數和最大可執行的應用的數量。如下:
<?xml version="1.0"?> <allocations> <queue name="sample_queue"> <minResources>10000 mb,0vcores</minResources> <maxResources>90000 mb,0vcores</maxResources> <maxRunningApps>50</maxRunningApps> <maxAMShare>0.1</maxAMShare> <weight>2.0</weight> <schedulingPolicy>fair</schedulingPolicy> <queue name="sample_sub_queue"> <aclSubmitApps>charlie</aclSubmitApps> <minResources>5000 mb,0vcores</minResources> </queue> <queue name="sample_reservable_queue"> <reservation></reservation> </queue> </queue> <queueMaxAMShareDefault>0.5</queueMaxAMShareDefault> <queueMaxResourcesDefault>40000 mb,0vcores</queueMaxResourcesDefault> <!-- Queue 'secondary_group_queue' is a parent queue and may have user queues under it --> <queue name="secondary_group_queue" type="parent"> <weight>3.0</weight> <maxChildResources>4096 mb,4vcores</maxChildResources> </queue> <user name="sample_user"> <maxRunningApps>30</maxRunningApps> </user> <userMaxAppsDefault>5</userMaxAppsDefault> <queuePlacementPolicy> <rule name="specified" /> <rule name="primaryGroup" create="false" /> <rule name="nestedUserQueue"> <rule name="secondaryGroupExistingQueue" create="false" /> </rule> <rule name="default" queue="sample_queue"/> </queuePlacementPolicy> </allocations>
3.2 搶佔
當一個job提交到一個繁忙叢集中的空佇列時,job並不會馬上執行,而是阻塞直到正在執行的job釋放系統資源。為了使提交job的執行時間更具預測性(可以設定等待的超時時間),Fair排程器支援搶佔。
搶佔就是允許排程器殺掉佔用超過其應占份額資源佇列的containers,這些containers資源便可被分配到應該享有這些份額資源的佇列中。需要注意搶佔會降低叢集的執行效率,因為被終止的containers需要被重新執行。
可以通過設定一個全域性的引數yarn.scheduler.fair.preemption=true來啟用搶佔功能。此外,還有兩個引數用來控制搶佔的過期時間(這兩個引數預設沒有配置,需要至少配置一個來允許搶佔Container):
-minimum share preemption timeout -fair share preemption timeout
如果佇列在minimum share preemption timeout指定的時間內未獲得最小的資源保障,排程器就會搶佔containers。我們可以通過配置檔案中的頂級元素<defaultMinSharePreemptionTimeout>為所有佇列配置這個超時時間;我們還可以在<queue>元素內配置<minSharePreemptionTimeout>元素來為某個佇列指定超時時間。
與之類似,如果佇列在fair share preemption timeout指定時間內未獲得平等的資源的一半(這個比例可以配置),排程器則會進行搶佔containers。這個超時時間可以通過頂級元素 <defaultFairSharePreemptionTimeout>
和元素級元素 <fairSharePreemptionTimeout>
分別配置所有佇列和某個佇列的超時時間。上面提到的比例可以通過 <defaultFairSharePreemptionThreshold>
(配置所有佇列)和 <fairSharePreemptionThreshold>
(配置某個佇列)進行配置,預設是0.5。