Hadoop運行原理總結(詳細)

  本編隨筆是小編我的參照我的的筆記、官方文檔以及網上的資料等後對HDFS的概念以及運行原理進行系統性地概括,提及來真的慚愧呀,自學了很長一段時間也沒有對Hadoop知識點進行概括,有時候在實戰中或者與別人交流Hadoop相關技術時,不少概念也只是模模糊糊記得,並不是很熟練。哈哈哈,趁着最後一個暑假,把本身這兩年自學的大數據開發技術都系統性概括,省得之後本身忘記了,順便分享到本身的博客上,也給初學者等有須要的人蔘考。html

  寫博客不易,若是文章有錯誤,請指出,以爲不錯的話,請給個贊哈,謝謝~前端

一、HDFS的介紹

  Hadoop分佈式文件系統(HDFS)被設計成適合運行在通用硬件(commodity hardware)上的分佈式文件系統。它和現有的分佈式文件系統有不少共同點。但同時,它和其餘的分佈式文件系統的區別也是很明顯的。HDFS是一個高度容錯性的系統,適合部署在廉價的機器上。HDFS能提供高吞吐量的數據訪問,很是適合大規模數據集上的應用。HDFS放寬了一部分POSIX約束,來實現流式讀取文件系統數據的目的。HDFS在最開始是做爲Apache Nutch搜索引擎項目的基礎架構而開發的。HDFS是Apache Hadoop Core項目的一部分。java

  Hadoop 是Apache基金會下一個開源的分佈式計算平臺,它以分佈式文件系統HDFS和MapReduce算法爲核心,爲用戶提供了系統底層細節透明的分佈式基礎架構。用戶能夠在不瞭解分佈式底層細節的狀況下,充分利用分佈式集羣進行高速運算和存儲。node

  Hadoop是一個可以讓用戶輕鬆架構和使用的分佈式計算平臺。它主要有如下幾個 優勢:  
  ① 高可靠性。Hadoop按位存儲和處理數據的能力值得人們信賴。  
  ② 高擴展性。Hadoop是在可用的計算機集簇間分配數據並完成計算任務的,這些集簇能夠方便地擴展到數以千計的節點中。  
  ③ 高效性。Hadoop可以在節點之間動態地移動數據,並保證各個節點的動態平衡,所以處理速度很是快。  
  ④ 高容錯性。Hadoop可以自動保存數據的多個副本,而且可以自動將失敗的任務從新分配。  
  ⑤ 低成本。與一體機、商用數據倉庫以及QlikView、Yonghong Z-Suite等數據集市相比,Hadoop是開源的,項目的軟件成本所以會大大下降。  

  缺點:  算法

  ①不適合低延遲數據訪問。  
  ②沒法高效存儲大量小文件,會佔用大量的namenode內存。  
  ③不支持多用戶寫入以及任意修改文件。
 

二、 HDFS的架構與設計

  2.1 HDFS的設計

  HDFS以流式數據訪問模式來存儲超大文件,運行於商用硬件集羣上。apache

  如下是對HDFS的設計簡單描述(詳細能夠參閱該文章):vim

  • 超大文件 :「超大文件」在這裏指具備幾百MB、幾百GB甚至幾百TB大小的文件。目前已經有存儲PB級數據的Hadoop集羣了。
  • 流式數據訪問 :HDFS的構建思路是這樣的:一次寫入、屢次讀取是最高效的訪問模式。數據集一般由數據源生成或從數據源複製而來,接着長時間 在此數據集上進行各類分析。每次分析都將涉及該數據集的大部分數據甚至所有,所以讀取整個數據集的時間延遲比讀取第一條記錄的時間延遲更重要。
  • 商用硬件 :Hadoop並不須要運行在昂貴且高可靠的硬件上。
  • 低時間延遲的數據訪問 :要求低時間延遲數據訪問的應用,例如幾十毫秒範圍,不適合在HDFS上運行。HDFS是爲高數據吞吐量應用優化的,這可能會以提升時間延遲爲代價。對於低延遲的訪問需求,HBase是更好的選擇。
  • 大量的小文件 :因爲namenode將文件系統的元數據存儲在內存中,所以該文件系統所能存儲的文件總數受限於NameNode的內存容量。
  • 多用戶寫入,任意修改文件 :HDFS中的文件寫入只支持單個寫入者,並且寫操做老是以「只添加」方式在文件末尾寫數據。它不支持多個寫入者的操做,也不支持在文件的任意位置進行修改。但可能之後會支持,不過這種相對比較低效。

  2.2 HDFS核心組件

  HDFS採用master/slave架構。一個HDFS集羣是有一個Namenode和必定數目的Datanode組成。Namenode是一箇中心服務器,負責管理文件系統的namespace和客戶端對文件的訪問。Datanode在集羣中通常是一個節點一個,負責管理節點上它們附帶的存儲。在內部,一個文件其實分紅一個或多個block,這些block存儲在Datanode集合裏。Namenode執行文件系統的namespace操做,例如打開、關閉、重命名文件和目錄,同時決定block到具體Datanode節點的映射。Datanode在Namenode的指揮下進行block的建立、刪除和複製。Namenode和Datanode都是設計成能夠跑在普通的廉價的運行Linux的機器上。HDFS採用java語言開發,所以能夠部署在很大範圍的機器上。一個典型的部署場景是一臺機器跑一個單獨的Namenode節點,集羣中的其餘機器各跑一個Datanode實例。這個架構並不排除一臺機器上跑多個Datanode,不過這比較少見。集羣中單一Namenode的結構大大簡化了系統的架構。Namenode是全部HDFS元數據的仲裁者和管理者,這樣,用戶數據永遠不會流過Namenode。緩存

  下圖是Hadoop的架構設計圖:安全

Hadoop的架構設計圖服務器

  

