系列文章:
大數據系列:一文初識Hdfs
大數據系列2:Hdfs的讀寫操作
大數據謝列3:Hdfs的HA實現
通過前文,我們對Hdfs的已經有了一定的瞭解,本文將繼續之前的內容,介紹Yarn
與Yarn
在MapReduce 2
的應用
MapReduce1 作業流程
在介紹Yarn
之前,我們先介紹一下Mapreduce1
作業流程。
有了這個基礎,再去看看採用Yarn
以後的MapReduce2
到底有啥優勢也許會有更好的理解。
首先先介紹一下相關的幾個實體:
Client
:負責提交MapReduce
作業jobtracker
:協調作業運行,是一個Jave程序,主類爲JobTracker
tasktracker
:運行作業劃分後的任務,是一個Jave程序,主類爲TaskTracker
Hdfs
:分佈式文件系統,用於在其他實體之間共享作業文件
作業流程圖如下:
-
MapReduce Program
調用runJob()
創建JobClient
並告知其提交作業。
在提交作業後runJob()
會每秒輪詢作業進度,如果發生改變就把進度輸出控制檯。
作業成後輸出作業計數器,如果失敗,則輸出失敗信息。 -
JobClient
通過調用JobTracker.getNewJobId()
請求一個新的JoobId
。 -
將運行作業需要的資源(作業
Ja
r文件,配置文件,計算所得的輸入分片)複製到以JobId
命名的目錄下jobtracker
的HDFS
中。
作業Jar的會有多個副本(mapred.submit.replication
默認10),在運行作業的時候,tasktracker
可以訪問多個副本。 -
調用
JobTracker.submitJob()
方法告知jobtracker
作業準備執行。 -
JobTracker
接收到對submitJob()
的調用後,會把改調用放入一個內部隊列,交由作業調度器(job scheduler
)進行調度。
同時會對Job
初始化,包括創建一個表示Job
正在運行的對象,用來封裝任務和記錄的信息,用於追蹤任務的狀態和進程。 -
爲了創建人物運行列表,作業調度器會從共享文件系統中獲取
JobCient
已經計算好的輸入分片信息。
然後爲每一個分片創建一個map
任務。
至於reduce
任務則由JonConf
的mapred.reduce.task
決定,通過setNumReduceTask()
設置,
然後調度器創建相應數量的reduce
任務。
此時會被指定任務ID
-
tasktracker
與jobtracker
之間維持一個心跳,
作爲消息通道,tasktracker
或告知自身存活情況與是否可以運行新的任務。
根據信息,jobtracker
會決定是否爲tasktracker
分配任務(通過調度算法)。
這個過程中,對於map
任務會考慮數據本地性,對於reduce
則不需要。 -
一旦
tasktracker
被分配了任務,接下里就是執行,首先通過Hdfs
把作業的Jar
文件複製到tasktracker
所在的文件系統。
實現作業Jar
本地化。
同時,tasktracker
把需要的文件從Hdfs
複製到本地磁盤。
然後爲任務建立一個本地工作目錄,並將Jar
中的內容解壓到這裏。
最後創建一個TaskRunner
實例運行該任務。 -
TaskerRunner
啓動一個新的JVM
用來運行每一個任務。 -
分別執行
MapTask
或者ReduceTask
,結束後告知TaskTracker
結束信息,同時TaskTracker
將該信息告知JobTracker
上面就是Maopreduce1
作業運行的流程。我們先有個概念,後面介紹Yarn
的時候做下對比。
這裏說的
Mapreduce1
指的是Hadoop
初始版本(版本1以及更早的)中的Mapreduce
分佈式執行框架,也就是我們上面的作業流程。
Mapreduce2
指的是使用Yarn
(Hadoop 2
以及以後版本)的Mapreduce
執行方式。
這裏Mapreduce1、Mapreduce2
指的不是Hadoop
版本,指的是Mapreduce
程序的不同執行機制而已。
Yarn
Yarn (Yet Another Resource Negotiator)
是在Hadoop 2
引入的集羣資源管理系統,最初的目的是爲了改善MapReduce
的實現。
但是由於其具有強大的通用性,可以支持其他的分佈式計算框架。
在引入的Yarn
後,Hadoop 2
的生態就發生了一變化,如下:
Yarn
提供請求和使用集羣資源的API
,但是一般都是由分佈式框架(Saprk、Flink
等)內部調用這些API
,
用戶則使用分佈式系統提供的更高層的API
。
這種方式向用戶隱藏了資源管理的細節,一定程度上降低了開發難度和運維成本。
Yarn
的結構很簡單,如下
Yarn
的核心思想是將資源管理和作業調度/監視功能拆分爲單獨的守護進程。
具體實現就是:
一個管理集羣上資源使用的全局資源管理器(RM,ResourceManager
);
運行在集羣所有結點上並且能夠啓動和監控容器(Container
)的結點管理器(Node Manager
)
Container
是用於執行特定應用程序的進程,每個資源都有資源限制(內存、CPU等)
Container
可以是Unix
進程,也可以Linux cgroup
Yarn的組成介紹就這麼簡單,接下來我們就看看它怎麼提交執行一個任務。
提交任務
這裏分爲兩部分,
第一部分會介紹Yarn任務提交流程,
第二部分會介紹Mapreduce 2 的提交流程
Yarn任務提交流程
Yarn
任務的提交流程如下:
-
爲了在
Yarn
上運行任務,Client
會向ResourceManager
發出運行Application Master process
的請求。 -
Resource Manager
找到一個可以運行Application Master
的NodeManager
。 -
NodeMager
啓動一個容器,運行Application Master
。 -
此
時Application Master
會做什麼操作取決於Application
本身,
可以是在在Application Master
執行一個簡單計算任務,將結果返回Client
,
也可以向Resource Manager
申請更多容器。 -
申請到更多的
container
。
從上面的步驟可以發現,Yarn
本身是不會爲應用的各個部分(Client, Master, Process
)之間提供交互。
大多數基於Yarn
的任務使用某些遠程通信機制(比如Hadoop RPC
)向客戶端傳遞信息。
這些RPC
通信機制一般都是專屬於該應用的。
MapReduce 2 任務提交流程
有了上面的基礎,具體的應用怎麼提交。
此處選用MapReduce 2
,與一開始MapReduce 1
做個對比
涉及到五個實體:
Client
:提交MapReduce job
的客戶端YARN Resource Manager
:負責協調分配集羣計算資源YARN Node Managers
:啓動並監視集羣中機器上的計算容器。MapReduce Application Master
:協調MapReduce job
的任務執行。HDFS
:用於在其他實體之間共享Job
文件
Application Master
和MapReduce Tasks
在容器中運行,他們由Resource Manager
調度,由Node Managers
管理
提交流程如下:
-
Job.sumbit()
方法創建一個內部的JobSummiter
實例,並調用其sunbmitJobInternal()
方法。
作業提交後,waitForCompletion()
會每秒輪詢返回作業的進度。
如果作業完成後,如果成功則顯示作業計數器,否則輸出錯誤。 -
JobSummiter
向Resource Manager
申請一個用於MapReduce job ID
的新Application ID
。
這個過程會檢查作業,輸出說明:
例如,如果沒有指定輸出目錄,或者輸出目錄已經存在,則不會提交作業,並向MapReduce
程序拋出錯誤;
計算作業的輸入分片。
如果無法計算分片(例如,因爲輸入路徑不存在),則作業不提交,並向MapReduce
程序拋出錯誤。 -
將運行作業需要的資源(作業
Jar
文件,配置文件,計算所得的輸入分片)複製到以JobId
命名的HDFS
的目錄下。
作業Jar
的會有多個副本(mapreduce.client.submit.file.replication
默認10),
當Node Managers
運行任務時,可以跨集羣訪問許多副本。 -
通過調用
Resource Manager
的submitApplication()
提交任務。 -
Resource Manager
收到submitApplication()
的調用請求後,將請求傳遞給Yarn
的調度器(Scheduler
)。
Scheduler
會爲其分配一個容器, -
Node Manager
在容器中啓動一個Application Master
,主類爲MRAppMaster
。 -
由於
MRAppMaster
將從任務接收進度和完成報告,它通過創建許多簿記對象(bookkeeping objects
)來初始化作業,以跟蹤作業的進度。 -
接下來,
MRAppMaster
從共享文件系統檢索在客戶機中計算的輸入切片,
它會爲每個切片建立一個map task;
建立mapreduce.job.reduces
(由Job.setNumReduceTasks()
)數量的reduce task
。
MRAppMaster
根據任務的情況決定是執行一個uber task
還是向Resource Manager
請求更多的資源。 -
MRAppMaster
向Resource Manager
爲job
中所有的map、reduce tasks
申請容器。 -
一旦
Resource Manager
的Scheduler
爲task
在指定的Node Manager
分配了容器以後,Application Master
就會請求Node Manager
分配容器。 -
Node Manager
收到請,啓動容器。容器中的主類爲YarnChild
,運行在專用的JVM
中,所以map、reduce
、甚至YarnChild
本身出現的錯誤都不會影響Node Manager
。 -
在運行
task
之前,YarnChild
會對任務需要的資源進行本地化,包括job
配置、JAR
文件以及其他來自Hdfs
的文件。 -
最後執行
map 或 reduce
任務。
關於的ubertask
細節說明:
MRAppMaster
必須決定如何運行MapReduce job
。
利用並行的優勢,確實可以提高任務的執行效率,
但是在小任務或少任務的情況下,
在新的容器中分配和運行任務所額外消耗的時間大於並行執行帶來效率的提升。
這個時候在一個節點上順序運行這些任務反而能獲得更好的效率。
這樣的job被稱爲uber task
簡單的說就是並行執行的時候任務效率的提升還不夠彌補你重新申請資源、創建容器、分發任務等消耗的時間。
那麼怎樣纔算small job
呢?
默認情況下:small job
是有少於10個mapper
,只有一個reducer
,一個輸入大小小於一個HDFS Block
大小的job。
當然也可以通過參數 mapreduce.job.ubertask.maxmaps
,mapreduce.job.ubertask.maxreduces
, mapreduce.job.ubertask.maxbytes
進行設置。
對於Ubertasks
,mapreduce.job.ubertask.enable
必須設置爲true
。
對於步驟9補充說明:
在這個過程中,會先申請map
任務的容器,
因爲所有的map任務都必須在reduce的排序階段開始之前完成(Shuffle and Sort機制
)。
對reduce
任務的請求直到5%的map
任務完成纔會發出(reduce slow start機制
)。
對於reduce
任務,可以在集羣的任何結點運行,
但是對map
任務,會有數據本地性的要求(詳情此處不展開)
申請還爲任務指定內存和cpu
。默認情況下,每個map
和reduce
任務分配1024 MB
內存和1個虛擬核,
可以通過mapreduce.map.memory.mb
, mapreduce.reduce.memory.mb
, mapreduce.map.cpu.vcores
和 mapreduce.reduce.cpu.vcores
進行配置
Yarn 與mapreduce 1
上面就是Mapreduce2
的任務提交執行流程,一開始我們就介紹了Mapreduce1
,現在我們對比下兩個有啥區別。
本質就是結合
Mapreduce 2
對比Yarn
與Mapreduce1
調度的區別,所以後面Mapreduce 2
直接用Yarn
替換
Mapreduce 1
中,作業執行過程由兩類守護進程控制,分別爲一個jobtracker
和多個tasktracker
。
jobtracker
通過調度tasktracker
上的任務來協調運行在系統的Job
,並記錄返回的任務進度。
tasktracker
負責運行任務並向`jobtracker``發送任務進度。
jobtracker
同時負責作業的調度(分配任務與tasktracker
匹配)和任務進度監控(任務跟蹤、失敗重啓、記錄流水、維護進度、計數器等)
Yarn
中,也有兩類守護進程Resource Manager
和Nonde Manager
分別類比jobtracker
和tasktracker
。
但是不一樣的地方在於,jobtracker
的職責在Yarn
中被拆分,由兩個實體Reource Manger
和``Application Master```(每個Job有一個)。
jobtracker
也可以存儲作業歷史,或者通過運行一個獨立守護進程作爲歷史作業服務器。而與對應的,Yarn
提供一個時間軸服務器(timeline server
)來存儲應用的歷史。
二者組成類比
Mapreduce 1 | Yarn |
---|---|
jobtracker |
Reource Manger Application Master timeline server |
tasktracker |
Nonde Manager |
Slot |
container |
對於二者的區別,心血來潮想了個例子,希望能夠幫助理解。
有三個角色:皇帝、大臣、打工人
現在有兩個情況,
1:發生水災,需要賑災
2:敵寇入侵,邊疆告急
在這種情況下 Mapreduce 1
的做法是:
Yarn
的做法:
簡單的說,就是Yarn
讓專業的人做專業的事情。
遇到事情找個專家,我只負責提需求和提供資源,
其他的讓專家去做。
這個專家就是
MRAppMaster(Mapreduce)
,而對應的Spark也有自己的專家
由此也總結下Yarn
帶來的優勢:
- 可拓展性(
Scalability
)
Yarn
可以在比MapReduce 1
更大的集羣上運行。
MapReduce 1
在4000個節點和40000個任務的時候達到拓展性的瓶頸。
主要是因爲jobtracker
需要管理作業和任務。
Yarn
就拆分了這個,將作業與任務拆分,由Manager/Application Master
分別負責,可以輕鬆將拓展至10,000 個節點 100,000 個任務。 - 可用性(
Availability)
高可用性(HA)通常是通過複製另一個守護進程所需的狀態來實現的,以便在活躍狀態的守護進程掛掉時接管提供服務所需的工作。
但是,jobtracker
的內存中有大量快速變化的複雜狀態(例如,每個任務狀態每隔幾秒更新一次),這使得將在jobtracker
服務配置HA非常困難。
而對於Yarn
而言,由於職責被拆分,那麼HA
也隨之變成了分治問題。
可以先提供Resource Manager
的HA,同時如果有需要可以爲每個人應用也提供HA。
實際上對於
Mapreduce 2
對Resource Manager
和Application Master
都提供了HA,稍候介紹。
- 利用率(
Utilization
)
MapReduce 1
中,每個tasktracker
都靜態配置若干個slot
,在配置的時候被劃分爲map slot
和reduce slot
,只能執行固定的任務。
而在Yarn
中,Node Manager
管理一個資源池,只要有資源,任務就可以運行。
同時資源是精細化管理的,任務可以按需申請資源。 - 多租戶(
Multitenancy
)
其實,某種程度上來說,統一的資源管理,向其他分佈式應用開放Hadoop
纔是Yarn
的最大優勢。
比如我們可以部署Spark、Flink
等等。此時MapReduce
也僅僅是在這之上的一個應用罷了
High Availability
接下來再說一下HA吧。
這裏主要結合Mapreduce 2
來說明
HA 針對的都是出現錯誤或失敗的情況。
在我們這裏,出現錯誤或失敗的場景有以下幾個
- 任務失敗
Application Master
失敗Node Manager
失敗Resource Manager
失敗
接下來我們分別看看這些情況怎麼解決。
task 失敗
任務失敗的情況有可能出現下面的情況:
- 用戶
map、reduce task
代碼問題,這種失敗最常見,此時在task JVM
在退出前會向Application Master
發送錯誤報告,該報告會被計入用戶日誌。最後Application Master
會將該任務將任務嘗試標記爲failed
,並釋放容器,使其資源可供另一個任務使用。 - 另一種情況是
task JVM
突然退出,可能存在一個JVM bug
,導致JVM在特定環境下退出MapReduce
的用戶代碼。
這種情況下,Node Manager
發現進程已經退出,會告知Application Master
,並將任務嘗試標記爲failed
。 - 還有一種是任務超時或者掛起,一旦
Application Master
注意到有一段時間沒有收到任務進度更新了,就會將該任務標記爲failed
,由參數mapreduce.task.timeout
(默認10分鐘,0表示關閉超時,此時長時間運行任務永遠不會標記爲failed
,慎用)設置。
task 失敗的處理方式:
Application Master
發現任務失敗後,會重新調度該任務,會進行避免在之前失敗的Node Manager
上調度該任務。
如果一個任務連續失敗四次(mapreduce.map.maxattempts
,mapreduce.reduce.maxattempts
),就不會繼續重調,整個Job也就失敗。- 而有些場景在少數任務失敗,結果仍舊可以使用,那麼此時我們不希望停止任務,可以配置一個允許任務失敗的閥值(百分比),此時不會觸發Job失敗。
通過mapreduce.map.failures.maxpercent
、mapreduce.reduce.failures.maxpercent
設置。 - 還有一個情況是任務嘗試被kill,這種情況
Application Master
制動標記killed
不屬於任務失敗。
推測機制(Speculative Execution),如果發現task執行的時間運行速度明顯慢於平均水平,就會在其他的結點啓動一個相同的任務,稱爲推測執行。
這個不一定有效,僅僅是投機性的嘗試。
當任務成功完成時,任何正在運行的重複任務都將被終止,因爲不再需要它們。
就是推測任務與原始任務誰能上位就看誰先完成了。
Application Master 失敗
當遇到Application Master
失敗時,Yarn
也會進行嘗試。
可以通過配置mapreduce.am.max-attempts property
(默認:2)配置重試次數,
同時,Yarn
對於集羣中運行的Application Master
最大嘗試次數加了限制,也需要通過 yarn.resourcemanager.am.max-attempts
(默認:2)進行配置。
重試的流程如下:
Application Master
向Resource Manager
發送心跳,如果Application Master
發生故障,Resource Manager
將檢測故障,並在新的容器中啓動運行Application Master
的新實例
在MapReduce,它可以使用作業歷史記錄來恢復(失敗的)應用程序已經運行的任務的狀態,這樣它們就不必重新運行。
默認情況下恢復是啓用的,但是可以通過設置yarn.app.mapreduce.am.job.recovery
來禁用。
MapReduce client
輪詢Application Master
的進度報告,
但如果它的Application Master
失敗,客戶端需要定位新的實例。
在Job
初始化期間,client
向Resource Manager
請求Application Master
的地址,然後對其進行緩存,這樣在每次需要輪詢Application Master
時,
就不會向Resource Manager
發出請求,從而使Resource Manager
負擔過重。
但是,如果Application Master
失敗,client
將發出狀態更新時超時,此時client
將向Resource Manager
請求新的Application Master
的地址。
Node Manager 失敗
如果Node Manager
因崩潰或運行緩慢而發生故障,它將停止向Resource Manager
發送心跳(或發送頻率非常低)。
Resource Manager
如果在10分鐘內(yarn.resourcemanager.nm.liveness-monitor.expiry-interval-ms
)沒有收到Node Manager
的心跳信息,
就會告訴該Node Manager
,停止發送心跳,並將它從自己的Nodes
池中移除。
在此Node Manager
失敗的task
或 Application Master
都會按照之前的說的方式恢復。
此外,即使map tasks
在失敗的Node Manager
上運行併成功完成但屬於未完成的job
,
Application Master
也會安排它們重新運行,
因爲它們的中間輸出駐留在故障Node Manager
的本地文件系統上,reduce
任務可能無法訪問。
如果一個Node Manager
失敗任務次數過多,該Node Manager
會被Application Master
拉入黑名單。
對於 MapReduce,如果一個Job在某個
Node Manager
失敗3個任務(mapreduce.job.maxtaskfailures.per.tracker
),就會嘗試在其他的結點進行調度。
注意,Resource Manager
不會跨應用程序執行黑名單(編寫時),
因此來自新作業的任務可能會在壞節點上調度,即使它們已被運行較早作業的應用程序主程序列入黑名單。
Resource Manager 失敗
Resource Manager
失敗是很嚴重的,一旦它失敗, job
和task
容器都無法啓動。
在默認配置中,Resource Manager
是一個單故障點,因爲在(不太可能的)機器故障的情況下,所有正在運行的作業都失敗了並且無法恢復。
要實現高可用性(HA),必須在一個active-standby
配置中運行一對Resource Manager
。
如果 active Resource Manager
發生故障,則standby Resource Manager
可以接管,而不會對client
造成重大中斷。
通過將運行中的應用程序信息存儲在高可用的狀態存儲區中(通過ZooKeeper/HDFS
備份),實現standby Resource Manager
恢復active Resource Manager
(失敗)的關鍵狀態。
Node Manager
信息沒有存儲在狀態存儲中,因爲當Node Manager
發出第一次心跳時,新的Resource Manager
可以相對較快地對其進行重構。
因爲
task
由Application Master
管理,所以task
不屬於Resource Manager
的狀態,因此於Resource Manager
存儲的狀態比jobtracker
中的狀態更容易管理。
目前,有兩種持久化RMStateStore的方式,分別爲:FileSystemRMStateStore
和ZKRMStateStore
。
整體架構如下:
我們可以通過手動或自動重啓ResourceManager
。
被提升爲active 狀態的ResourceManager加載ResourceManager內部狀態,並根據ResourceManager restart特性儘可能從上一個active Resource Manager 離開的地方繼續操作。
對於以前提交給ResourceManager的每個託管Application,都會產生一個新的嘗試。
應用程序可以定期checkpoint,以避免丟失任何工作。
狀態存儲必須在兩個Active/Standby Resource Managers中都可見。
從上圖可以看到我們可以選擇的狀態存儲介質有兩個FileSystemRMStateStore
和 ZKRMStateStore
。
ZKRMStateStore
隱式地允許在任何時間點對單ResourceManagers
進行寫訪問,
因此在HA集羣中推薦使用ZKRMStateStore。
在使用ZKRMStateStore
時,不需要單獨的防禦機制來解決可能出現的腦裂情況,即多個Resource Manager
可能扮演active
角色。
並且ResourceManager
可以選擇嵌入基於zookeeper
的ActiveStandbyElector
來決定哪個Resource Manager
應該是active
的。
當active
的ResourceManager
關閉或失去響應時,另一個Resource Manager
會自動被選爲active
,然後由它接管。
注意,不需要像HDFS那樣運行一個單獨的
ZKFC
守護進程,因爲嵌入在Resource Manager
中的ActiveStandbyElector
充當故障檢測器和leader elector
,所以不需要單獨的ZKFC
守護進程。
關於Yarn的內容就介紹到這裏,更詳細的內容可以參考官網
之後會更新一些Hdfs讀寫的源碼追蹤相關文章,有興趣可以關注【兔八哥雜談】