大數據系列4:Yarn以及MapReduce 2

系列文章:
大數據系列:一文初識Hdfs
大數據系列2:Hdfs的讀寫操作
大數據謝列3:Hdfs的HA實現

通過前文,我們對Hdfs的已經有了一定的瞭解,本文將繼續之前的內容,介紹YarnYarnMapReduce 2的應用


MapReduce1 作業流程

在介紹Yarn之前,我們先介紹一下Mapreduce1作業流程。

有了這個基礎,再去看看採用Yarn以後的MapReduce2到底有啥優勢也許會有更好的理解。

首先先介紹一下相關的幾個實體:

  1. Client:負責提交 MapReduce 作業
  2. jobtracker:協調作業運行,是一個Jave程序,主類爲JobTracker
  3. tasktracker:運行作業劃分後的任務,是一個Jave程序,主類爲TaskTracker
  4. Hdfs:分佈式文件系統,用於在其他實體之間共享作業文件

作業流程圖如下:

  1. MapReduce Program 調用runJob()創建JobClient並告知其提交作業。
    在提交作業後runJob()會每秒輪詢作業進度,如果發生改變就把進度輸出控制檯。
    作業成後輸出作業計數器,如果失敗,則輸出失敗信息。

  2. JobClient通過調用JobTracker.getNewJobId()請求一個新的JoobId

  3. 將運行作業需要的資源(作業Jar文件,配置文件,計算所得的輸入分片)複製到以JobId命名的目錄下jobtrackerHDFS中。
    作業Jar的會有多個副本(mapred.submit.replication默認10),在運行作業的時候,tasktracker可以訪問多個副本。

  4. 調用JobTracker.submitJob()方法告知jobtracker作業準備執行。

  5. JobTracker接收到對submitJob()的調用後,會把改調用放入一個內部隊列,交由作業調度器(job scheduler)進行調度。
    同時會對Job初始化,包括創建一個表示Job正在運行的對象,用來封裝任務和記錄的信息,用於追蹤任務的狀態和進程。

  6. 爲了創建人物運行列表,作業調度器會從共享文件系統中獲取JobCient已經計算好的輸入分片信息。
    然後爲每一個分片創建一個map任務。
    至於reduce任務則由JonConfmapred.reduce.task決定,通過setNumReduceTask()設置,
    然後調度器創建相應數量的reduce任務。
    此時會被指定任務ID

  7. tasktrackerjobtracker之間維持一個心跳,
    作爲消息通道,tasktracker或告知自身存活情況與是否可以運行新的任務。
    根據信息,jobtracker會決定是否爲tasktracker分配任務(通過調度算法)。
    這個過程中,對於map任務會考慮數據本地性,對於reduce則不需要。

  8. 一旦tasktracker被分配了任務,接下里就是執行,首先通過Hdfs把作業的Jar文件複製到tasktracker所在的文件系統。
    實現作業Jar本地化。
    同時,tasktracker把需要的文件從Hdfs複製到本地磁盤。
    然後爲任務建立一個本地工作目錄,並將Jar中的內容解壓到這裏。
    最後創建一個TaskRunner實例運行該任務。

  9. TaskerRunner啓動一個新的JVM用來運行每一個任務。

  10. 分別執行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 任務的提交流程如下:

  1. 爲了在Yarn上運行任務,Client會向ResourceManager發出運行 Application Master process的請求。

  2. Resource Manager找到一個可以運行Application MasterNodeManager

  3. NodeMager啓動一個容器,運行Application Master

  4. 時Application Master會做什麼操作取決於Application本身,
    可以是在在Application Master執行一個簡單計算任務,將結果返回Client
    也可以向Resource Manager申請更多容器。

  5. 申請到更多的container

從上面的步驟可以發現,Yarn本身是不會爲應用的各個部分(Client, Master, Process)之間提供交互。
大多數基於Yarn的任務使用某些遠程通信機制(比如Hadoop RPC)向客戶端傳遞信息。
這些RPC通信機制一般都是專屬於該應用的。


MapReduce 2 任務提交流程

有了上面的基礎,具體的應用怎麼提交。
此處選用MapReduce 2,與一開始MapReduce 1做個對比

涉及到五個實體:

  1. Client:提交 MapReduce job的客戶端
  2. YARN Resource Manager:負責協調分配集羣計算資源
  3. YARN Node Managers:啓動並監視集羣中機器上的計算容器。
  4. MapReduce Application Master:協調MapReduce job的任務執行。
  5. HDFS:用於在其他實體之間共享Job文件

Application MasterMapReduce Tasks 在容器中運行,他們由Resource Manager調度,由Node Managers管理