三、HDFS的概念

  3.1 數據塊

  每一個磁盤都有默認的數據塊大小,這是磁盤進行數據讀/寫的最小單位。構建於單個磁盤之上的文件系統經過磁盤塊來管理該文件系統中的塊,該文件系統塊的大小能夠是磁盤塊的整數倍。文件系統塊通常爲幾千字節,而磁盤塊通常爲512字節。但這些對於須要讀/寫文件的文件系統用戶來講是透明的。

  HDFS一樣也有塊(block)的概念,可是大得多,默認爲128MB。與單一磁盤上的文件系統類似,HDFS上的文件也被劃分爲塊大小的多個分塊,做爲獨立的存儲單元。但與面向單一磁盤的文件系統不一樣的是,HDFS中小於一個塊大小的文件不會佔據整個塊的空間,例如當一個1MB的文件存儲在一個128MB的塊中時,文件只使用1MB的磁盤空間,而不是128MB。

  HDFS中的塊爲何這麼大?HDFS的塊比磁盤的塊大,其目的是爲了最小化尋址開銷。若是塊足夠大,從磁盤傳輸數據的時間會明顯大於定位這個塊開始位置所需的時間。由於,傳輸一個由多個塊組成的大文件的時間取決於磁盤傳輸速率。可是塊大小這個參數也不會設置得過大,MapReduce中map任務一般一次只處理一個塊中的數據,所以若是任務數太少(少於集羣中的節點數量),做業的運行速度就會比較慢。

  對分佈式文件系統中的塊進行抽象會帶來不少好處。

  1. 第一好處是一個文件的大小能夠大於網絡中任意一個磁盤的容量。
  2. 第二個好處是使用抽象塊而非整個文件做爲存儲單元,大大簡化了存儲子系統的設計。
  3. 第三個好處是塊還很是適合用於數據備份進而提供數據容錯能力和提升可用性。

  HDFS將每一個塊複製到少數幾個物理上相互獨立的機器上(默認爲3個),能夠確保在塊、磁盤或機器發生故障後數據不會丟失。若是發現一個塊不可用,系統會從其餘地方讀取另外一個複本,而這個過程對用戶是透明的。一個因損壞或機器故障而丟失的塊能夠從其餘候選地點複製到另外一臺能夠正常運行的機器上,以保證複本的數量回到正常水平。一樣,有些應用程序可能選擇爲一些經常使用的文件塊設置更高的複本數量進而分散集羣中的讀取負載。

  在HDFS中顯示塊信息:

# hdfs fsck / -files -blocks

   能夠執行命令修改HDFS的數據塊大小以及複本數量:

# vim $HADOOP_HOME/etc/hadoop/hdfs-site.xml

 

  3.2 NameNode(管理節點)

  3.2.1 NameNode目錄結構

  運行中的NameNode有以下所示的目錄結構:

  

  •  VERSION文件 :是一個Java屬性文件,其中包含正在運行的HDFS的版本信息。該文件通常包含如下內容:
#Mon Sep 29 09:54:36 BST 2014
namespaceID=1342387246
clusterID=CID-01b5c398-959c-4ea8-aae6-1e0d9bd8b142
cTime=0
storageType=NAME_NODE
blockpoolID=BP-526805057-127.0.0.1-1411980876842
layoutVersion=-57
    • layoutVersion :這是一個負整數,描述HDFS持久性數據結構(也稱佈局)的版本,可是該版本號與Hadoop發佈包的版本號無關。只要佈局變動,版本號將會遞減,此時HDFS也要升級。不然,新版本的NameNode(或DataNode)就沒法正常工做。
    • namespaceID :文件系統命名空間的惟一標識符,是在NameNode首次格式化時建立的。
    • clusterID : 在HDFS集羣上做爲一個總體賦予的惟一標識符,這對於聯邦HDFS很是重要。
    • blockpoolID :數據塊池的惟一標識符,數據塊池中包含了由一個NameNode管理的命名空間中的全部文件。
    • cTime :標記了NameNode存儲系統的建立時間。剛格式化的存儲系統,值爲0,但升級後,該值會更新到新的時間戳。
    • storageType :該存儲目錄包含的時NameNode的數據結構。
  • 編輯日誌(edits log)與命名空間鏡像文件(fsimage):

  編輯日誌(edits log) :文件系統客戶端執行寫操做時,這些事務首先被記錄到edits中。NameNode在內存中維護文件系統的元數據;當被修改時,相關元數據信息也同步更新。內存中的元數據可支持客戶端的讀請求。咱們可使用OEV查看edits文件

選項解析:

-i,--inputFile <arg>:要處理的編輯文件
-o,--outputFile <arg>:輸出文件的名稱;若是指定的文件存在,它將被覆蓋
-p,--processor <arg>:選擇要應用於編輯文件的處理器類型 (XML|FileDistribution|Web|Delimited)

oev中的e指定了鏡像文件

    命令以下:

<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
    <EDITS_VERSION>-63</EDITS_VERSION>
    <RECORD>
        <!-- 開始日誌段-->
        <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
        <DATA>
            <!-- 事務id-->
            <TXID>1</TXID>
        </DATA>
    </RECORD>
    <RECORD>
        <!-- 結束日誌段-->
        <OPCODE>OP_END_LOG_SEGMENT</OPCODE>
        <DATA>
            <TXID>2</TXID>
        </DATA>
    </RECORD>
</EDITS>

  命名空間鏡像文件(fsimage):文件系統元數據的持久檢查點,每一個fsimage文件包含文件系統中的全部目錄和文件inode的序列化信息(從Hadoop-2.4.0起,FSImage開始採用Google Protobuf編碼格式),每一個inodes表徵一個文件或目錄的元數據信息以及文件的副本數、修改和訪問時間等信息。數據塊存儲在DataNode中,但fsimage文件並不描述DataNode。咱們可使用OIV查看fsimage文件

選項解析:

-i,--inputFile <arg>:要處理的鏡像文件
-o,--outputFile <arg>:輸出文件的名稱;若是指定的文件存在,它將被覆蓋
-p,--processor <arg>:選擇要應用於鏡像文件的處理器類型 (XML|FileDistribution|Web|Delimited)

oiv中的i指定了image文件

    命令以下:

# hdfs oiv -p XML -i fsimage_0000000000000014026 -o fsimage.xml
<?xml version="1.0"?>
<fsimage>
    <NameSection>
        <!-- 默認的開啓編號-->
        <genstampV1>1000</genstampV1>
        <!-- 最後一個塊的編號-->
        <genstampV2>2215</genstampV2>
        <genstampV1Limit>0</genstampV1Limit>
         <!-- 最後一個分配的塊的塊id-->
        <lastAllocatedBlockId>1073743027</lastAllocatedBlockId>
        <!-- 開始的事務id號-->
        <txid>14026</txid>
    </NameSection>
    <INodeSection>
        <!-- 最後一個文件(目錄)的inode號-->
        <lastInodeId>18763</lastInodeId>
        <!--當前文件系統中只有根目錄,如下爲根目錄的相關信息-->
        <inode>
            <id>16385</id>
            <type>DIRECTORY</type>
            <name></name>
            <mtime>1560256204322</mtime>
            <permission>root:root:rwxrwxrwx</permission>
            <nsquota>9223372036854775807</nsquota>
            <dsquota>-1</dsquota>
        </inode>
        <inode>
            <id>16417</id>
            <type>DIRECTORY</type>
            <name>myInfo</name>
            <mtime>1552974220469</mtime>
            <permission>root:root:rwxrwxrwx</permission>
            <nsquota>-1</nsquota>
            <dsquota>-1</dsquota>
        </inode>
        <inode>
            <id>16418</id>
            <type>FILE</type>
            <name>myInfo.txt</name>
            <replication>1</replication>
            <mtime>1552830434241</mtime>
            <atime>1552974031814</atime>
            <perferredBlockSize>134217728</perferredBlockSize>
            <permission>root:root:rwxrwxrwx</permission>
            <blocks>
                <block>
                    <id>1073741855</id>
                    <genstamp>1031</genstamp>
                    <numBytes>147</numBytes>
                </block>
            </blocks>
        </inode>
        .........   // inode文件太多,省略
    </INodeSection>
    <INodeReferenceSection></INodeReferenceSection>
    <SnapshotSection>
        <snapshotCounter>0</snapshotCounter>
    </SnapshotSection>
    <INodeDirectorySection>
        <directory>
            <parent>16385</parent>
            <inode>18543</inode>
            <inode>16474</inode>
            <inode>16419</inode>
            <inode>16417</inode>
            <inode>16427</inode>
            <inode>17544</inode>
            <inode>17561</inode>
        </directory>
        <directory>
            <parent>16417</parent>
            <inode>16420</inode>
        </directory>
        <directory>
            <parent>16419</parent>
            <inode>17399</inode>
            <inode>17258</inode>
            <inode>16418</inode>
            <inode>17294</inode>
        </directory>
         ......        // 省略其餘<directory>標籤
    </INodeDirectorySection>
    <FileUnderConstructionSection>        
    </FileUnderConstructionSection>
    <SecretManagerSection>
        <currentId>0</currentId>
        <tokenSequenceNumber>0</tokenSequenceNumber>
    </SecretManagerSection>
    <CacheManagerSection>
        <nextDirectiveId>1</nextDirectiveId>
    </CacheManagerSection>
</fsimage>
View Code
  • seen_txid文件 :該文件對於NameNode很是重要,它是存放transactionId的文件,format以後是0,它表明的是NameNode裏面的edits_*文件的尾數,NameNode重啓的時候,會按照seen_txid的數字,循序從頭跑edits_000*01~到seen_txid的數字。當hdfs發生異常重啓的時候,必定要比對seen_txid內的數字是否是你edits最後的尾數,否則會發生建置NameNode時元數據信息缺失,致使誤刪DataNode上多餘block。

  • in_use.lock文件 :是一個鎖文件,NameNode使用該文件爲存儲目錄加鎖。能夠避免其餘NameNode實例同時使用(可能會破壞)同一個存儲目錄的狀況。  

  3.2.2 NameNode的工做原理

  NameNode管理文件系統的命名空間。它維護着文件系統樹及整棵樹內全部的文件和目錄。這些信息以兩個文件形式永久保存在本地磁盤上:命名空間鏡像文件(fsimage)和編輯日誌文件(edits log)。它也記錄着每一個文件中各個塊所在的數據節點信息,但它並不永久保存塊的位置信息,由於這些信息會在系統啓動時根據DataNode節點信息重建,塊信息存儲在內存中。

  能夠看得出來NameNode的正常運行是很是重要的,若是運行的NameNode服務的機器毀壞,文件系統上全部的文件將會丟失,由於咱們不知道如何根據DataNode的塊重建文件。所以,Hadoop爲此提供兩種實現NameNode容錯機制:

  1. 備份組成文件系統元數據持久狀態的文件。通常是將持久狀態寫入本地磁盤的同時,寫入一個遠程掛載的網絡文件系統(NFS),HDFS與NFS安裝配置能夠參考該文章(小編目前還沒實現,但將來會實現)。
  2. 運行一個輔助NameNode。但它不能做爲主NameNode,這個輔助NameNode的重要做用是按期合併編輯日誌(edits)與命名空間鏡像文件(fsimage),以防止編輯日誌過大。通常來講輔助NameNode在一個單獨的機器上運行,由於它須要佔用大量CPU時間而且同樣多的內存來執行合併操做。設計成這樣的好處在於,一旦主NameNode發生故障,輔助NameNode馬上就能夠接替它的工做,可是因爲保存數據是定時進行的,因此不免會有損失的數據,此時就能夠把保存在其餘地方(NFS)的數據複製到輔助NameNode,而後輔助NameNode做爲新的主NameNode運行(注意,也能夠運行熱備份NameNode代替運行輔助NameNode)。

 

  3.3 SecondaryNamenode(輔助NameNode)

  Hadoop SecondaryNameNode並非Hadoop的第二個namanode,它不提供NameNode服務,而僅僅是NameNode的一個工具,這個工具幫助NameNode管理元數據信息。多是因爲SecondaryNameNode這個名字給人帶來的混淆,Hadoop後面的版本(1.0.4)建議不要使用,而使用CheckPoint Node。但在這小節中,小編仍是使用SecondaryNamenode。

  運行中的SecondaryNamenode(輔助NameNode)的目錄結構與主NameNode的目錄結構幾乎同樣,但有部分時間不相同,它爲主NameNode內存中的文件系統元數據建立檢查點(後面解釋)還沒有成功時二者不相同。運行中的SecondaryNamenode有以下所示的目錄結構:

  

  當NameNode 啓動時,須要合併fsimage和edits文件,按照edits文件內容將fsimage進行事務處理,從而獲得HDFS的最新狀態。實際應用中,NameNode不多從新啓動。假如存在一個龐大的集羣,且關於HDFS的操做至關頻繁與複雜,那麼就會產生一個很是大的edits文件用於記錄操做,這就帶來了如下問題:

  • edits文件過大會帶來管理問題;
  • 一旦須要重啓HDFS時,就須要花費很長一段時間對edits和fsimage進行合併,這就致使HDFS長時間內沒法啓動;
  • 若是NameNode掛掉了,會丟失部分操做記錄(這部分記錄存儲在內存中,還未寫入edits);

  此時,Secondary NameNode就要發揮它的做用了:合併edits文件,防止edits文件持續增加。該輔助NameNode會爲主NameNode內存中的文件系統元數據建立檢查點(fsimage文件),建立檢查點前HDFS會自動進入安全模式(safe mode),當NameNode處在安全模式,管理員也可手動調用hdfs dfsadmin -saveNameSpace命令來建立檢查點。建立檢查點的步驟以下所示(如圖中也簡單地描述)。

  1. 輔助NameNode請求主NameNode中止使用正在進行中的edits文件,這樣新的編輯操做記錄到一個新文件中。主NameNode還會更新全部存儲目錄中的seen_txid文件。
  2. 輔助NameNode從主NameNode獲取最近的fsimage和edits文件(採用HTTP GET)。
  3. 輔助NameNode將fsimage文件載入內存,逐一執行edits文件中的事務,建立新的合併後的fsimage文件。
  4. 輔助NameNode將新的fsimage文件發送回主NameNode(使用HTTP PUT),主NameNode將其保存爲臨時的.ckpt文件。
  5. 主NameNode從新命名臨時的fsimage文件,便於往後使用。

