Apache YARN(Yet Another Resource Negotiator)是一個Hadoop集群資源管理系統。YARN是在Hadoop 2引入的,用以改善MapReduce的表現。但是它也足夠勝任其它的分布式計算框架。
YARN提供了一些能被請求調用的APIs,并處理集群資源。但是通常用戶不會直接調用這些APIs,而是調用由分布計算框架提供的更高級別的APIs。這些更高級別的APIs基于YARN建立,并對用戶隱藏了資源管理的細節。圖4-1說明了這個情景,并顯示了一些分布式計算框架(MapReduce,Spark等等)作為YARN應用位于集群計算層(YARN)和存儲層之上(HDFS和Hbase)。
圖4-1框架表示的應用層之上還有一層應用,如Pig,Hive和Crunch。它們都運行在MapReduce,Spark或Tez(或同時三者)之上,并不和YARN直接交互。
這一章節帶領大家過一遍YARN的特性,為理解第四部分章節的內容(包括一些分布式處理框架)打下基礎。
YARN應用運行分析
YARN通過兩種一直運行的守護進程來提供它的核心服務。一種是資源管理器(一個集群一個),管理集群中所有資源的使用,另一種是節點管理器,在所有節點上運行,啟動或監控容器。容器會使用分配的有限資源的集合(內存,CPU等)執行應用特定的進程。取決于YARN是如何配置的,容器可以是一個Unix進程,也可以是一個Linux cgroup(control groups)。圖4-2顯示了YARN怎么樣運行應用的。
為了運行基于YARN的應用,客戶端必須與資源管理器(resource manager)通信,請求它運行一個應用主進程(圖4-2步驟1)。資源管理器然后尋找能夠在容器中啟動這個應用主進程的節點管理器(步驟2a和2b)。應用啟動后,具體能夠做什么取決于應用本身。它可以在它所在的容器中簡單地執行一個計算然后將結果返回給客戶端。或者它可以向資源管理器請求更多的容器(步驟3),以便運行分布式計算(步驟4a和4b)。后者是MapReduce YARN應用所做的事,我們將會在"一個MapRedue作業運行分析"小節中詳細地學習。
從圖4-2我們注意到,YARN本身不提供任何方法讓應用各部分(客戶端,主進程,進程)間進行通信。大多數特殊的YARN應用使用遠程調用的形式(例如Hadoop的RPC),將更新的狀態和結果傳遞回客戶端,但是這不是正常情況。
資源請求
YARN對于資源請求的形式要求比較靈活。某個請求,請求多個容器,可以對每一個容器都指定需要的計算機硬件資源(內存,CPU等),并能夠指定位置限定的一些容器。
位置對于一些分布式的數據處理算法能夠充分高效地使用集群帶寬是很重要的。所以YARN允許應用指定它請求的容器的位置。位置限定可以指定位于某個特定的節點或機架,或者集群中任意位置(比如:不在機架上的)的容器。
有時,并不能夠滿足位置限定的條件,這種情況下,要未不分配任何位置,要未,選擇放寬限定條件。例如,指定了某個節點,但是不可能在這個節點上啟動容器(因為其它容器正在它上面運行),那么YARN將會嘗試啟動位于相同機架上的其它節點上的容器,或者其它節點也不可用時,就啟動集群中任意一個節點上的容器。
啟動一個容器處理HDFS塊(比方說,執行MapReduce中的一個map任務),通常情況下,應用會請求保存了塊三個復本的那個節點,或者保存了這些復本的機架中的某個節點,如果以上都失敗了,就選擇集群中任意一個節點上的容器。
一個YARN容器可以在它運行時的任意時間發起資源請求。例如,一個應用可以預先發起所需所有資源的請求,也可以以一種更加動態的途徑,即當應用有更改時,再動態地請求更多資源。
Spark采取了第一種途徑,在集群中啟動固定數量的執行器(“參看在YARN上的Spark ”章節)。另一方面,MapReduce會采取這兩種途徑。執行map任務時會預先請求所有容器,執行reduce任務的容器不會立即啟動,會在后面啟動。而且,如果有任何任務處理失敗了,將會請求額外的容器重新執行失敗的任務。
應用的生命周期
一個YARN應用的生命周期可以千差萬別,從幾秒的短命應用到可以運行數天甚至數月的長期應用。可行的應用歸類是根據應用與作業之間的映射關系而不是應用運行的時間來進行分類。最簡單的情況是每一個作業對應一個應用,MapReduce任務采取的就是這個途徑。
第二個模式是每一個工作流運行一個應用或多個作業(可能是不相關的作業)運行一個應用。這種途徑比第一個途徑更高效,因為應用容器可以被多個作業共用,也可以緩存多個作業產生的中間數據。Spark就是一個使用這種模式的例子。
第三個模式是被不同用戶共享的長生命周期應用。這種應用經常是以某種配合的角色發揮作用。例如Apache Slider就有一個長期運行的應用管理器,這個應用管理器作用是啟動集群中的其它應用。Impala通過這個途徑來提供一個代理應用,用于響應Impala實體機的資源請求。通過使用這種"一直運行"的應用管理器,用戶可以獲得低延遲響應,因為當用戶查詢時不需要啟動一個新的應用管理器了。
構建YARN應用
從頭開始寫一個YARN應用是相當復雜地,但是大多數情況不必要。因為可以使用一個已經存在的應用,進行調整以適應自己地需求。例如,如果你對有向無環圖(DAG)感興趣,那么Spark或者Tez是合適的,或者對流式處理感興趣,Spark,Samza或者Storm是合適的。
有很多工程用于簡化構建一個YARN應用時的操作。早先提到的Apache Slider讓現有的分布式應用運行在YARN上成為可能。用戶可以在集群上運行他們自己的應用(例如HBase)而不影響其它用戶,不同的用戶可以運行同一個應用不同的版本。Slider能夠改變應用運行的節點數量,掛起和恢復運行某個應用。
Apache Twill與Slider相似,但除了以上功能,另外還可以提供一個簡單的編程模型,可以開發基于YARN的分布式應用。Twill允許你定義實現了Java Runnable接口的集群進程,然后在集群的YARN容器中運行它們。Twill還提供實時日志(記錄可執行進程的事件以流形式返回客戶端)和命令消息(將客戶端的命令發送給可執行進程)。
當以上選擇都不能滿足要求時,例如需要開發一個能夠進行復雜時間調度的YARN應用。那么YARN工程中有一個分布式的shell應用可以做為如何開發YARN應用的例子,它演示了如何使用YARN APIs在客戶端、應用管理器與YARN守護進程之間交互通信。
YARN與MapReduce 1比較
在Hadoop最初版本(版本1或更早)中的MapReduce有時被稱為"MapReduce 1",以和MapReduce 2區分開。MapReduce 2是Hadoop 2或之后的版本,它使用了YARN。
有一件重要的事情,那就是舊的和新的MapReduce APIs與MapReduce1和MapReduce2并不是一回事。APIs是面向用戶,客戶端的,決定了你如何寫MapReduce程序(參看附錄D),然而MapReduce1和2僅僅是運行MapReduce程序不同的方法。舊的和新的MapReduce APIs都可以在MapReduce1和2中運行。
在MapReduce1中,有兩種控制作業執行過程的守護進程,一種是jobtracker,一種是一個或多個tasktracker。jobtracker組合系統中需要運行的所有作業,然后分配運行在tasktracker上的任務。Tasktracker執行任務,并將進度報告發送給jobtracker,jobtracker將會保存每一個作業的整個進度。如果一個任務失敗了,jobtracker將會在另一個tasktracker上啟動它。
在MapReduce1中,jobtracker既關心作業的調度(匹配tasktracker與task),又關心任務的進度(跟蹤任務,重啟失敗的任務,顯示任務,記錄任務,例如維護任務數)。相對地,在YARN中,這些責任由不同的實體處理:資源管理器和應用管理器(一個MapReduce作業一個應用管理器)。jobtracker還需要存儲已經完成的作業的歷史記錄。當然也可以單獨運行一個歷史記錄服務來給jobtracker減負。在YARN中,具有相同角色的是時間線服務,它存儲應用的歷史記錄。
在YARN應用中,與tasktracker等效的是節點管理器。MapReduce1與YARN的功能映射關系如表4-1所示:
MapReduce 1 | YARN |
---|---|
Jobtracker | 資源管理器,應用管理器,時間線服務 |
Tasktracker | 節點管理器 |
槽(Slot) | 容器 |
設計YARN的目的是解決MapReduce 1的一些局限性。使用YARN有如下好處:
擴展性
YARN可以運行在比MapReduce 1更大的集群上。當達到4000節點或4000個任務時,MapReduce 1就達到了瓶頸。因為jobtracker必須要管理作業和任務。YARN通過使用分開的資源管理與應用管理的結構克服了這個限制,YARN設計的目的是能擴展到10000個節點和100000個任務。高可用性
HA(High availability 高可用)是當正在服務的實體機故障時,通過復制所需的狀態和數據到另外一臺實體機上,執行所需的工作,繼續提供服務來實現的。然而jobtracker內存中大量快速地改變復雜的狀態(例如,每幾秒鐘每一個task狀態就會更新一次)使HA應用到jobtracker變得非常困難。
YARN通過將jobtracker的功能分解到資源管理器和應用管理器,使服務高度可用變成了一個可以分開克服的問題。那就是為資源管理器提供HA,然后為YARN應用(以每一個應用為基礎單位)提供HA。實際小,Hadoop 2支持MapReduce作業中的資源 管理器和應用管理器HA。YARN中的故障恢復將在第7章"故障"小節中詳細講解。實用性
在MapReduce 1中,每個tasktracker通過一個位置固定,大小固定的"槽"中配置,槽分為map槽和reduce槽。map槽只能用于運行map任務,相應的,reduce槽只能用于reduce任務。
在YARN中,一個節點管理器管理一個資源池,而不是數量固定的指定的槽。YARN上的運行的MapReduce不會出現由于集群中僅僅有map槽,reduce任務必須等待的情況。這種情況可能發生在MapReduce 1中.YARN中,如果運行任務時,資源可得,那么應用就應該能夠使用它們。
而且,YARN中的資源是精細化管理的,所以應用可以請求它所需要的資源,而不必請求一個槽。對于某些特殊的任務來說,槽太大的話,會造成資源浪費,太小的話,造成任務失敗。-
多用性
從某些方面來說,YARN最大的優勢是它使Hadoop能夠使用除了MapReduce其它類型的分布式應用。MapReduce僅僅是其中一個YARN應用。用戶甚至能夠在同一個集群中運行不同版本的MapReduce應用。這就使得升級MapReduce變得更加容易管理。(注意,MapReduce中的某些部分,例如作業歷史記錄服務器,shuffle處理器和YARN本身仍然需要整個集群一起升級。)
既然Hadoop 2被廣泛使用,而且是最新的穩定版本。這本書中剩余部分內容中"MapReduce"指的就是"MapReduce 2"。第7章將會詳細地講解MapReduce如何運行在YARN之上。
YARN中的調度計劃
理想情況下,一個YARN應用的請求應該立刻響應。然而,現實情況是,資源是有限的,而且集群繁忙時,應用經常需要等待直到它的部分請求得到滿足。YARN調度器的工作就是根據一些既定的規則給應用分配資源。調度通常是一個困難的問題,沒有一個最好的規則。這也就是為什么YARN提供調度器和可配置規則兩種選擇的原因。我們接下來詳細看看。
調度器
YARN中有三種調度器:FIFO調度器,容量調度器和公平調度器。FIFO調度器將應用放在一個隊列中,按照它們提交的順序運行它們(先進,先出)。隊列中第一個應用的請求首先滿足。一旦它的請求被滿足了之后,就服務隊列中下一個應用,依次類推。
FIFO的優點是容易理解,而且不需要配置。但是它不適合資源共享的集群。一般大的應用會用到集群中所有資源,如果使用FIFO,每一個應用必須要按序等待。在資源共享的集群中,最好使用容量調度器或者公平調度器。二者都會使那些運行時間長的作業能夠在合理時間內完成,而且也使得用戶在執行少量的臨時的并發查詢時,能夠在合理的時間內返回結果。
調度器之間的區別如圖4-3所示,我們可以看到,FIFO調度模式(i)下,小的作業必須要等待大的作業完成之后才能執行。
在容量調度模式(ii)下,一個分開的專用的隊列允許小的作業一提交就能夠執行。這是以整個集群的可利用空間為代價的,因為需要為這個專用隊列預留空間。這也意味著大的作業比使用FIFO調度完成的晚。
在公平調度模式(iii)下,不需要預留一定數量的空間。因為它會動態的平衡所有運行的作業所需的空間資源。第一個(大)作業啟動后(目前是集群中唯一運行的作業),它會獲取集群中所有的資源,當第二個(小)作業啟動后,它將把一半資源分配給第二個作業。這樣,每一個作業都能分到相同數量的資源。
注意到,第二個作業啟動到它接收到所分的資源有一定的延遲。因為必須等待資源從第一個作業使用的容器中釋放出來后才能使用。在小作業完成,并不再請求資源后,大的作業又將使用集群中所有的資源。這個模式造成集群的高占用空間和小作業及時的完成。
圖4-3對比了這三個調試器基本操作。接下來的兩部分,我們將學習容量和公平調度器中一些高級的配置。
容量調度器配置
容量調度器允許按照組織的行形式共享Hadoop集群資源,每一個組織都分配了總集群資源中的一部分資源。每一個組織都設一個專用的隊列。可以配置隊列使用集群中指定的部分資源。隊列也許可以進一步按層級劃分,使得每一個組織可以將它的資源分配給不同組的用戶。在隊列中,應用按照FIFO規則進行調度。
正如我們在圖4-3看到的那樣,單個作業不能使用超過它所在隊列容量的資源。然而,如果隊列中的作業超過一個,并且有空閑的資源,那么容量調度器也許會將剩余的資源分配給這個隊列中的作業,即使會超出隊列的容量(應分配的資源)[1],這就是所熟知的"彈性隊列"。
正常操作時,容量調度器不會強制地殺死作業來回收容器[2],所以如果一個隊列由于缺少請求而容量不夠,然后增加請求,如果其它隊列中作業完成,有資源從容器中釋放出來,隊列將會占用其它隊列的資源。通過配置隊列的最大容量可以限制隊列不占用其它隊列太多資源。但這是以隊列的彈性為代價,當然,通過不斷嘗試與錯誤,應該能找到一個合理的平衡點。
假設隊列層級如下面這樣:
示例4-1顯示了一個容量調度器配置文件,這個配置文件叫做capacity-scheduler.xml。對應于上面的層級,在root隊列下定義了兩個隊列,prod,dev,分別占40%和60%的資源。注意,可以通過屬性yarn.scheduler.capacity.<queue-path>.<sub-property> 來配置隊列特殊的屬性。<queue-path>是隊列的層級路徑(以點分隔),例如root.prod。
示例:4-1:容量調度器的基本配置文件
<?xml version="1.0"?>
<configuration>
<property>
<name>yarn.scheduler.capacity.root.queues</name>
<value>prod,dev</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.queues</name>
<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.maximum-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隊列。所以當prod隊列空閑的時候,dev隊列沒有使用集群所有的資源,它最大的使用資源設置為75%。換句話說,prod隊列總是有25%資源可以立即使用。因為其它隊列沒有設置最大資源,eng或者science隊列中的作業可以使用dev隊列所有的資源(最多占集群的75%),或者對于prod隊列來說,實際可使用集群所有資源。
除了配置隊列的層級以及容量,還可以控制一個用戶或應用可以分配的資源最大數量,同時可以運行的應用數,隊列的ACLs控制(權限控制)。詳細說明請參考Hadoop: Capacity Scheduler。
隊列指定
指定應用放在哪個隊列是在應用端進行指定的。例如,在MapReduce
中,你將屬性mapreduce.job.queue.name的值設置為你想存放的隊列的名字。如果指定的隊列名不存在,將會在提交作業時報出錯誤。如果沒有指定隊列,則應用會放在叫做default的隊列中。
對于容量調度器而言,隊列名稱是層級結構最后一級的名字,全路徑名稱將不識別。所以,拿先前的配置例子來講,prod和eng這樣寫沒問題,但root.dev.eng和dev.eng就不行。
公平調度器的配置
公平調度器試著使所有正運行的應用得到相同的資源。圖4-3顯示了在同一個隊列中應用是怎么樣平均分配資源的。然而,對于多個隊列,仍然可以平均分配,下面將加以說明。
為了理解資源是如何在隊列間平分的,假設有兩個用戶A和B,每一個用戶都有自己的隊列(圖4-4)。A用戶啟動了一個作業,由于B沒有請求資源,這個作業將得到集群所有的資源。然后,B也啟動了一個作業,A的作業仍然在運行,一會之后,每一個作業都能得到一半的資源,就像我們先前看到的那樣。現在,如果B啟動了第二個作業,這時其它作業仍在運行。B將把它的資源分配給他啟動的其它作業,這樣,B的每一個作業都將占有四分之一的資源。A仍然占有二分之一的資源。這樣資源在用戶之間平均分配了。在公平調度器上下文中,隊列和池可以互換使用,意思是一樣的
啟用公平調度器
使用哪個調度器是通過yarn.resourcemanager.scheduler.class屬性決定的。默認是容量調度器(在有些hadoop分布式系統,例如CDH中,默認是使用公平調度器)。通過在yarn-site.xml配置文件中配置yarn.resourcemanager.scheduler.class來改變默認的調度器,它的值是調度器的全路徑類名:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler。
隊列配置
公平調度器在一個叫做fair-scheduler.xml的配置文件中配置,這個配置文件在加載classpath指定的類時一同被加載,配置文件的名字可以通過屬性yarn.scheduler.fair.allocation.file設置。每一個應用被放在以用戶名命名的隊列中,當用戶提交第一個應用時,隊列就會被動態地創建。
在配置文件中,配置每一個隊列,可以像容量調度器一樣按照層級進行配置。例如,我們可以按照我們在容量調度器中定義的那樣定義prod和dev隊列,如示例4-2。
示例4-2:公平調度器的配置文件
<?xml version="1.0"?>
<allocations>
<defaultQueueSchedulingPolicy>fair</defaultQueueSchedulingPolicy>
<queue name="prod">
<weight>40</weight>
<schedulingPolicy>fifo</schedulingPolicy>
</queue>
<queue name="dev">
<weight>60</weight>
<queue name="eng" />
<queue name="science" />
</queue>
<queuePlacementPolicy>
<rule name="specified" create="false" />
<rule name="primaryGroup" create="false" />
<rule name="default" queue="dev.eng" />
</queuePlacementPolicy>
</allocations>
隊列的層級定義通過使用嵌套的queue節點。所有的隊列是root隊列的子隊列,即使實現上沒有嵌套在root隊列節點下。這里,我們又將dev隊列分成eng和science兩個子隊列。
隊列可以有重量,用于公平分享資源時的計算。在這個例子中,集群將prod和dev隊列按照40:60的比例分配資源,這樣分配是公平的。eng和science沒有指定重量,所以它們是平均分配的。重量和比例不完全一樣,這個示例中,我們使用加起來等于100的重量只是為了簡便起見。我們也能給prod和dev隊列的重量都指定2或3.
當設置重量的時候,記得考慮到"默認隊列"和動態生成的隊列(例如那些以客戶命名的隊列)。沒有在配置文件中指定的隊列,重量都是1。
這些隊列可以有不同的調度規則。默認的規則可以通過頂級節點defaultQueueSchedulingPolicy設置。如果省略了這個節點,將使用公平調度規則。不能只看它的名字是“公平”,公平調度器也支持FIFO(fifo)規則和后面將講到的優勢資源公平規則(drf Dominant Resource Fairness)。
某個特定隊列的調度規則可以通過它的schedulingPolicy屬性覆蓋。如上面的配置文件,prod隊列使用FIFO調度規則,因為我們想要每一個作業按順序執行并且能在最短的時間內執行完。注意一點的是,prod和dev隊列仍然使用公平調度規則進行資源的劃分,eng和science隊列也是一樣。
雖然沒有在以上配置文件中顯示出來,但還可以配置隊列能使用的最小或最大資源空間,和隊列中最多運行的應用數(詳細配置參看此頁)。最小資源空間不是一個硬性限制,而是調度器用來優先分配資源的。例如如果兩個隊列的資源都不夠,那么離最小資源分配要求差距最大的將優先分配到資源。最小資源的設置還可用于優先占有,稍后將討論到。
隊列指定
公平調度器使用一定的規則來決定應用放在哪個隊列中。如示例4-2,queuePlacementPolicy節點包含一系列規則,系統將按順序嘗試每一條規則,直到匹配到一條。第一條規則,specified指定應用放在哪一個隊列中,如果沒有指定或指定的隊列不存在,這條規則不符合,將嘗試下一條規則。primaryGroup規則指定應用放在與用戶的主Unix組名相同的隊列中。如果不存在這樣的隊列,則嘗試下一條規則。default規則是上面的規則都不滿足時,系統總是會嘗試的規則,此條規則將應用放在dev.eng隊列中。
queuePlacementPolicy節點整個可以省略不配置。如果是這樣的話,就跟指定了下面的配置是一樣的。
<queuePlacementPolicy>
<rule name="specified" />
<rule name="user" />
</queuePlacementPolicy>
換句話說,除非隊列顯示地聲明,否則將尋找與用戶的名字相同的隊列,如果有必要,會創建與用戶的名稱一樣的隊列。
另一個簡單的隊列指定規則是所有應用指定放于相同(默認)隊列中。這樣,每個應用都會分到相等的資源,而不是按照用戶。對應的規則如下:
<queuePlacementPolicy>
<rule name="default" />
</queuePlacementPolicy>
也可以不使用配置文件來設置規則,那就是將屬性yarn.scheduler.fair.user-as-default-queue設置為false,這樣應用就會都進入默認隊列中,而不是按照用戶分的隊列中。另外,yarn.scheduler.fair.allow-undeclared-pools應該設置為false,這樣用戶就不能夠在運行時動態創建隊列了。
優先占有
當一個作業提交到一臺繁忙的集群中的一個空隊列中時,這個作業不會立即啟動,直到資源從正在運行在這個集群中的其它作業釋放出來后才會啟動。為了使一個作業啟動的時間是可預料的,公平調度器允許優先占有。
優先占有意思是調度器可以釋放那些占用的資源超過它們應分配資源的隊列正在使用的容器,然后分配給那些不夠它們本應該分配的資源的隊列。注意優先占有會降低整個集群的效率,因為容器終止后,容器之前運行的任務需要重新執行。
如果將屬性yarn.scheduler.fair.preemption設置為true,則會啟用整個集群的優先占有。有兩個相關的優先占有超時設置。一個針對最小資源的,一個針對公平分配資源的,都是以秒為單位。默認情況下,不會設置超時,所以你需要至少設置一個,以便讓可以占有容器。
如果隊列等到了超時的時間還沒到分到保證的最少資源。那么調度器也許會占其它的容器。通過在配置文件設置頂級屬性defaultMinSharePreemptionTimeout,可以對所有隊列設置超時的時間。如果想單獨對某個隊列設置,可以在隊列節點中設置minSharePreemptionTimeout。
同樣地,如果一個隊列占的資源不到它應得資源的50%,這種狀態持續的時間達到了設置的公平分配的超時時間,那么調度器也會去占其它容器。通過在配置文件設置頂級屬性defaultFairSharePreemptionTimeout,可以對所有隊列設置超時的時間。如果想單獨對某個隊列設置,可以在隊列節點中設置fairSharePreemptionTimeout。隊列現占用的資源與應得資源的占比默認是0.5,我們可以通過配置屬性defaultFairSharePreemptionThreshold和fairSharePreemptionThreshold(此屬性針對單個隊列)改變。
延遲調度
所有的YARN調度器盡量在請求的位置上執行應用。在一個繁忙的集群中,如果應用請求某個節點,此時,正好其它容器正在這個節點上運行。那么系統就不會嚴格按照請求來了,它會在相同的機架上再找另外一個容器。然而,實際上,如果等待一點時間(不超過幾秒)就會增加能分配到請求節點上容器的機率,因此,也增加了集群的效率。這個特性叫做"延遲調度"。容量調度器和公平調度器都支持這個特性。
YARN集群中的每一個節點管理器都會周期性地向資源管理器發送一個心跳(默認1秒1次)。心跳會帶著節點管理器上正運行容器的信息還有能提供給新容器的資源信息,所以每一次心跳對一個應用來說是一個潛在的調度啟用新容器的機會。
當采取延遲調度時,調度器不會簡單地使用它得到的第一次調度機會,而是等待一個指定的最大的錯過的調度機會數,如果達到了最大的錯過的調度機會數,則會不嚴格按照請求來分配節點并準備在下一次調度機會來時進行調度。
對于容量調度器而言,延遲調度通過yarn.scheduler.capacity.node-locality-delay屬性進行配置,將此屬性配置成一個正整數,表示調度器錯過的調度機會數,如果達到了調度機會數,請求的那個節點仍然不能啟用新容器,則將不會按照請求來執行而是在相同機架上尋找任意一個節點。
公平調度器也使用調度機會數也決定延遲,然而它是用集群大小的比例來表示的。例如,將屬性yarn.scheduler.fair.locality.threshold.node設置為0.5,意思是調度器應該等到集群中一半的節點都已經提供了調度機會了,請求還沒有滿足時,將會在相同機架中尋找另外一個節點。相應地,還有一個屬性yarn.scheduler.fair.locality.threshold.rack設置機架的閾值,達到閾值后,將選擇另外一個機架,而不是請求的節點所在的機架。
高占比資源公平分配
當只需要調度一種資源時,例如內存,不管是使用容量調度器還是公平調度器都很容易分配。如果有兩個用戶的應用需要運行,你可以通過比較兩個應用所需要的內存來進行分配。然而,當有多種類型資源時,事情就會變得更復雜一些。如果一個用戶的應用需要大量的CPU,但是卻需要少量的內存,其它用戶需要少量CPU,卻需要大量內存,那么這兩個應用該怎么比較呢?
YARN框架中的調度器解決這個問題所使用的方法是看看每一個用戶的高占比資源是多少,然后使用這些高占比的資源做為集群資源占用的標準。這種方法被稱為"高占比資源公平分配或簡稱DRF"[3]。下面用一個簡單的例子加以說明。
假設一個集群一共有100個CPU和10TB的內存。應用A申請2CPU,300GB內存的容器,應用B則申請6CPU,100GB。A請求的資源分別占集群總資源的2%,3%,所以內存是A應用的高占比資源,因為3%比2%大。B請求的資源分別占集群總資源的6%,1%,所以CPU是高占比資源。可以看出,就高占比資源而言,B應用請求的資源是A應用的2倍(6%vs3%),所以在公平分配原則下,B應用分到的容器數將是A應用分到的一半。
默認DRF沒有啟用,所以在資源計算中,僅僅只考慮內存,不考慮CPU。容量調度器通過將capacity-scheduler.xml配置文件中的屬性yarn.scheduler.capacity.resource-calculator的值配置為org.apache.hadoop.yarn.util.resource.DominantResourceCalculator來啟用DRF。
至于公平調度器,則通過在配置文件配置頂級元素QueueSchedulingPolicy的值為drf啟用DRF。
延伸閱讀
這一章簡單的概括性了解了一下YARN。如果想更詳細地了解,可以看Arun C. Murthy等人寫的《Apache Hadoop YARN》這本書。
本文是筆者翻譯自《OReilly.Hadoop.The.Definitive.Guide.4th.Edition》第一部分第4章,后續將繼續翻譯其它章節。雖盡力翻譯,但奈何水平有限,錯誤再所難免,如果有問題,請不吝指出!希望本文對你有所幫助。
-
如果屬性yarn.scheduler.capacity.<queue-path>.user-limit-factor值比默認的1大,則作業允許使用超過隊列容量的資源 ?
-
然而,容量調度器可以進行預置進程保護, 資源管理器可以要求應用釋放容器以平衡資源容量 ?
-
DRF是Ghodsi等人在2011年3月份發表的《高占比資源公平分配:多種資源的公平分配》這篇文章里提出來的 ?