提交流程如下:

  1. Job.sumbit()方法創建一個內部的JobSummiter實例,並調用其sunbmitJobInternal()方法。
    作業提交後,waitForCompletion()會每秒輪詢返回作業的進度。
    如果作業完成後,如果成功則顯示作業計數器,否則輸出錯誤。

  2. JobSummiterResource Manager申請一個用於 MapReduce job ID的新Application ID
    這個過程會檢查作業,輸出說明:
    例如,如果沒有指定輸出目錄,或者輸出目錄已經存在,則不會提交作業,並向MapReduce程序拋出錯誤;
    計算作業的輸入分片。
    如果無法計算分片(例如,因爲輸入路徑不存在),則作業不提交,並向MapReduce程序拋出錯誤。

  3. 將運行作業需要的資源(作業Jar文件,配置文件,計算所得的輸入分片)複製到以JobId命名的HDFS的目錄下。
    作業Jar的會有多個副本(mapreduce.client.submit.file.replication默認10),
    Node Managers運行任務時,可以跨集羣訪問許多副本。

  4. 通過調用Resource ManagersubmitApplication()提交任務。

  5. Resource Manager收到submitApplication()的調用請求後,將請求傳遞給Yarn的調度器(Scheduler)。
    Scheduler會爲其分配一個容器,

  6. Node Manager在容器中啓動一個Application Master,主類爲MRAppMaster

  7. 由於MRAppMaster將從任務接收進度和完成報告,它通過創建許多簿記對象(bookkeeping objects)來初始化作業,以跟蹤作業的進度。

  8. 接下來,MRAppMaster從共享文件系統檢索在客戶機中計算的輸入切片,
    它會爲每個切片建立一個map task;
    建立mapreduce.job.reduces(由Job.setNumReduceTasks())數量的reduce task
    MRAppMaster根據任務的情況決定是執行一個uber task還是向Resource Manager請求更多的資源。

  9. MRAppMasterResource Managerjob中所有的map、reduce tasks申請容器。

  10. 一旦Resource ManagerSchedulertask在指定的Node Manager分配了容器以後,Application Master就會請求Node Manager分配容器。

  11. Node Manager收到請,啓動容器。容器中的主類爲YarnChild,運行在專用的JVM中,所以map、reduce、甚至YarnChild本身出現的錯誤都不會影響Node Manager

  12. 在運行task之前,YarnChild會對任務需要的資源進行本地化,包括job配置、JAR文件以及其他來自Hdfs的文件。

  13. 最後執行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。默認情況下,每個mapreduce任務分配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 對比YarnMapreduce1調度的區別,所以後面Mapreduce 2 直接用Yarn替換

Mapreduce 1 中,作業執行過程由兩類守護進程控制,分別爲一個jobtracker和多個tasktracker

