天天看點

Yarn 排程器Scheduler詳解

理想情況下,我們應用對yarn資源的請求應該立刻得到滿足,但現實情況資源往往是有限的,特别是在一個很繁忙的叢集,一個應用資源的請求經常需要等待一段時間才能的到相應的資源。在yarn中,負責給應用配置設定資源的就是scheduler。其實排程本身就是一個難題,很難找到一個完美的政策可以解決所有的應用場景。為此,yarn提供了多種排程器和可配置的政策供我們選擇。

在yarn中有三種排程器可以選擇:<code>fifo scheduler</code> ,<code>capacity scheduler</code>,<code>fairs cheduler</code>。

<code>fifo scheduler</code>把應用按送出的順序排成一個隊列,這是一個先進先出隊列,在進行資源配置設定的時候,先給隊列中最頭上的應用進行配置設定資源,待最頭上的應用需求滿足後再給下一個配置設定,以此類推。

<code>fifo scheduler</code>是最簡單也是最容易了解的排程器,也不需要任何配置,但它并不适用于共享叢集。大的應用可能會占用所有叢集資源,這就導緻其它應用被阻塞。在共享叢集中,更适合采用<code>capacity scheduler</code>或<code>fair scheduler</code>,這兩個排程器都允許大任務和小任務在送出的同時獲得一定的系統資源。

下面“yarn排程器對比圖”展示了這幾個排程器的差別,從圖中可以看出,在fifo 排程器中,小任務會被大任務阻塞。

而對于capacity排程器,有一個專門的隊列用來運作小任務,但是為小任務專門設定一個隊列會預先占用一定的叢集資源,這就導緻大任務的執行時間會落後于使用fifo排程器時的時間。

在fair排程器中,我們不需要預先占用一定的系統資源,fair排程器會為所有運作的job動态的調整系統資源。如下圖所示,當第一個大job送出時,隻有這一個job在運作,此時它獲得了所有叢集資源;當第二個小任務送出後,fair排程器會配置設定一半資源給這個小任務,讓這兩個任務公平的共享叢集資源。

需要注意的是,在下圖fair排程器中,從第二個任務送出到獲得資源會有一定的延遲,因為它需要等待第一個任務釋放占用的container。小任務執行完成之後也會釋放自己占用的資源,大任務又獲得了全部的系統資源。最終的效果就是fair排程器即得到了高的資源使用率又能保證小任務及時完成。

yarn排程器對比圖:

Yarn 排程器Scheduler詳解

capacity 排程器允許多個組織共享整個叢集,每個組織可以獲得叢集的一部分計算能力。通過為每個組織配置設定專門的隊列,然後再為每個隊列配置設定一定的叢集資源,這樣整個叢集就可以通過設定多個隊列的方式給多個組織提供服務了。除此之外,隊列内部又可以垂直劃分,這樣一個組織内部的多個成員就可以共享這個隊列資源了,在一個隊列内部,資源的排程是采用的是先進先出(fifo)政策。

通過上面那幅圖,我們已經知道一個job可能使用不了整個隊列的資源。然而如果這個隊列中運作多個job,如果這個隊列的資源夠用,那麼就配置設定給這些job,如果這個隊列的資源不夠用了呢?其實capacity排程器仍可能配置設定額外的資源給這個隊列,這就是“彈性隊列”(queue elasticity)的概念。

在正常的操作中,capacity排程器不會強制釋放container,當一個隊列資源不夠用時,這個隊列隻能獲得其它隊列釋放後的container資源。當然,我們可以為隊列設定一個最大資源使用量,以免這個隊列過多的占用空閑資源,導緻其它隊列無法使用這些空閑資源,這就是”彈性隊列”需要權衡的地方。

假設我們有如下層次的隊列:

下面是一個簡單的capacity排程器的配置檔案,檔案名為<code>capacity-scheduler.xml</code>。在這個配置中,在root隊列下面定義了兩個子隊列<code>prod</code>和<code>dev</code>,分别占40%和60%的容量。需要注意,一個隊列的配置是通過屬性<code>yarn.sheduler.capacity.&lt;queue-path&gt;.&lt;sub-property&gt;</code>指定的,<code>&lt;queue-path&gt;</code>代表的是隊列的繼承樹,如<code>root.prod</code>隊列,<code>&lt;sub-property&gt;</code>一般指<code>capacity</code>和<code>maximum-capacity</code>。

Yarn 排程器Scheduler詳解