建立檢查點的步驟圖

  最終,主NameNode擁有最新的fsimage文件和一個更小的正在進行中的edits文件(edits文件可能非空,由於在建立檢查點過程當中主NameNode還可能收到一些編輯請求)。這個過程清晰解釋了輔助NameNode和主NameNode擁有相近內存需求的緣由(由於輔助NameNode也把fsimage文件載入內存)。所以,在大型集羣中,輔助NameNode須要運行在一臺專用機器上。

  在hdfs-site.xml中能夠配置與檢查點觸發點有關的屬性:

<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600</value>
  <description>兩個按期檢查點之間的秒數
  </description>
</property>
 
<property>
  <name>dfs.namenode.checkpoint.txns</name>
  <value>1000000</value>
  <description>secondarynamenode或檢查點節點將建立檢查點
        每一個「dfs.namenode.checkpoint.txns」事務的名稱空間
        判斷「dfs.namenode.checkpoint.period」是否已過時
  </description>
</property>
 
<property>
  <name>dfs.namenode.checkpoint.check.period</name>
  <value>60</value>
  <description>SecondaryNameNode和CheckpointNode將輪詢NameNode    
        每隔'dfs.namenode.checkpoint.check.period'秒查詢一次
        未存入檢查點事務
  </description>
</property>

  默認狀況下,輔助NameNode每隔一個小時建立檢查點;此外,若是從上一個檢查點開始編輯日誌的大小已經達到100萬個事務時,即便不到一小時,也會建立檢查點,檢查頻率爲每分鐘一次。

  這個過程namesecondary目錄發生了更新;secondaryNameNode的檢查點目錄的佈局與NameNode的是相同的,這種設計的好處是NameNode發生故障時,能夠從secondaryNameNode恢復數據;有兩種實現方法:一是將相關存儲目錄複製到新的NameNode中;二是使用-importCheckpoint選項啓動NameNode守護進程,從而將secondaryNameNode用做新的NameNode

  與第一次開啓hdfs過程不一樣的是這次有30多秒的安全模式:

  在安全模式中在等待塊報告,這也關係到DataNode的運行過程。

 

  3.4 DataNode(工做節點)

  DataNode是文件系統的工做節點。它們根據須要存儲並檢索數據塊(受客戶端或NameNode調度),而且按期向NameNode發送它們所存儲的塊的列表。

  3.4.1 DataNode目錄結構

    和NameNode不一樣的是,DataNode的存儲目錄是初始階段自動建立的,不須要額外格式化。DataNode的關鍵文件和目錄以下所示:

  

  分析:從上圖能夠看出,dataNode的文件結構主要由blk_前綴文件、BP-random integer-NameNode-IP address-creation time和VERSION構成。

  • BP-random integer-NameNode-IP address-creation time
    • BP表明BlockPool的,就是Namenode的VERSION中的集羣惟一blockpoolID
    • 從上圖能夠看出個人DataNode是一個BP,也就是說只有一個NameNode管理所有的文件系統命名空間,若是有兩個以上的BP,該HDFS是Federation HDFS,因此該目錄下有兩個BP開頭的目錄,IP部分和時間戳表明建立該BP的NameNode的IP地址和建立時間戳。
  •  finalized/rbw :
    • 這兩個目錄都是用於實際存儲HDFS BLOCK的數據,裏面包含許多block_xx文件以及相應的.meta後綴的元數據文件,.meta文件包含了checksum信息。
    • rbw是「replica being written」的意思,該目錄用於存儲用戶當前正在寫入的數據。
  • blk_前綴文件 :
    • HDFS中的文件塊,存儲的是原始文件內容。
    • 塊的元數據信息,每個塊有一個相關聯的.meta文件,一個文件塊由存儲的原始文件字節組成。
    • .meta文件包括頭部(含版本和類型信息)和該塊各區段的一系列的校驗和。
    • 每一個塊屬於一個數據塊池(在本篇文章中,只有一個數據塊池),每一個數據塊池都有本身的存儲目錄,目錄根據數據塊池ID造成(和NameNode的VERSION文件中的數據塊池ID相同)

  注 :當目錄中數據塊的數量增長到必定規模時,DataNode會建立一個子目錄來存放新的數據塊及其元數據信息。若是當前目錄已經存儲了64個(經過dfs.datanode.numblocks屬性設置)數據塊時,就建立一個子目錄。終極目標是設計一棵高扇出的目錄樹,即便文件系統中的塊數量很是多,目錄樹的層數也很少。經過這種方式,DataNode能夠有效管理各個目錄中的文件,避免大多數操做系統遇到的管理難題,即不少(成千上萬個)文件放在同一個目錄之中。

  • VERSION
