Apache YARN(Yet Another Resource Negotiator)是一個(gè)Hadoop集群資源管理系統(tǒng)。YARN是在Hadoop 2引入的,用以改善MapReduce的表現(xiàn)。但是它也足夠勝任其它的分布式計(jì)算框架。
YARN提供了一些能被請(qǐng)求調(diào)用的APIs,并處理集群資源。但是通常用戶不會(huì)直接調(diào)用這些APIs,而是調(diào)用由分布計(jì)算框架提供的更高級(jí)別的APIs。這些更高級(jí)別的APIs基于YARN建立,并對(duì)用戶隱藏了資源管理的細(xì)節(jié)。圖4-1說明了這個(gè)情景,并顯示了一些分布式計(jì)算框架(MapReduce,Spark等等)作為YARN應(yīng)用位于集群計(jì)算層(YARN)和存儲(chǔ)層之上(HDFS和Hbase)。

圖4-1框架表示的應(yīng)用層之上還有一層應(yīng)用,如Pig,Hive和Crunch。它們都運(yùn)行在MapReduce,Spark或Tez(或同時(shí)三者)之上,并不和YARN直接交互。
這一章節(jié)帶領(lǐng)大家過一遍YARN的特性,為理解第四部分章節(jié)的內(nèi)容(包括一些分布式處理框架)打下基礎(chǔ)。
YARN應(yīng)用運(yùn)行分析
YARN通過兩種一直運(yùn)行的守護(hù)進(jìn)程來提供它的核心服務(wù)。一種是資源管理器(一個(gè)集群一個(gè)),管理集群中所有資源的使用,另一種是節(jié)點(diǎn)管理器,在所有節(jié)點(diǎn)上運(yùn)行,啟動(dòng)或監(jiān)控容器。容器會(huì)使用分配的有限資源的集合(內(nèi)存,CPU等)執(zhí)行應(yīng)用特定的進(jìn)程。取決于YARN是如何配置的,容器可以是一個(gè)Unix進(jìn)程,也可以是一個(gè)Linux cgroup(control groups)。圖4-2顯示了YARN怎么樣運(yùn)行應(yīng)用的。