我們可以看到,<code>dev</code>隊列又被分成了<code>eng</code>和<code>science</code>兩個相同容量的子隊列。<code>dev</code>的<code>maximum-capacity</code>屬性被設定成了75%,是以即使<code>prod</code>隊列完全空閑<code>dev</code>也不會占用全部叢集資源,也就是說,<code>prod</code>隊列仍有25%的可用資源用來應急。我們注意到,<code>eng</code>和<code>science</code>兩個隊列沒有設定<code>maximum-capacity</code>屬性,也就是說<code>eng</code>或<code>science</code>隊列中的job可能會用到整個<code>dev</code>隊列的所有資源(最多為叢集的75%)。而類似的,<code>prod</code>由于沒有設定maximum-capacity屬性,它有可能會占用叢集全部資源。

capacity容器除了可以配置隊列及其容量外,我們還可以配置一個使用者或應用可以配置設定的最大資源數量、可以同時運作多少應用、隊列的acl認證等。

關于隊列的設定,這取決于我們具體的應用。比如,在mapreduce中,我們可以通過<code>mapreduce.job.queuename</code>屬性指定要用的隊列。如果隊列不存在,我們在送出任務時就會收到錯誤。如果我們沒有定義任何隊列,所有的應用将會放在一個<code>default</code>隊列中。

注意:對于capacity排程器,我們的隊列名必須是隊列樹中的最後一部分,如果我們使用隊列樹則不會被識别。比如,在上面配置中,我們使用<code>prod</code>和<code>eng</code>作為隊列名是可以的,但是如果我們用<code>root.dev.eng</code>或者<code>dev.eng</code>是無效的。

fair排程器的設計目标是為所有的應用配置設定公平的資源(對公平的定義可以通過參數來設定)。在上面的“yarn排程器對比圖”展示了一個隊列中兩個應用的公平排程;當然,公平排程在也可以在多個隊列間工作。舉個例子,假設有兩個使用者a和b,他們分别擁有一個隊列。當a啟動一個job而b沒有任務時,a會獲得全部叢集資源;當b啟動一個job後,a的job會繼續運作,不過一會兒之後兩個任務會各自獲得一半的叢集資源。如果此時b再啟動第二個job并且其它job還在運作,則它将會和b的第一個job共享b這個隊列的資源,也就是b的兩個job會用于四分之一的叢集資源,而a的job仍然用于叢集一半的資源,結果就是資源最終在兩個使用者之間平等的共享。過程如下圖所示:

Yarn 排程器Scheduler詳解

排程器的使用是通過<code>yarn-site.xml</code>配置檔案中的<code>yarn.resourcemanager.scheduler.class</code>參數進行配置的,預設采用capacity scheduler排程器。如果我們要使用fair排程器,需要在這個參數上配置fairscheduler類的全限定名: <code>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.fairscheduler</code>。

fair排程器的配置檔案位于類路徑下的<code>fair-scheduler.xml</code>檔案中,這個路徑可以通過<code>yarn.scheduler.fair.allocation.file</code>屬性進行修改。若沒有這個配置檔案,fair排程器采用的配置設定政策,這個政策和3.1節介紹的類似:排程器會在使用者送出第一個應用時為其自動建立一個隊列,隊列的名字就是使用者名,所有的應用都會被配置設定到相應的使用者隊列中。

我們可以在配置檔案中配置每一個隊列,并且可以像capacity 排程器一樣分層次配置隊列。比如,參考<code>capacity-scheduler.xml</code>來配置fair-scheduler:

Yarn 排程器Scheduler詳解

隊列的層次是通過嵌套<code>&lt;queue&gt;</code>元素實作的。所有的隊列都是<code>root</code>隊列的孩子,即使我們沒有配到<code>&lt;root&gt;</code>元素裡。在這個配置中,我們把<code>dev</code>隊列有分成了<code>eng</code>和<code>science</code>兩個隊列。

fair排程器中的隊列有一個權重屬性(這個權重就是對公平的定義),并把這個屬性作為公平排程的依據。在這個例子中,當排程器配置設定叢集<code>40:60</code>資源給<code>prod</code>和<code>dev</code>時便視作公平,<code>eng</code>和<code>science</code>隊列沒有定義權重,則會被平均配置設定。這裡的權重并不是百分比,我們把上面的40和60分别替換成2和3,效果也是一樣的。注意,對于在沒有配置檔案時按使用者自動建立的隊列,它們仍有權重并且權重值為1。