#Mon Sep 29 09:54:36 BST 2014storageID=DS-c478e76c-fe1b-44c8-ba45-4e4d6d266547
clusterID=CID-01b5c398-959c-4ea8-aae6-1e0d9bd8b142
cTime=0
datanodeUuid=75ffabf0-813c-4798-9a91-e7b1a26ee6f1
storageType=DATA_NODE layoutVersion=-57
    • storageID :相對於DataNode來講是惟一的,用於在NameNode處標識DataNode 
    • clusterID :是系統生成或手動指定的集羣ID 
    • cTime :表示NameNode存儲時間的建立時間 
    • datanodeUuid :表示DataNode的ID號
    • storageType :將這個目錄標誌位DataNode數據存儲目錄。 
    • layoutVersion :是一個負整數,保存了HDFS的持續化在硬盤上的數據結構的格式版本號。
  • in_use.lock :  

      是一個鎖文件,NameNode使用該文件爲存儲目錄加鎖。能夠避免其餘NameNode實例同時使用(可能會破壞)同一個存儲目錄的狀況。  

 

   3.5 塊緩存

  一般DataNode從磁盤中讀取塊,但對於訪問頻繁的文件,其對應的塊可能被顯式地緩存在DataNode內存中,以堆外塊緩存(off-heap block cache)的形式存在。默認狀況下,一個塊僅緩存在一個DataNode的內存中,固然能夠對每一個文件配置DataNode的數量。做業調度器(用於MapReduce、Spark和其餘框架的)經過在緩存塊的DataNode上運行任務,能夠利用塊緩存的優點提升讀操做的性能。

  用戶或應用經過在緩存池(cache pool)中增長一個 cache directive來告訴NameNode須要緩存哪些文件及存多久。緩存池是一個用於管理緩存權限和資源使用的管理性分組。

  本小節只簡單描述,有關HDFS的緩存管理請查閱官方文檔或者其餘等相關資料。

 

  3.6 聯邦HDFS

  NameNode在內存中保存文件系統中每一個文件和每一個數據塊的引用關係,這意味着對於一個擁有大量文件的超大集羣來講,內存將成爲限制系統橫向擴展的瓶頸。在2.X發行版本系列中引入的聯邦HDFS容許系統經過添加NameNode實現擴展,其中每一個NameNode管理文件系統命名空間中的一部分

  在聯邦環境中,每一個NameNode維護一個命名空間卷(namespace volume),由命名空間的元數據和一個數據塊池(block pool)組成,數據塊池包含該命名空間下文件的全部數據塊。命名空間卷之間是相互獨立的,兩兩之間並不相互通訊,甚至其中一個NameNode的失效也不會影響由其餘NameNode維護的命名空間的可用性。

  集羣中的DataNode還須要註冊到每一個NameNode,而且存儲着來自多個數據塊池中的數據塊。

  聯邦HDFS的架構圖以下圖所示:

聯邦HDFS架構圖

  聯邦HDFS更詳細的請查閱官方文檔

 

  3.7 HDFS的高可用性(High Availability)

  經過聯合使用在多個文件系統中備份NameNode的元數據和經過備用NameNode建立監測點能防止數據丟失,可是依舊沒法實現文件系統的高可用性。NameNode依舊存在單點失效(SPOF)的問題。若是NameNode失效了,那麼全部的客戶端,包括MapReduce做業,均沒法讀、寫或列舉文件,由於NameNode是惟一存儲元數據與文件到數據塊映射的地方,對於一個大型並擁有大量文件和數據塊的集羣,NameNode的冷啓動須要30分鐘,甚至更長時間,系統恢復時間太長了,也會影響到平常維護。在這一狀況下,Hadoop系統沒法提供服務直到有新的NameNode上線。

   在這樣的狀況下要向從一個失效的NameNode恢復,系統管理員得啓動一個擁有文件系統元數據副本得新的NameNode,並配置DataNode和客戶端以便使用這個新的NameNode。新的NameNode直到知足如下情形才能相應服務:

  1. 將命名空間鏡像文件導入內存中;
  2. 重演編輯日誌;
  3. 接收到足夠多的來自DataNode的數據塊報告並退出安全模式

   Hadoop2.X以上版本針對上述問題增長了對HDFS高可用性(HA)的支持。在這一實現中,配置了一對活動-備用(active-standby) NameNode。當活動NameNode失效,備用NameNode就會接管它的任務並開始服務於來自客戶端的請求,不會有任何明顯中斷。實現這一目標須要在架構上作以下修改。HDFS HA架構圖以下所示:

HDFS HA架構圖

    • NameNode之間須要經過高可用共享存儲實現編輯日誌的共享。當備用NameNode接管工做以後,它將通讀共享編輯日誌直至末尾,以實現與活動NameNode的狀態同步,並繼續讀取由活動NameNode寫入的新條目。
    • DataNode須要同時向兩個NameNode發送數據塊處理報告,由於數據塊的映射信息存儲在NameNode的內存中,而非磁盤。
    • 客戶端須要使用特定的機制來處理NameNode的失效問題,這一機制對用戶是透明的。
    • 輔助NameNode的角色被備用NameNode所包含,備用NameNode爲活動的NameNode命名空間設置週期性檢查點。

  有兩種高可用性共享存儲能夠作出選擇:NFS過濾器羣體日誌管理器(QJM, quorum journal manager)。QJM是一個專用的HDFS實現,爲提供一個高可用的編輯日誌而設計,被推薦用於大多數HDFS部署中,同時,QJM的實現並沒使用Zookeeper,但在HDFS HA選取活動的NameNode時使用了Zookeeper技術。QJM以一組日誌節點(journalnode)的形式運行,通常是奇數點結點組成,每一個JournalNode對外有一個簡易的RPC接口,以供NameNode讀寫EditLog到JN本地磁盤。當寫EditLog時,NameNode會同時向全部JournalNode並行寫文件,只要有N/2+1結點寫成功則認爲這次寫操做成功,遵循Paxos協議。其內部實現框架以下:

QJM內部實現框架

  從圖中可看出,主要是涉及EditLog的不一樣管理對象和輸出流對象,每種對象發揮着各自不一樣做用:

    • FSEditLog:全部EditLog操做的入口。
    • JournalSet:集成本地磁盤和JournalNode集羣上EditLog的相關操做。
    • FileJournalManager:實現本地磁盤上EditLog操做。
    • QuorumJournalManager:實現JournalNode集羣EditLog操做。
    • AsyncLoggerSet:實現JournalNode集羣EditLog的寫操做集合。
    • AsyncLogger:發起RPC請求到JN,執行具體的日誌同步功能。
    • JournalNodeRpcServer:運行在JournalNode節點進程中的RPC服務,接收NameNode端的AsyncLogger的RPC請求。
    • JournalNodeHttpServer:運行在JournalNode節點進程中的Http服務,用於接收處於Standby狀態的NameNode和其它JournalNode的同步EditLog文件流的請求。

  3.7.1 QJM寫過程分析

  上面提到EditLog,NameNode會把EditLog同時寫到本地和JournalNode。寫本地由配置中參數dfs.namenode.name.dir控制,寫JN由參數dfs.namenode.shared.edits.dir控制,在寫EditLog時會由兩個不一樣的輸出流來控制日誌的寫過程,分別爲:EditLogFileOutputStream(本地輸出流)和QuorumOutputStream(JN輸出流)。寫EditLog也不是直接寫到磁盤中,爲保證高吞吐,NameNode會分別爲EditLogFileOutputStream和QuorumOutputStream定義兩個同等大小的Buffer,大小大概是512KB,一個寫Buffer(buffCurrent),一個同步Buffer(buffReady),這樣能夠一邊寫一邊同步,因此EditLog是一個異步寫過程,同時也是一個批量同步的過程,避免每寫一筆就同步一第二天志。

  這個是怎麼實現邊寫邊同步的呢,這中間實際上是有一個緩衝區交換的過程,即bufferCurrent和buffReady在達到條件時會觸發交換,如bufferCurrent在達到閾值同時bufferReady的數據又同步完時,bufferReady數據會清空,同時會將bufferCurrent指針指向bufferReady以知足繼續寫,另外會將bufferReady指針指向bufferCurrent以提供繼續同步EditLog。上面過程用流程圖就是表示以下:

EditLog輸出流程圖

問題一:  

  既然EditLog是異步寫的,怎麼保證緩存中的數據不丟呢,其實這裏雖然是異步,但實際全部日誌都須要經過logSync同步成功後纔會給client返回成功碼,假設某一時刻NameNode不可用了,其內存中的數據實際上是未同步成功的,因此client會認爲這部分數據未寫成功。還有EditLog怎麼在多個JN上保持一致的呢?

  解決方案:

1. 隔離雙寫

  在ANN每次同步EditLog到JN時,先要保證不會有兩個NN同時向JN同步日誌,也就是說同一時間QJM僅容許一個NameNode向編輯日誌中寫入數據。這個隔離是怎麼作的。這裏面涉及一個很重要的概念Epoch Numbers,不少分佈式系統都會用到。Epoch有以下幾個特性:

    • 當NN成爲活動結點時,其會被賦予一個EpochNumber。
    • 每一個EpochNumber是惟一的,不會有相同的EpochNumber出現。
    • EpochNumber有嚴格順序保證,每次NN切換後其EpochNumber都會自增1,後面生成的EpochNumber都會大於前面的EpochNumber。

  但QJM是怎麼保證上面的特性的呢,主要有如下幾點:

    1. 在對EditLog做任何修改前,QuorumJournalManager(NameNode上)必須被賦予一個EpochNumber;
    2. QJM把本身的EpochNumber經過newEpoch(N)的方式發送給全部JN結點
    3. 當JN收到newEpoch請求後,會把QJM的EpochNumber保存到一個lastPromisedEpoch變量中並持久化到本地磁盤;
    4. ANN同步日誌到JN的任何RPC請求(如logEdits(),startLogSegment()等),都必須包含ANN的EpochNumber;
    5. JN在收到RPC請求後,會將之與lastPromisedEpoch對比,若是請求的EpochNumber小於lastPromisedEpoch,將會拒絕同步請求,反之,會接受同步請求並將請求的EpochNumber保存在lastPromisedEpoch。

  這樣就能保證主備NN發生切換時,就算同時向JN同步日誌,也能保證日誌不會寫亂,由於發生切換後,原ANN的EpochNumber確定是小於新ANN的EpochNumber,因此原ANN向JN的發起的全部同步請求都會拒絕,實現隔離功能,防止了腦裂。

2. 恢復in-process日誌

  若是在寫過程當中寫失敗了,可能各個JN上的EditLog的長度都不同,須要在開始寫以前將不一致的部分恢復。恢復機制以下:

  1.  ANN先向全部JN發送getJournalState請求;
  2. JN會向ANN返回一個Epoch(lastPromisedEpoch);
  3. ANN收到大多數JN的Epoch後,選擇最大的一個並加1做爲當前新的Epoch,而後向JN發送新的newEpoch請求,把新的Epoch下發給JN;
  4. JN收到新的Epoch後,和lastPromisedEpoch對比,若更大則更新到本地並返回給ANN本身本地一個最新EditLogSegment起始事務Id,若小則返回NN錯誤;
  5. ANN收到多數JN成功響應後認爲Epoch生成成功,開始準備日誌恢復;
  6. ANN會選擇一個最大的EditLogSegment事務ID做爲恢復依據,而後向JN發送prepareRecovery; RPC請求,對應Paxos協議2p階段的Phase1a,若多數JN響應prepareRecovery成功,則可認爲Phase1a階段成功;
  7. ANN選擇進行同步的數據源,向JN發送acceptRecovery RPC請求,並將數據源做爲參數傳給JN。
  8. JN收到acceptRecovery請求後,會從JournalNodeHttpServer下載EditLogSegment並替換到本地保存的EditLogSegment,對應Paxos協議2p階段的Phase1b,完成後返回ANN請求成功狀態。
  9. ANN收到多數JN的響應成功請求後,向JN發送finalizeLogSegment請求,表示數據恢復完成,這樣以後全部JN上的日誌就能保持一致。
    數據恢復後,ANN上會將本地處於in-process狀態的日誌改名爲finalized狀態的日誌,形式如edits[start-txid][stop-txid]。

3. 日誌同步

  日誌從ANN同步到JN的過程,具體以下:

  1. 執行logSync過程,將ANN上的日誌數據放到緩存隊列中;
  2. 將緩存中數據同步到JN,JN有相應線程來處理logEdits請求
  3. JN收到數據後,先確認EpochNumber是否合法,再驗證日誌事務ID是否正常,將日誌刷到磁盤,返回ANN成功碼;
  4.  ANN收到JN成功請求後返回client寫成功標識,若失敗則拋出異常。

 

  經過上面一些步驟,日誌能保證成功同步到JN,同時保證JN日誌的一致性,進而備NN上同步日誌時也能保證數據是完整和一致的。

3.7.2 QJM讀過程分析

  這個讀過程是面向備NN(SNN)的,SNN按期檢查JournalNode上EditLog的變化,而後將EditLog拉回本地。SNN上有一個線程StandbyCheckpointer,會按期將SNN上FSImage和EditLog合併,並將合併完的FSImage文件傳回主NN(ANN)上,就是所說的Checkpointing過程。下面咱們來看下Checkpointing是怎麼進行的。

  在2.x版本中,已經將原來的由SecondaryNameNode主導的Checkpointing替換成由SNN主導的Checkpointing。下面是一個CheckPoint的流向圖:

Checkpointing流向圖

   總的來講,就是在SNN上先檢查前置條件,前置條件包括兩個方面:距離上次Checkpointing的時間間隔和EditLog中事務條數限制。前置條件任何一個知足都會觸發Checkpointing,而後SNN會將最新的NameSpace數據即SNN內存中當前狀態的元數據保存到一個臨時的fsimage文件( fsimage.ckpt)而後比對從JN上拉到的最新EditLog的事務ID,將fsimage.ckpt_中沒有,EditLog中有的全部元數據修改記錄合併一塊兒並重命名成新的fsimage文件,同時生成一個md5文件。將最新的fsimage再經過HTTP請求傳回ANN。經過按期合併fsimage有什麼好處呢,主要有如下幾個方面:

    • 能夠避免EditLog愈來愈大,合併成新fsimage後能夠將老的EditLog刪除;
    • 能夠避免主NN(ANN)壓力過大,合併是在SNN上進行的;
    • 能夠避免fsimage保存的是一份最新的元數據,故障恢復時避免數據丟失。

3.7.3 HDFS HA如何實現故障切換與規避?

  在活動namenode(ANN)失效以後,備用namenode(SNN)可以快速(幾十秒的時間)實現任務接管,由於最新的狀態存儲在內存中:包括最新的編輯日誌條目和最新的數據塊映射信息。實際觀察到的失效時間略長一點(須要1分鐘左右),這是由於系統須要保守肯定活動namenode是否真的失效了。活動namenode失效且備用namenode也失效的狀況下,固然這類狀況發生的機率很是低很是低的,如今Hadoop 3.X發行版本已經支持運行更多備用namenode來提供更高的容錯性

  系統中有一個稱爲故障轉移控制器(failover controller)的新實體,管理着將活動namenode轉移爲備用namenode的轉換過程。有多種故障轉移控制器,但默認一種是使用了Zookeeper來確保有且僅有一個活動namenode。每個namenode運行着一個輕量級的故障轉移控制器,其工做就是監視宿主namenode是否失效(經過一個簡單的心跳機制實現)並在namenode失效時進行故障轉移,這就是HA的主備切換機制,主備選舉依賴於Zookeeper。下面是主備切換的狀態圖:

Failover流程圖

  從圖中能夠看出,整個切換過程是由ZKFC(即故障轉移控制器,全稱Zookeeper Failover Controller)來控制的,具體又可分爲HealthMonitor、ZKFailoverController和ActiveStandbyElector三個組件。

    • ZKFailoverController:是HealthMontior和ActiveStandbyElector的母體,執行具體的切換操做。
    • HealthMonitor:監控NameNode健康狀態,若狀態異常會觸發回調ZKFailoverController進行自動主備切換。
    • ActiveStandbyElector:通知ZK執行主備選舉,若ZK完成變動,會回調ZKFailoverController相應方法進行主備狀態切換。

  在故障切換期間,Zookeeper主要是發揮什麼做用呢,有如下幾點:

    • 失敗保護:集羣中每個NameNode都會在Zookeeper維護一個持久的session,機器一旦掛掉,session就會過時,故障遷移就會觸發。
    • Active NameNode選擇:Zookeeper有一個選擇ActiveNN的機制,一旦現有的ANN宕機,其餘NameNode能夠向Zookeeper申請成爲下一個Active節點。
    • 防腦裂:ZK自己是強一致和高可用的,能夠用它來保證同一時刻只有一個活動節點。

  在哪些場景會觸發自動切換呢,從HDFS-2185中概括瞭如下幾個場景:

    • ANN JVM崩潰:ANN上HealthMonitor狀態上報會有鏈接超時異常,HealthMonitor會觸發狀態遷移至SERVICE_NOT_RESPONDING,而後ANN上的ZKFC會退出選舉,SNN上的ZKFC會得到Active Lock,做相應隔離後成爲Active節點。
    • ANN JVM凍結:這個是JVM沒崩潰,但也沒法響應,同崩潰同樣,會觸發自動切換。
    • ANN 機器宕機:此時ActiveStandbyElector會失去同ZK的心跳,會話超時,SNN上的ZKFC會通知ZK刪除ANN的活動鎖,做相應隔離後完成主備切換。
    • ANN 健康狀態異常:此時HealthMonitor會收到一個HealthCheckFailedException,並觸發自動切換。
    • Active ZKFC崩潰:雖然ZKFC是一個獨立的進程,但因設計簡單也容易出問題,一旦ZKFC進程掛掉,雖然此時NameNode是正常運行的,但系統也認爲須要切換,此時SNN會發一個請求到ANN要求ANN放棄主節點位置,ANN收到請求後,會觸發自動切換。
    • Zookeeper集羣崩潰:若是ZK集羣崩潰了,主備NN上的ZKFC都會感知並斷連,此時主備NN會進入一個NeutralMode模式,同時不改變主備NN的狀態,繼續發揮做用,只不過此時,若是ANN也故障了,那集羣沒法發揮Failover,也就沒法使用集羣了,因此對於此種場景,ZK集羣通常是不容許掛掉到多臺,至少要有(N / 2 + 1)臺保持服務纔算是安全的。

  管理員也能夠經過手動發起故障轉移,例如在進行平常維護時,這稱爲」平穩的故障轉移「(graceful failover),由於故障轉移控制器能夠組織兩個namenode有序地切換角色。命令參考以下所示。

// 將 active 狀態由 nn1 切換到 nn2
# hdfs haadmin -failover --forcefence --forceactive nn1 nn2

// 在啓用自動故障轉移的集羣上 --forcefence -- forceactive 參數不起做用
// 使用如下方法檢查名稱節點狀態(假設 nn1 爲 active,nn2 standby):
# hdfs haadmin -getServiceState nn1
active
# hdfs haadmin -getServiceState nn2
standby

// 因而咱們人爲製造故障,在 nn1 上查看 NameNode 進程
# jps
# kill -9 [進程ID]
// 自動故障轉移將會激活 nn2 節點,狀態從 standby 轉換爲 active

  但在非平穩故障轉移的狀況下,沒法確切直到失效NameNode是否已經中止運行。例如網速較慢或者網絡被分割的狀況下,可能激發故障轉移,但Active NameNode依然運行着而且依舊是Active NameNode。高可用實現作了更一步的優化,以確保先前Active NameNode不會執行危害系統並致使系統崩潰的操做,該方法稱爲」規避「。

  規避機制包括:撤銷NameNode訪問共享存儲目錄的權限(一般使用供應商指定的NFS命令)、經過遠程管理命令屏蔽相應的網絡端口。最不行的話,能夠經過「一槍爆頭」(斷電關機)等製造人爲故障技術。

 