jobtracker 通過調度tasktracker上的任務來協調運行在系統的Job,並記錄返回的任務進度。
tasktracker負責運行任務並向`jobtracker``發送任務進度。

jobtracker同時負責作業的調度(分配任務與tasktracker匹配)和任務進度監控(任務跟蹤、失敗重啓、記錄流水、維護進度、計數器等)

Yarn 中,也有兩類守護進程Resource ManagerNonde Manager分別類比jobtrackertasktracker

但是不一樣的地方在於,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帶來的優勢:

  1. 可拓展性(Scalability)
    Yarn可以在比MapReduce 1更大的集羣上運行。
    MapReduce 1在4000個節點和40000個任務的時候達到拓展性的瓶頸。
    主要是因爲jobtracker需要管理作業和任務。
    Yarn就拆分了這個,將作業與任務拆分,由Manager/Application Master分別負責,可以輕鬆將拓展至10,000 個節點 100,000 個任務。
  2. 可用性(Availability)
    高可用性(HA)通常是通過複製另一個守護進程所需的狀態來實現的,以便在活躍狀態的守護進程掛掉時接管提供服務所需的工作。
    但是,jobtracker的內存中有大量快速變化的複雜狀態(例如,每個任務狀態每隔幾秒更新一次),這使得將在jobtracker服務配置HA非常困難。
    而對於Yarn而言,由於職責被拆分,那麼HA也隨之變成了分治問題。
    可以先提供Resource Manager的HA,同時如果有需要可以爲每個人應用也提供HA。

實際上對於Mapreduce 2Resource ManagerApplication Master都提供了HA,稍候介紹。

  1. 利用率(Utilization)
    MapReduce 1 中,每個tasktracker都靜態配置若干個slot,在配置的時候被劃分爲map slotreduce slot,只能執行固定的任務。
    而在Yarn中,Node Manager管理一個資源池,只要有資源,任務就可以運行。
    同時資源是精細化管理的,任務可以按需申請資源。
  2. 多租戶(Multitenancy
    其實,某種程度上來說,統一的資源管理,向其他分佈式應用開放Hadoop纔是Yarn的最大優勢。
    比如我們可以部署Spark、Flink等等。此時MapReduce也僅僅是在這之上的一個應用罷了

High Availability

接下來再說一下HA吧。
這裏主要結合Mapreduce 2 來說明
HA 針對的都是出現錯誤或失敗的情況。
在我們這裏,出現錯誤或失敗的場景有以下幾個

  1. 任務失敗
  2. Application Master失敗
  3. Node Manager失敗
  4. Resource Manager失敗

接下來我們分別看看這些情況怎麼解決。


task 失敗

任務失敗的情況有可能出現下面的情況:

  1. 用戶map、reduce task代碼問題,這種失敗最常見,此時在task JVM在退出前會向Application Master發送錯誤報告,該報告會被計入用戶日誌。最後Application Master會將該任務將任務嘗試標記爲failed,並釋放容器,使其資源可供另一個任務使用。
  2. 另一種情況是task JVM突然退出,可能存在一個JVM bug,導致JVM在特定環境下退出MapReduce的用戶代碼。
    這種情況下,Node Manager發現進程已經退出,會告知Application Master,並將任務嘗試標記爲failed
  3. 還有一種是任務超時或者掛起,一旦Application Master注意到有一段時間沒有收到任務進度更新了,就會將該任務標記爲failed,由參數mapreduce.task.timeout(默認10分鐘,0表示關閉超時,此時長時間運行任務永遠不會標記爲failed,慎用)設置。

task 失敗的處理方式:

  1. Application Master發現任務失敗後,會重新調度該任務,會進行避免在之前失敗的Node Manager上調度該任務。
    如果一個任務連續失敗四次(mapreduce.map.maxattempts,mapreduce.reduce.maxattempts),就不會繼續重調,整個Job也就失敗。
  2. 而有些場景在少數任務失敗,結果仍舊可以使用,那麼此時我們不希望停止任務,可以配置一個允許任務失敗的閥值(百分比),此時不會觸發Job失敗。
    通過mapreduce.map.failures.maxpercentmapreduce.reduce.failures.maxpercent設置。
  3. 還有一個情況是任務嘗試被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 MasterResource Manager發送心跳,如果Application Master發生故障,Resource Manager將檢測故障,並在新的容器中啓動運行Application Master的新實例

在MapReduce,它可以使用作業歷史記錄來恢復(失敗的)應用程序已經運行的任務的狀態,這樣它們就不必重新運行。
默認情況下恢復是啓用的,但是可以通過設置yarn.app.mapreduce.am.job.recovery來禁用。


MapReduce client輪詢Application Master的進度報告,
但如果它的Application Master失敗,客戶端需要定位新的實例。

Job初始化期間,clientResource 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失敗的taskApplication 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失敗是很嚴重的,一旦它失敗, jobtask容器都無法啓動。
在默認配置中,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可以相對較快地對其進行重構。

因爲taskApplication Master管理,所以task不屬於Resource Manager的狀態,因此於Resource Manager存儲的狀態比jobtracker中的狀態更容易管理。

目前,有兩種持久化RMStateStore的方式,分別爲:FileSystemRMStateStoreZKRMStateStore

整體架構如下:

我們可以通過手動或自動重啓ResourceManager

被提升爲active 狀態的ResourceManager加載ResourceManager內部狀態,並根據ResourceManager restart特性儘可能從上一個active Resource Manager 離開的地方繼續操作。

對於以前提交給ResourceManager的每個託管Application,都會產生一個新的嘗試。
應用程序可以定期checkpoint,以避免丟失任何工作。
狀態存儲必須在兩個Active/Standby Resource Managers中都可見。

從上圖可以看到我們可以選擇的狀態存儲介質有兩個FileSystemRMStateStoreZKRMStateStore

ZKRMStateStore隱式地允許在任何時間點對單ResourceManagers進行寫訪問,
因此在HA集羣中推薦使用ZKRMStateStore。

在使用ZKRMStateStore時,不需要單獨的防禦機制來解決可能出現的腦裂情況,即多個Resource Manager可能扮演active角色。

並且ResourceManager可以選擇嵌入基於zookeeperActiveStandbyElector來決定哪個Resource Manager應該是active的。
activeResourceManager關閉或失去響應時,另一個Resource Manager會自動被選爲active,然後由它接管。

注意,不需要像HDFS那樣運行一個單獨的ZKFC守護進程,因爲嵌入在Resource Manager中的ActiveStandbyElector充當故障檢測器和leader elector,所以不需要單獨的ZKFC守護進程。


關於Yarn的內容就介紹到這裏,更詳細的內容可以參考官網

之後會更新一些Hdfs讀寫的源碼追蹤相關文章,有興趣可以關注【兔八哥雜談】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章