每個隊列内部仍可以有不同的排程政策。隊列的預設排程政策可以通過頂級元素<code>&lt;defaultqueueschedulingpolicy&gt;</code>進行配置,如果沒有配置,預設采用公平排程。

盡管是fair排程器,其仍支援在隊列級别進行fifo排程。每個隊列的排程政策可以被其内部的<code>&lt;schedulingpolicy&gt;</code> 元素覆寫,在上面這個例子中,<code>prod</code>隊列就被指定采用fifo進行排程,是以,對于送出到<code>prod</code>隊列的任務就可以按照fifo規則順序的執行了。需要注意,<code>prod</code>和<code>dev</code>之間的排程仍然是公平排程,同樣<code>eng</code>和<code>science</code>也是公平排程。

盡管上面的配置中沒有展示,每個隊列仍可配置最大、最小資源占用數和最大可運作的應用的數量。

fair排程器采用了一套基于規則的系統來确定應用應該放到哪個隊列。在上面的例子中,<code>&lt;queueplacementpolicy&gt;</code> 元素定義了一個規則清單,其中的每個規則會被逐個嘗試直到比對成功。例如,上例第一個規則<code>specified</code>,則會把應用放到它指定的隊列中,若這個應用沒有指定隊列名或隊列名不存在,則說明不比對這個規則,然後嘗試下一個規則。<code>primarygroup</code>規則會嘗試把應用放在以使用者所在的unix組名命名的隊列中,如果沒有這個隊列,不建立隊列轉而嘗試下一個規則。目前面所有規則不滿足時,則觸發<code>default</code>規則,把應用放在<code>dev.eng</code>隊列中。

當然,我們可以不配置<code>queueplacementpolicy</code>規則,排程器則預設采用如下規則:

上面規則可以歸結成一句話,除非隊列被準确的定義,否則會以使用者名為隊列名建立隊列。

還有一個簡單的配置政策可以使得所有的應用放入同一個隊列(default),這樣就可以讓所有應用之間平等共享叢集而不是在使用者之間。這個配置的定義如下:

實作上面功能我們還可以不使用配置檔案,直接設定<code>yarn.scheduler.fair.user-as-default-queue=false</code>,這樣應用便會被放入default 隊列,而不是各個使用者名隊列。另外,我們還可以設定<code>yarn.scheduler.fair.allow-undeclared-pools=false</code>,這樣使用者就無法建立隊列了。

當一個job送出到一個繁忙叢集中的空隊列時,job并不會馬上執行,而是阻塞直到正在運作的job釋放系統資源。為了使送出job的執行時間更具預測性(可以設定等待的逾時時間),fair排程器支援搶占。

搶占就是允許排程器殺掉占用超過其應占份額資源隊列的containers,這些containers資源便可被配置設定到應該享有這些份額資源的隊列中。需要注意搶占會降低叢集的執行效率,因為被終止的containers需要被重新執行。

可以通過設定一個全局的參數<code>yarn.scheduler.fair.preemption=true</code>來啟用搶占功能。此外,還有兩個參數用來控制搶占的過期時間(這兩個參數預設沒有配置,需要至少配置一個來允許搶占container):

如果隊列在<code>minimum share preemption timeout</code>指定的時間内未獲得最小的資源保障,排程器就會搶占containers。我們可以通過配置檔案中的頂級元素<code>&lt;defaultminsharepreemptiontimeout&gt;</code>為所有隊列配置這個逾時時間;我們還可以在<code>&lt;queue&gt;</code>元素内配置<code>&lt;minsharepreemptiontimeout&gt;</code>元素來為某個隊列指定逾時時間。

與之類似,如果隊列在<code>fair share preemption timeout</code>指定時間内未獲得平等的資源的一半(這個比例可以配置),排程器則會進行搶占containers。這個逾時時間可以通過頂級元素<code>&lt;defaultfairsharepreemptiontimeout&gt;</code>和元素級元素<code>&lt;fairsharepreemptiontimeout&gt;</code>分别配置所有隊列和某個隊列的逾時時間。上面提到的比例可以通過<code>&lt;defaultfairsharepreemptionthreshold&gt;</code>(配置所有隊列)和<code>&lt;fairsharepreemptionthreshold&gt;</code>(配置某個隊列)進行配置,預設是0.5。

yarn相關的其它文章:

<a href="http://blog.csdn.net/suifeng3051/article/details/49486927">hadoop yarn詳解</a>

<a href="http://blog.csdn.net/suifeng3051/article/details/48135521">yarn 記憶體配置設定管理機制及相關參數配置</a>

繼續閱讀