四、HDFS的讀寫原理

  4.1 HDFS讀數據

HDFS讀數據流程圖

  1.  HDFS客戶端經過調用FileSyste對象的open()方法來打開但願讀取的文件,對於HDFS來講,這個對象是DistributedFileSystem的一個實例。
  2. DistributedFileSystem經過使用遠程過程調用(RPC)來調用NameNode,以肯定文件起始塊的位置。對於每一個塊,NameNode返回具備該塊副本的DataNode地址。此外,這些DataNode根據它們與客戶端的距離來排序(根據集羣的網絡拓撲),若是該客戶端自己就是一個DataNode,便從本地讀取數據。接着DistributedFileSystem類返回一個FSDataInputStream對象(一個支持文件定位的輸入流)給客戶端以便讀取數據。FSDataInputStream類轉而封裝DFSInputStream對象,該對象管理着DataNode和NameNode的 I/O。
  3. 客戶端對這個輸入流調用read()方法,存儲着文件起始幾個塊的DataNode地址的DFSInputStream隨即鏈接距離最近的文件中第一個塊所在的DataNode。
  4. 經過對數據流反覆調用read()方法,能夠將數據從DataNode傳輸到HDFS 客戶端。
  5. 讀取數據到塊的末端時,DFSInputStream關閉與該DataNode的鏈接,而後尋找下一個塊的最佳DataNode。在HDFS客戶端所看來它一直在讀取一個連續的流,這些對於客戶端來講是透明的。
  6. 客戶端從流中讀取數據時,塊是按照打開DFSInputStream與DataNode新建鏈接的順序讀取的,它也會根據須要詢問NameNode來檢索下一批數據塊的DataNode的位置,一旦客戶端讀取完畢,就會調用close()方法。但在讀取時,DFSInputStream與DataNode通訊時遇到錯誤,會嘗試從這個塊的另一個最鄰近DataNode讀取數據,它也會記住那個故障DataNode,以保證之後不會反覆讀取該節點上後續的塊。DFSInputStream也會經過校驗和確認從DataNode發來的數據是否完整。若是發現有損壞的塊,DFSInputStream會試圖從其餘DataNode讀取其複本,也會將被損壞的塊通知給NameNode。

 

  HDFS讀數據過程這一設計的一個重點是:客戶端能夠直接鏈接到DataNode檢索數據,且NameNode告知客戶端每一個塊所在的最佳DataNode,因爲數據流分散在集羣中的全部DataNode,因此這種設計能使HDFS擴展到大量的併發客戶端。同時,NameNode只須要響應塊位置的請求(這些信息存儲在內存中,於是很是高效),無需響應數據請求,不然隨着客戶端數量的增加,NameNode會很快稱爲瓶頸。

     這裏HdfsDataInputStream是FSDataInputStream的子類,這裏是經過子類建立父類對象。

 

  4.2 HDFS寫數據

HDFS寫數據流程圖

  1. 客戶端經過對DistributedFileSystem對象調用create()來新建對象。
  2. DistributedFileSystem對NameNode建立一個RPC調用,在文件系統的命名空間中新建一個文件,此時該文件中尚未響應的數據塊。NameNode執行各類不一樣的檢查以確保這個文件不存在以及客戶端有新建該文件的權限。
    1. 若是這些檢查均經過,NameNode就會爲建立新文件記錄一條記錄;DistributedFileStream向客戶端返回一個FSDataOutputStream對象,由此客戶端能夠開始寫入數據。就像讀取事件同樣,文件系統數據輸出流控制一個DFSOutputStream,負責處理datanode和namenode之間的通訊。
    2. 不然,文件建立失敗並向客戶端拋出一個IOException異常。
  3. 在客戶端寫入數據時,DFSOutputStream將它分紅一個個的數據包,並寫入內部隊列,稱爲「數據隊列」(data queue)。DataStreamer處理數據隊列,它的責任是挑選出適合存儲數據複本的一組DataNode,並據此來要求NameNode分配新的數據塊。這一組DataNode構成一個管線——咱們假設複本數爲3,因此管線中有3個節點。
  4. DataStream將數據包流式傳輸到管線中第1個DataNode,該DataNode存儲數據包並將它發送到管線中的第2個DataNode。一樣,第2個DataNode存儲該數據包而且發送給管線中的第3個(也是最後一個)DataNode。
  5. DFSOutputStream也維護着一個內部數據包隊列來等待DataNode的收到確認回執,稱爲「確認隊列」(ack queue)。收到管道中全部DataNode確認信息後,該數據包纔會從確認隊列刪除。若是有DataNode在數據寫入期間發生故障,則執行如下操做(對寫入數據的客戶端是透明的)。
    1. 首先關閉管線,確認把隊列中的全部數據包都添加回數據隊列的最前端,以確保故障節點下游的DataNode不會漏掉任何一個數據包。
    2. 爲存儲在另外一正常DataNode的當前數據塊指定一個新的標識,並將該標識傳送給NameNode,以便故障DataNode在恢復後能夠刪除存儲的部分數據塊。
    3. 從管線中刪除故障DataNode,基於兩個正常DataNode構建一條新管線。
    4. 餘下的數據塊寫入管線中正常的DataNode。
    5. NameNode注意到塊複本量不足時,會在另外一個節點上建立一個新的複本。後續的數據塊繼續正常接受處理。
  6. 客戶端完成數據的寫入後,對數據流調用close()。
  7. 在聯繫到NameNode告知其文件寫入完成以前,此操做會將剩餘的全部數據包寫入DataNode管線並等待確認。NameNode已經直到文件由哪些塊組成(由於Datastreamer請求分配數據塊),因此它在返回成功前只須要等待數據塊進行最小量的複製。

 

 


 

參考資料 :《Hadoop權威指南(第四版)》

     http://hadoop.apache.org/docs/stable/index.html

     https://blog.csdn.net/baiye_xing/article/details/76268495#commentBox

        https://www.jianshu.com/p/53e40d3b0f7d

     http://www.javashuo.com/article/p-rfvoucjp-bx.html

       https://blog.csdn.net/qq_39192827/article/details/88953472

     https://cloud.tencent.com/community/article/282177

相關文章
相關標籤/搜索