為了運(yùn)行基于YARN的應(yīng)用,客戶端必須與資源管理器(resource manager)通信,請(qǐng)求它運(yùn)行一個(gè)應(yīng)用主進(jìn)程(圖4-2步驟1)。資源管理器然后尋找能夠在容器中啟動(dòng)這個(gè)應(yīng)用主進(jìn)程的節(jié)點(diǎn)管理器(步驟2a和2b)。應(yīng)用啟動(dòng)后,具體能夠做什么取決于應(yīng)用本身。它可以在它所在的容器中簡(jiǎn)單地執(zhí)行一個(gè)計(jì)算然后將結(jié)果返回給客戶端?;蛘咚梢韵蛸Y源管理器請(qǐng)求更多的容器(步驟3),以便運(yùn)行分布式計(jì)算(步驟4a和4b)。后者是MapReduce YARN應(yīng)用所做的事,我們將會(huì)在"一個(gè)MapRedue作業(yè)運(yùn)行分析"小節(jié)中詳細(xì)地學(xué)習(xí)。
從圖4-2我們注意到,YARN本身不提供任何方法讓應(yīng)用各部分(客戶端,主進(jìn)程,進(jìn)程)間進(jìn)行通信。大多數(shù)特殊的YARN應(yīng)用使用遠(yuǎn)程調(diào)用的形式(例如Hadoop的RPC),將更新的狀態(tài)和結(jié)果傳遞回客戶端,但是這不是正常情況。
資源請(qǐng)求
YARN對(duì)于資源請(qǐng)求的形式要求比較靈活。某個(gè)請(qǐng)求,請(qǐng)求多個(gè)容器,可以對(duì)每一個(gè)容器都指定需要的計(jì)算機(jī)硬件資源(內(nèi)存,CPU等),并能夠指定位置限定的一些容器。
位置對(duì)于一些分布式的數(shù)據(jù)處理算法能夠充分高效地使用集群帶寬是很重要的。所以YARN允許應(yīng)用指定它請(qǐng)求的容器的位置。位置限定可以指定位于某個(gè)特定的節(jié)點(diǎn)或機(jī)架,或者集群中任意位置(比如:不在機(jī)架上的)的容器。
有時(shí),并不能夠滿足位置限定的條件,這種情況下,要未不分配任何位置,要未,選擇放寬限定條件。例如,指定了某個(gè)節(jié)點(diǎn),但是不可能在這個(gè)節(jié)點(diǎn)上啟動(dòng)容器(因?yàn)槠渌萜髡谒厦孢\(yùn)行),那么YARN將會(huì)嘗試啟動(dòng)位于相同機(jī)架上的其它節(jié)點(diǎn)上的容器,或者其它節(jié)點(diǎn)也不可用時(shí),就啟動(dòng)集群中任意一個(gè)節(jié)點(diǎn)上的容器。
啟動(dòng)一個(gè)容器處理HDFS塊(比方說,執(zhí)行MapReduce中的一個(gè)map任務(wù)),通常情況下,應(yīng)用會(huì)請(qǐng)求保存了塊三個(gè)復(fù)本的那個(gè)節(jié)點(diǎn),或者保存了這些復(fù)本的機(jī)架中的某個(gè)節(jié)點(diǎn),如果以上都失敗了,就選擇集群中任意一個(gè)節(jié)點(diǎn)上的容器。
一個(gè)YARN容器可以在它運(yùn)行時(shí)的任意時(shí)間發(fā)起資源請(qǐng)求。例如,一個(gè)應(yīng)用可以預(yù)先發(fā)起所需所有資源的請(qǐng)求,也可以以一種更加動(dòng)態(tài)的途徑,即當(dāng)應(yīng)用有更改時(shí),再動(dòng)態(tài)地請(qǐng)求更多資源。
Spark采取了第一種途徑,在集群中啟動(dòng)固定數(shù)量的執(zhí)行器(“參看在YARN上的Spark ”章節(jié))。另一方面,MapReduce會(huì)采取這兩種途徑。執(zhí)行map任務(wù)時(shí)會(huì)預(yù)先請(qǐng)求所有容器,執(zhí)行reduce任務(wù)的容器不會(huì)立即啟動(dòng),會(huì)在后面啟動(dòng)。而且,如果有任何任務(wù)處理失敗了,將會(huì)請(qǐng)求額外的容器重新執(zhí)行失敗的任務(wù)。
應(yīng)用的生命周期
一個(gè)YARN應(yīng)用的生命周期可以千差萬別,從幾秒的短命應(yīng)用到可以運(yùn)行數(shù)天甚至數(shù)月的長(zhǎng)期應(yīng)用??尚械膽?yīng)用歸類是根據(jù)應(yīng)用與作業(yè)之間的映射關(guān)系而不是應(yīng)用運(yùn)行的時(shí)間來進(jìn)行分類。最簡(jiǎn)單的情況是每一個(gè)作業(yè)對(duì)應(yīng)一個(gè)應(yīng)用,MapReduce任務(wù)采取的就是這個(gè)途徑。
第二個(gè)模式是每一個(gè)工作流運(yùn)行一個(gè)應(yīng)用或多個(gè)作業(yè)(可能是不相關(guān)的作業(yè))運(yùn)行一個(gè)應(yīng)用。這種途徑比第一個(gè)途徑更高效,因?yàn)閼?yīng)用容器可以被多個(gè)作業(yè)共用,也可以緩存多個(gè)作業(yè)產(chǎn)生的中間數(shù)據(jù)。Spark就是一個(gè)使用這種模式的例子。
第三個(gè)模式是被不同用戶共享的長(zhǎng)生命周期應(yīng)用。這種應(yīng)用經(jīng)常是以某種配合的角色發(fā)揮作用。例如Apache Slider就有一個(gè)長(zhǎng)期運(yùn)行的應(yīng)用管理器,這個(gè)應(yīng)用管理器作用是啟動(dòng)集群中的其它應(yīng)用。Impala通過這個(gè)途徑來提供一個(gè)代理應(yīng)用,用于響應(yīng)Impala實(shí)體機(jī)的資源請(qǐng)求。通過使用這種"一直運(yùn)行"的應(yīng)用管理器,用戶可以獲得低延遲響應(yīng),因?yàn)楫?dāng)用戶查詢時(shí)不需要啟動(dòng)一個(gè)新的應(yīng)用管理器了。
構(gòu)建YARN應(yīng)用
從頭開始寫一個(gè)YARN應(yīng)用是相當(dāng)復(fù)雜地,但是大多數(shù)情況不必要。因?yàn)榭梢允褂靡粋€(gè)已經(jīng)存在的應(yīng)用,進(jìn)行調(diào)整以適應(yīng)自己地需求。例如,如果你對(duì)有向無環(huán)圖(DAG)感興趣,那么Spark或者Tez是合適的,或者對(duì)流式處理感興趣,Spark,Samza或者Storm是合適的。
有很多工程用于簡(jiǎn)化構(gòu)建一個(gè)YARN應(yīng)用時(shí)的操作。早先提到的Apache Slider讓現(xiàn)有的分布式應(yīng)用運(yùn)行在YARN上成為可能。用戶可以在集群上運(yùn)行他們自己的應(yīng)用(例如HBase)而不影響其它用戶,不同的用戶可以運(yùn)行同一個(gè)應(yīng)用不同的版本。Slider能夠改變應(yīng)用運(yùn)行的節(jié)點(diǎn)數(shù)量,掛起和恢復(fù)運(yùn)行某個(gè)應(yīng)用。
Apache Twill與Slider相似,但除了以上功能,另外還可以提供一個(gè)簡(jiǎn)單的編程模型,可以開發(fā)基于YARN的分布式應(yīng)用。Twill允許你定義實(shí)現(xiàn)了Java Runnable接口的集群進(jìn)程,然后在集群的YARN容器中運(yùn)行它們。Twill還提供實(shí)時(shí)日志(記錄可執(zhí)行進(jìn)程的事件以流形式返回客戶端)和命令消息(將客戶端的命令發(fā)送給可執(zhí)行進(jìn)程)。
當(dāng)以上選擇都不能滿足要求時(shí),例如需要開發(fā)一個(gè)能夠進(jìn)行復(fù)雜時(shí)間調(diào)度的YARN應(yīng)用。那么YARN工程中有一個(gè)分布式的shell應(yīng)用可以做為如何開發(fā)YARN應(yīng)用的例子,它演示了如何使用YARN APIs在客戶端、應(yīng)用管理器與YARN守護(hù)進(jìn)程之間交互通信。
YARN與MapReduce 1比較
在Hadoop最初版本(版本1或更早)中的MapReduce有時(shí)被稱為"MapReduce 1",以和MapReduce 2區(qū)分開。MapReduce 2是Hadoop 2或之后的版本,它使用了YARN。
有一件重要的事情,那就是舊的和新的MapReduce APIs與MapReduce1和MapReduce2并不是一回事。APIs是面向用戶,客戶端的,決定了你如何寫MapReduce程序(參看附錄D),然而MapReduce1和2僅僅是運(yùn)行MapReduce程序不同的方法。舊的和新的MapReduce APIs都可以在MapReduce1和2中運(yùn)行。
在MapReduce1中,有兩種控制作業(yè)執(zhí)行過程的守護(hù)進(jìn)程,一種是jobtracker,一種是一個(gè)或多個(gè)tasktracker。jobtracker組合系統(tǒng)中需要運(yùn)行的所有作業(yè),然后分配運(yùn)行在tasktracker上的任務(wù)。Tasktracker執(zhí)行任務(wù),并將進(jìn)度報(bào)告發(fā)送給jobtracker,jobtracker將會(huì)保存每一個(gè)作業(yè)的整個(gè)進(jìn)度。如果一個(gè)任務(wù)失敗了,jobtracker將會(huì)在另一個(gè)tasktracker上啟動(dòng)它。
在MapReduce1中,jobtracker既關(guān)心作業(yè)的調(diào)度(匹配tasktracker與task),又關(guān)心任務(wù)的進(jìn)度(跟蹤任務(wù),重啟失敗的任務(wù),顯示任務(wù),記錄任務(wù),例如維護(hù)任務(wù)數(shù))。相對(duì)地,在YARN中,這些責(zé)任由不同的實(shí)體處理:資源管理器和應(yīng)用管理器(一個(gè)MapReduce作業(yè)一個(gè)應(yīng)用管理器)。jobtracker還需要存儲(chǔ)已經(jīng)完成的作業(yè)的歷史記錄。當(dāng)然也可以單獨(dú)運(yùn)行一個(gè)歷史記錄服務(wù)來給jobtracker減負(fù)。在YARN中,具有相同角色的是時(shí)間線服務(wù),它存儲(chǔ)應(yīng)用的歷史記錄。
在YARN應(yīng)用中,與tasktracker等效的是節(jié)點(diǎn)管理器。MapReduce1與YARN的功能映射關(guān)系如表4-1所示:
| MapReduce 1 | YARN |
|---|---|
| Jobtracker | 資源管理器,應(yīng)用管理器,時(shí)間線服務(wù) |
| Tasktracker | 節(jié)點(diǎn)管理器 |
| 槽(Slot) | 容器 |
設(shè)計(jì)YARN的目的是解決MapReduce 1的一些局限性。使用YARN有如下好處:
擴(kuò)展性
YARN可以運(yùn)行在比MapReduce 1更大的集群上。當(dāng)達(dá)到4000節(jié)點(diǎn)或4000個(gè)任務(wù)時(shí),MapReduce 1就達(dá)到了瓶頸。因?yàn)閖obtracker必須要管理作業(yè)和任務(wù)。YARN通過使用分開的資源管理與應(yīng)用管理的結(jié)構(gòu)克服了這個(gè)限制,YARN設(shè)計(jì)的目的是能擴(kuò)展到10000個(gè)節(jié)點(diǎn)和100000個(gè)任務(wù)。高可用性
HA(High availability 高可用)是當(dāng)正在服務(wù)的實(shí)體機(jī)故障時(shí),通過復(fù)制所需的狀態(tài)和數(shù)據(jù)到另外一臺(tái)實(shí)體機(jī)上,執(zhí)行所需的工作,繼續(xù)提供服務(wù)來實(shí)現(xiàn)的。然而jobtracker內(nèi)存中大量快速地改變復(fù)雜的狀態(tài)(例如,每幾秒鐘每一個(gè)task狀態(tài)就會(huì)更新一次)使HA應(yīng)用到j(luò)obtracker變得非常困難。
YARN通過將jobtracker的功能分解到資源管理器和應(yīng)用管理器,使服務(wù)高度可用變成了一個(gè)可以分開克服的問題。那就是為資源管理器提供HA,然后為YARN應(yīng)用(以每一個(gè)應(yīng)用為基礎(chǔ)單位)提供HA。實(shí)際小,Hadoop 2支持MapReduce作業(yè)中的資源 管理器和應(yīng)用管理器HA。YARN中的故障恢復(fù)將在第7章"故障"小節(jié)中詳細(xì)講解。實(shí)用性
在MapReduce 1中,每個(gè)tasktracker通過一個(gè)位置固定,大小固定的"槽"中配置,槽分為map槽和reduce槽。map槽只能用于運(yùn)行map任務(wù),相應(yīng)的,reduce槽只能用于reduce任務(wù)。
在YARN中,一個(gè)節(jié)點(diǎn)管理器管理一個(gè)資源池,而不是數(shù)量固定的指定的槽。YARN上的運(yùn)行的MapReduce不會(huì)出現(xiàn)由于集群中僅僅有map槽,reduce任務(wù)必須等待的情況。這種情況可能發(fā)生在MapReduce 1中.YARN中,如果運(yùn)行任務(wù)時(shí),資源可得,那么應(yīng)用就應(yīng)該能夠使用它們。
而且,YARN中的資源是精細(xì)化管理的,所以應(yīng)用可以請(qǐng)求它所需要的資源,而不必請(qǐng)求一個(gè)槽。對(duì)于某些特殊的任務(wù)來說,槽太大的話,會(huì)造成資源浪費(fèi),太小的話,造成任務(wù)失敗。-
多用性
從某些方面來說,YARN最大的優(yōu)勢(shì)是它使Hadoop能夠使用除了MapReduce其它類型的分布式應(yīng)用。MapReduce僅僅是其中一個(gè)YARN應(yīng)用。用戶甚至能夠在同一個(gè)集群中運(yùn)行不同版本的MapReduce應(yīng)用。這就使得升級(jí)MapReduce變得更加容易管理。(注意,MapReduce中的某些部分,例如作業(yè)歷史記錄服務(wù)器,shuffle處理器和YARN本身仍然需要整個(gè)集群一起升級(jí)。)
既然Hadoop 2被廣泛使用,而且是最新的穩(wěn)定版本。這本書中剩余部分內(nèi)容中"MapReduce"指的就是"MapReduce 2"。第7章將會(huì)詳細(xì)地講解MapReduce如何運(yùn)行在YARN之上。
YARN中的調(diào)度計(jì)劃
理想情況下,一個(gè)YARN應(yīng)用的請(qǐng)求應(yīng)該立刻響應(yīng)。然而,現(xiàn)實(shí)情況是,資源是有限的,而且集群繁忙時(shí),應(yīng)用經(jīng)常需要等待直到它的部分請(qǐng)求得到滿足。YARN調(diào)度器的工作就是根據(jù)一些既定的規(guī)則給應(yīng)用分配資源。調(diào)度通常是一個(gè)困難的問題,沒有一個(gè)最好的規(guī)則。這也就是為什么YARN提供調(diào)度器和可配置規(guī)則兩種選擇的原因。我們接下來詳細(xì)看看。
調(diào)度器
YARN中有三種調(diào)度器:FIFO調(diào)度器,容量調(diào)度器和公平調(diào)度器。FIFO調(diào)度器將應(yīng)用放在一個(gè)隊(duì)列中,按照它們提交的順序運(yùn)行它們(先進(jìn),先出)。隊(duì)列中第一個(gè)應(yīng)用的請(qǐng)求首先滿足。一旦它的請(qǐng)求被滿足了之后,就服務(wù)隊(duì)列中下一個(gè)應(yīng)用,依次類推。
FIFO的優(yōu)點(diǎn)是容易理解,而且不需要配置。但是它不適合資源共享的集群。一般大的應(yīng)用會(huì)用到集群中所有資源,如果使用FIFO,每一個(gè)應(yīng)用必須要按序等待。在資源共享的集群中,最好使用容量調(diào)度器或者公平調(diào)度器。二者都會(huì)使那些運(yùn)行時(shí)間長(zhǎng)的作業(yè)能夠在合理時(shí)間內(nèi)完成,而且也使得用戶在執(zhí)行少量的臨時(shí)的并發(fā)查詢時(shí),能夠在合理的時(shí)間內(nèi)返回結(jié)果。
調(diào)度器之間的區(qū)別如圖4-3所示,我們可以看到,F(xiàn)IFO調(diào)度模式(i)下,小的作業(yè)必須要等待大的作業(yè)完成之后才能執(zhí)行。
在容量調(diào)度模式(ii)下,一個(gè)分開的專用的隊(duì)列允許小的作業(yè)一提交就能夠執(zhí)行。這是以整個(gè)集群的可利用空間為代價(jià)的,因?yàn)樾枰獮檫@個(gè)專用隊(duì)列預(yù)留空間。這也意味著大的作業(yè)比使用FIFO調(diào)度完成的晚。
在公平調(diào)度模式(iii)下,不需要預(yù)留一定數(shù)量的空間。因?yàn)樗鼤?huì)動(dòng)態(tài)的平衡所有運(yùn)行的作業(yè)所需的空間資源。第一個(gè)(大)作業(yè)啟動(dòng)后(目前是集群中唯一運(yùn)行的作業(yè)),它會(huì)獲取集群中所有的資源,當(dāng)?shù)诙€(gè)(小)作業(yè)啟動(dòng)后,它將把一半資源分配給第二個(gè)作業(yè)。這樣,每一個(gè)作業(yè)都能分到相同數(shù)量的資源。
注意到,第二個(gè)作業(yè)啟動(dòng)到它接收到所分的資源有一定的延遲。因?yàn)楸仨毜却Y源從第一個(gè)作業(yè)使用的容器中釋放出來后才能使用。在小作業(yè)完成,并不再請(qǐng)求資源后,大的作業(yè)又將使用集群中所有的資源。這個(gè)模式造成集群的高占用空間和小作業(yè)及時(shí)的完成。
圖4-3對(duì)比了這三個(gè)調(diào)試器基本操作。接下來的兩部分,我們將學(xué)習(xí)容量和公平調(diào)度器中一些高級(jí)的配置。

容量調(diào)度器配置
容量調(diào)度器允許按照組織的行形式共享Hadoop集群資源,每一個(gè)組織都分配了總集群資源中的一部分資源。每一個(gè)組織都設(shè)一個(gè)專用的隊(duì)列??梢耘渲藐?duì)列使用集群中指定的部分資源。隊(duì)列也許可以進(jìn)一步按層級(jí)劃分,使得每一個(gè)組織可以將它的資源分配給不同組的用戶。在隊(duì)列中,應(yīng)用按照FIFO規(guī)則進(jìn)行調(diào)度。
正如我們?cè)趫D4-3看到的那樣,單個(gè)作業(yè)不能使用超過它所在隊(duì)列容量的資源。然而,如果隊(duì)列中的作業(yè)超過一個(gè),并且有空閑的資源,那么容量調(diào)度器也許會(huì)將剩余的資源分配給這個(gè)隊(duì)列中的作業(yè),即使會(huì)超出隊(duì)列的容量(應(yīng)分配的資源)[1],這就是所熟知的"彈性隊(duì)列"。
正常操作時(shí),容量調(diào)度器不會(huì)強(qiáng)制地殺死作業(yè)來回收容器[2],所以如果一個(gè)隊(duì)列由于缺少請(qǐng)求而容量不夠,然后增加請(qǐng)求,如果其它隊(duì)列中作業(yè)完成,有資源從容器中釋放出來,隊(duì)列將會(huì)占用其它隊(duì)列的資源。通過配置隊(duì)列的最大容量可以限制隊(duì)列不占用其它隊(duì)列太多資源。但這是以隊(duì)列的彈性為代價(jià),當(dāng)然,通過不斷嘗試與錯(cuò)誤,應(yīng)該能找到一個(gè)合理的平衡點(diǎn)。
假設(shè)隊(duì)列層級(jí)如下面這樣:

示例4-1顯示了一個(gè)容量調(diào)度器配置文件,這個(gè)配置文件叫做capacity-scheduler.xml。對(duì)應(yīng)于上面的層級(jí),在root隊(duì)列下定義了兩個(gè)隊(duì)列,prod,dev,分別占40%和60%的資源。注意,可以通過屬性yarn.scheduler.capacity.<queue-path>.<sub-property> 來配置隊(duì)列特殊的屬性。<queue-path>是隊(duì)列的層級(jí)路徑(以點(diǎn)分隔),例如root.prod。
示例:4-1:容量調(diào)度器的基本配置文件
<?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隊(duì)列進(jìn)一步分成了相同大小的eng和science隊(duì)列。所以當(dāng)prod隊(duì)列空閑的時(shí)候,dev隊(duì)列沒有使用集群所有的資源,它最大的使用資源設(shè)置為75%。換句話說,prod隊(duì)列總是有25%資源可以立即使用。因?yàn)槠渌?duì)列沒有設(shè)置最大資源,eng或者science隊(duì)列中的作業(yè)可以使用dev隊(duì)列所有的資源(最多占集群的75%),或者對(duì)于prod隊(duì)列來說,實(shí)際可使用集群所有資源。
除了配置隊(duì)列的層級(jí)以及容量,還可以控制一個(gè)用戶或應(yīng)用可以分配的資源最大數(shù)量,同時(shí)可以運(yùn)行的應(yīng)用數(shù),隊(duì)列的ACLs控制(權(quán)限控制)。詳細(xì)說明請(qǐng)參考Hadoop: Capacity Scheduler。
隊(duì)列指定
指定應(yīng)用放在哪個(gè)隊(duì)列是在應(yīng)用端進(jìn)行指定的。例如,在MapReduce
中,你將屬性mapreduce.job.queue.name的值設(shè)置為你想存放的隊(duì)列的名字。如果指定的隊(duì)列名不存在,將會(huì)在提交作業(yè)時(shí)報(bào)出錯(cuò)誤。如果沒有指定隊(duì)列,則應(yīng)用會(huì)放在叫做default的隊(duì)列中。
對(duì)于容量調(diào)度器而言,隊(duì)列名稱是層級(jí)結(jié)構(gòu)最后一級(jí)的名字,全路徑名稱將不識(shí)別。所以,拿先前的配置例子來講,prod和eng這樣寫沒問題,但root.dev.eng和dev.eng就不行。
公平調(diào)度器的配置
公平調(diào)度器試著使所有正運(yùn)行的應(yīng)用得到相同的資源。圖4-3顯示了在同一個(gè)隊(duì)列中應(yīng)用是怎么樣平均分配資源的。然而,對(duì)于多個(gè)隊(duì)列,仍然可以平均分配,下面將加以說明。
為了理解資源是如何在隊(duì)列間平分的,假設(shè)有兩個(gè)用戶A和B,每一個(gè)用戶都有自己的隊(duì)列(圖4-4)。A用戶啟動(dòng)了一個(gè)作業(yè),由于B沒有請(qǐng)求資源,這個(gè)作業(yè)將得到集群所有的資源。然后,B也啟動(dòng)了一個(gè)作業(yè),A的作業(yè)仍然在運(yùn)行,一會(huì)之后,每一個(gè)作業(yè)都能得到一半的資源,就像我們先前看到的那樣?,F(xiàn)在,如果B啟動(dòng)了第二個(gè)作業(yè),這時(shí)其它作業(yè)仍在運(yùn)行。B將把它的資源分配給他啟動(dòng)的其它作業(yè),這樣,B的每一個(gè)作業(yè)都將占有四分之一的資源。A仍然占有二分之一的資源。這樣資源在用戶之間平均分配了。在公平調(diào)度器上下文中,隊(duì)列和池可以互換使用,意思是一樣的

啟用公平調(diào)度器
使用哪個(gè)調(diào)度器是通過yarn.resourcemanager.scheduler.class屬性決定的。默認(rèn)是容量調(diào)度器(在有些hadoop分布式系統(tǒng),例如CDH中,默認(rèn)是使用公平調(diào)度器)。通過在yarn-site.xml配置文件中配置yarn.resourcemanager.scheduler.class來改變默認(rèn)的調(diào)度器,它的值是調(diào)度器的全路徑類名:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler。
隊(duì)列配置
公平調(diào)度器在一個(gè)叫做fair-scheduler.xml的配置文件中配置,這個(gè)配置文件在加載classpath指定的類時(shí)一同被加載,配置文件的名字可以通過屬性yarn.scheduler.fair.allocation.file設(shè)置。每一個(gè)應(yīng)用被放在以用戶名命名的隊(duì)列中,當(dāng)用戶提交第一個(gè)應(yīng)用時(shí),隊(duì)列就會(huì)被動(dòng)態(tài)地創(chuàng)建。
在配置文件中,配置每一個(gè)隊(duì)列,可以像容量調(diào)度器一樣按照層級(jí)進(jìn)行配置。例如,我們可以按照我們?cè)谌萘空{(diào)度器中定義的那樣定義prod和dev隊(duì)列,如示例4-2。
示例4-2:公平調(diào)度器的配置文件
<?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>
隊(duì)列的層級(jí)定義通過使用嵌套的queue節(jié)點(diǎn)。所有的隊(duì)列是root隊(duì)列的子隊(duì)列,即使實(shí)現(xiàn)上沒有嵌套在root隊(duì)列節(jié)點(diǎn)下。這里,我們又將dev隊(duì)列分成eng和science兩個(gè)子隊(duì)列。
隊(duì)列可以有重量,用于公平分享資源時(shí)的計(jì)算。在這個(gè)例子中,集群將prod和dev隊(duì)列按照40:60的比例分配資源,這樣分配是公平的。eng和science沒有指定重量,所以它們是平均分配的。重量和比例不完全一樣,這個(gè)示例中,我們使用加起來等于100的重量只是為了簡(jiǎn)便起見。我們也能給prod和dev隊(duì)列的重量都指定2或3.
當(dāng)設(shè)置重量的時(shí)候,記得考慮到"默認(rèn)隊(duì)列"和動(dòng)態(tài)生成的隊(duì)列(例如那些以客戶命名的隊(duì)列)。沒有在配置文件中指定的隊(duì)列,重量都是1。
這些隊(duì)列可以有不同的調(diào)度規(guī)則。默認(rèn)的規(guī)則可以通過頂級(jí)節(jié)點(diǎn)defaultQueueSchedulingPolicy設(shè)置。如果省略了這個(gè)節(jié)點(diǎn),將使用公平調(diào)度規(guī)則。不能只看它的名字是“公平”,公平調(diào)度器也支持FIFO(fifo)規(guī)則和后面將講到的優(yōu)勢(shì)資源公平規(guī)則(drf Dominant Resource Fairness)。
某個(gè)特定隊(duì)列的調(diào)度規(guī)則可以通過它的schedulingPolicy屬性覆蓋。如上面的配置文件,prod隊(duì)列使用FIFO調(diào)度規(guī)則,因?yàn)槲覀兿胍恳粋€(gè)作業(yè)按順序執(zhí)行并且能在最短的時(shí)間內(nèi)執(zhí)行完。注意一點(diǎn)的是,prod和dev隊(duì)列仍然使用公平調(diào)度規(guī)則進(jìn)行資源的劃分,eng和science隊(duì)列也是一樣。
雖然沒有在以上配置文件中顯示出來,但還可以配置隊(duì)列能使用的最小或最大資源空間,和隊(duì)列中最多運(yùn)行的應(yīng)用數(shù)(詳細(xì)配置參看此頁(yè))。最小資源空間不是一個(gè)硬性限制,而是調(diào)度器用來優(yōu)先分配資源的。例如如果兩個(gè)隊(duì)列的資源都不夠,那么離最小資源分配要求差距最大的將優(yōu)先分配到資源。最小資源的設(shè)置還可用于優(yōu)先占有,稍后將討論到。
隊(duì)列指定
公平調(diào)度器使用一定的規(guī)則來決定應(yīng)用放在哪個(gè)隊(duì)列中。如示例4-2,queuePlacementPolicy節(jié)點(diǎn)包含一系列規(guī)則,系統(tǒng)將按順序嘗試每一條規(guī)則,直到匹配到一條。第一條規(guī)則,specified指定應(yīng)用放在哪一個(gè)隊(duì)列中,如果沒有指定或指定的隊(duì)列不存在,這條規(guī)則不符合,將嘗試下一條規(guī)則。primaryGroup規(guī)則指定應(yīng)用放在與用戶的主Unix組名相同的隊(duì)列中。如果不存在這樣的隊(duì)列,則嘗試下一條規(guī)則。default規(guī)則是上面的規(guī)則都不滿足時(shí),系統(tǒng)總是會(huì)嘗試的規(guī)則,此條規(guī)則將應(yīng)用放在dev.eng隊(duì)列中。
queuePlacementPolicy節(jié)點(diǎn)整個(gè)可以省略不配置。如果是這樣的話,就跟指定了下面的配置是一樣的。
<queuePlacementPolicy>
<rule name="specified" />
<rule name="user" />
</queuePlacementPolicy>
換句話說,除非隊(duì)列顯示地聲明,否則將尋找與用戶的名字相同的隊(duì)列,如果有必要,會(huì)創(chuàng)建與用戶的名稱一樣的隊(duì)列。
另一個(gè)簡(jiǎn)單的隊(duì)列指定規(guī)則是所有應(yīng)用指定放于相同(默認(rèn))隊(duì)列中。這樣,每個(gè)應(yīng)用都會(huì)分到相等的資源,而不是按照用戶。對(duì)應(yīng)的規(guī)則如下:
<queuePlacementPolicy>
<rule name="default" />
</queuePlacementPolicy>
也可以不使用配置文件來設(shè)置規(guī)則,那就是將屬性yarn.scheduler.fair.user-as-default-queue設(shè)置為false,這樣應(yīng)用就會(huì)都進(jìn)入默認(rèn)隊(duì)列中,而不是按照用戶分的隊(duì)列中。另外,yarn.scheduler.fair.allow-undeclared-pools應(yīng)該設(shè)置為false,這樣用戶就不能夠在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建隊(duì)列了。
優(yōu)先占有
當(dāng)一個(gè)作業(yè)提交到一臺(tái)繁忙的集群中的一個(gè)空隊(duì)列中時(shí),這個(gè)作業(yè)不會(huì)立即啟動(dòng),直到資源從正在運(yùn)行在這個(gè)集群中的其它作業(yè)釋放出來后才會(huì)啟動(dòng)。為了使一個(gè)作業(yè)啟動(dòng)的時(shí)間是可預(yù)料的,公平調(diào)度器允許優(yōu)先占有。
優(yōu)先占有意思是調(diào)度器可以釋放那些占用的資源超過它們應(yīng)分配資源的隊(duì)列正在使用的容器,然后分配給那些不夠它們本應(yīng)該分配的資源的隊(duì)列。注意優(yōu)先占有會(huì)降低整個(gè)集群的效率,因?yàn)槿萜鹘K止后,容器之前運(yùn)行的任務(wù)需要重新執(zhí)行。
如果將屬性yarn.scheduler.fair.preemption設(shè)置為true,則會(huì)啟用整個(gè)集群的優(yōu)先占有。有兩個(gè)相關(guān)的優(yōu)先占有超時(shí)設(shè)置。一個(gè)針對(duì)最小資源的,一個(gè)針對(duì)公平分配資源的,都是以秒為單位。默認(rèn)情況下,不會(huì)設(shè)置超時(shí),所以你需要至少設(shè)置一個(gè),以便讓可以占有容器。
如果隊(duì)列等到了超時(shí)的時(shí)間還沒到分到保證的最少資源。那么調(diào)度器也許會(huì)占其它的容器。通過在配置文件設(shè)置頂級(jí)屬性defaultMinSharePreemptionTimeout,可以對(duì)所有隊(duì)列設(shè)置超時(shí)的時(shí)間。如果想單獨(dú)對(duì)某個(gè)隊(duì)列設(shè)置,可以在隊(duì)列節(jié)點(diǎn)中設(shè)置minSharePreemptionTimeout。
同樣地,如果一個(gè)隊(duì)列占的資源不到它應(yīng)得資源的50%,這種狀態(tài)持續(xù)的時(shí)間達(dá)到了設(shè)置的公平分配的超時(shí)時(shí)間,那么調(diào)度器也會(huì)去占其它容器。通過在配置文件設(shè)置頂級(jí)屬性defaultFairSharePreemptionTimeout,可以對(duì)所有隊(duì)列設(shè)置超時(shí)的時(shí)間。如果想單獨(dú)對(duì)某個(gè)隊(duì)列設(shè)置,可以在隊(duì)列節(jié)點(diǎn)中設(shè)置fairSharePreemptionTimeout。隊(duì)列現(xiàn)占用的資源與應(yīng)得資源的占比默認(rèn)是0.5,我們可以通過配置屬性defaultFairSharePreemptionThreshold和fairSharePreemptionThreshold(此屬性針對(duì)單個(gè)隊(duì)列)改變。
延遲調(diào)度
所有的YARN調(diào)度器盡量在請(qǐng)求的位置上執(zhí)行應(yīng)用。在一個(gè)繁忙的集群中,如果應(yīng)用請(qǐng)求某個(gè)節(jié)點(diǎn),此時(shí),正好其它容器正在這個(gè)節(jié)點(diǎn)上運(yùn)行。那么系統(tǒng)就不會(huì)嚴(yán)格按照請(qǐng)求來了,它會(huì)在相同的機(jī)架上再找另外一個(gè)容器。然而,實(shí)際上,如果等待一點(diǎn)時(shí)間(不超過幾秒)就會(huì)增加能分配到請(qǐng)求節(jié)點(diǎn)上容器的機(jī)率,因此,也增加了集群的效率。這個(gè)特性叫做"延遲調(diào)度"。容量調(diào)度器和公平調(diào)度器都支持這個(gè)特性。
YARN集群中的每一個(gè)節(jié)點(diǎn)管理器都會(huì)周期性地向資源管理器發(fā)送一個(gè)心跳(默認(rèn)1秒1次)。心跳會(huì)帶著節(jié)點(diǎn)管理器上正運(yùn)行容器的信息還有能提供給新容器的資源信息,所以每一次心跳對(duì)一個(gè)應(yīng)用來說是一個(gè)潛在的調(diào)度啟用新容器的機(jī)會(huì)。
當(dāng)采取延遲調(diào)度時(shí),調(diào)度器不會(huì)簡(jiǎn)單地使用它得到的第一次調(diào)度機(jī)會(huì),而是等待一個(gè)指定的最大的錯(cuò)過的調(diào)度機(jī)會(huì)數(shù),如果達(dá)到了最大的錯(cuò)過的調(diào)度機(jī)會(huì)數(shù),則會(huì)不嚴(yán)格按照請(qǐng)求來分配節(jié)點(diǎn)并準(zhǔn)備在下一次調(diào)度機(jī)會(huì)來時(shí)進(jìn)行調(diào)度。
對(duì)于容量調(diào)度器而言,延遲調(diào)度通過yarn.scheduler.capacity.node-locality-delay屬性進(jìn)行配置,將此屬性配置成一個(gè)正整數(shù),表示調(diào)度器錯(cuò)過的調(diào)度機(jī)會(huì)數(shù),如果達(dá)到了調(diào)度機(jī)會(huì)數(shù),請(qǐng)求的那個(gè)節(jié)點(diǎn)仍然不能啟用新容器,則將不會(huì)按照請(qǐng)求來執(zhí)行而是在相同機(jī)架上尋找任意一個(gè)節(jié)點(diǎn)。
公平調(diào)度器也使用調(diào)度機(jī)會(huì)數(shù)也決定延遲,然而它是用集群大小的比例來表示的。例如,將屬性yarn.scheduler.fair.locality.threshold.node設(shè)置為0.5,意思是調(diào)度器應(yīng)該等到集群中一半的節(jié)點(diǎn)都已經(jīng)提供了調(diào)度機(jī)會(huì)了,請(qǐng)求還沒有滿足時(shí),將會(huì)在相同機(jī)架中尋找另外一個(gè)節(jié)點(diǎn)。相應(yīng)地,還有一個(gè)屬性yarn.scheduler.fair.locality.threshold.rack設(shè)置機(jī)架的閾值,達(dá)到閾值后,將選擇另外一個(gè)機(jī)架,而不是請(qǐng)求的節(jié)點(diǎn)所在的機(jī)架。
高占比資源公平分配
當(dāng)只需要調(diào)度一種資源時(shí),例如內(nèi)存,不管是使用容量調(diào)度器還是公平調(diào)度器都很容易分配。如果有兩個(gè)用戶的應(yīng)用需要運(yùn)行,你可以通過比較兩個(gè)應(yīng)用所需要的內(nèi)存來進(jìn)行分配。然而,當(dāng)有多種類型資源時(shí),事情就會(huì)變得更復(fù)雜一些。如果一個(gè)用戶的應(yīng)用需要大量的CPU,但是卻需要少量的內(nèi)存,其它用戶需要少量CPU,卻需要大量?jī)?nèi)存,那么這兩個(gè)應(yīng)用該怎么比較呢?
YARN框架中的調(diào)度器解決這個(gè)問題所使用的方法是看看每一個(gè)用戶的高占比資源是多少,然后使用這些高占比的資源做為集群資源占用的標(biāo)準(zhǔn)。這種方法被稱為"高占比資源公平分配或簡(jiǎn)稱DRF"[3]。下面用一個(gè)簡(jiǎn)單的例子加以說明。
假設(shè)一個(gè)集群一共有100個(gè)CPU和10TB的內(nèi)存。應(yīng)用A申請(qǐng)2CPU,300GB內(nèi)存的容器,應(yīng)用B則申請(qǐng)6CPU,100GB。A請(qǐng)求的資源分別占集群總資源的2%,3%,所以內(nèi)存是A應(yīng)用的高占比資源,因?yàn)?%比2%大。B請(qǐng)求的資源分別占集群總資源的6%,1%,所以CPU是高占比資源??梢钥闯觯透哒急荣Y源而言,B應(yīng)用請(qǐng)求的資源是A應(yīng)用的2倍(6%vs3%),所以在公平分配原則下,B應(yīng)用分到的容器數(shù)將是A應(yīng)用分到的一半。
默認(rèn)DRF沒有啟用,所以在資源計(jì)算中,僅僅只考慮內(nèi)存,不考慮CPU。容量調(diào)度器通過將capacity-scheduler.xml配置文件中的屬性yarn.scheduler.capacity.resource-calculator的值配置為org.apache.hadoop.yarn.util.resource.DominantResourceCalculator來啟用DRF。
至于公平調(diào)度器,則通過在配置文件配置頂級(jí)元素QueueSchedulingPolicy的值為drf啟用DRF。
延伸閱讀
這一章簡(jiǎn)單的概括性了解了一下YARN。如果想更詳細(xì)地了解,可以看Arun C. Murthy等人寫的《Apache Hadoop YARN》這本書。
本文是筆者翻譯自《OReilly.Hadoop.The.Definitive.Guide.4th.Edition》第一部分第4章,后續(xù)將繼續(xù)翻譯其它章節(jié)。雖盡力翻譯,但奈何水平有限,錯(cuò)誤再所難免,如果有問題,請(qǐng)不吝指出!希望本文對(duì)你有所幫助。
-
如果屬性yarn.scheduler.capacity.<queue-path>.user-limit-factor值比默認(rèn)的1大,則作業(yè)允許使用超過隊(duì)列容量的資源 ?
-
然而,容量調(diào)度器可以進(jìn)行預(yù)置進(jìn)程保護(hù), 資源管理器可以要求應(yīng)用釋放容器以平衡資源容量 ?
-
DRF是Ghodsi等人在2011年3月份發(fā)表的《高占比資源公平分配:多種資源的公平分配》這篇文章里提出來的 ?