HDFS簡述

         管理網絡中跨多臺計算機存儲的文件系統稱爲分佈式文件系統,Hadoop自帶HDFS(Hadoop Distributed Filesystem)分佈式文件系統。java

1、HDFS設計

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

         超大文件:幾百MB、GB、TB,目前已有PB級。web

         流式數據訪問:一次寫入、屢次讀取;數據集一般由數據源生成或從數據源複製而來,接着長時間在此數據集上進行各類分析。apache

         商用硬件:節點故障的概率較高,被設計成可以持續運行且不讓用戶覺察到明顯中斷。swift

         低時間延遲的數據訪問:HDFS是爲高數據吞吐量應用優化的,可能會以提升時間延遲爲代價。數組

         大量的小文件:因爲namenode將文件系統的元數據存儲在內存中,所以該文件系統所能存儲的文件總數受限於namenode的內存容量。緩存

         多用戶寫入,任意修改文件:HDFS文件只支持單個寫入者,並且寫操做老是以「只添加」方式在文件末尾寫數據。不支持多個寫入者的操做,也不支持在文件的任意位置進行修改。服務器

 

2、HDFS概念

一、數據塊

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

         HDFS也有塊的概念,默認爲128MB。HDFS上的文件也被分爲塊大小的多個分塊(chunk),做爲獨立的存儲單元,HDFS中小於一個塊大小的文件不會佔據整個塊的空間。app

         HDFS的塊比磁盤的塊大,目的是爲了最小化尋址開銷。若是塊足夠大,從磁盤傳輸數據的時間會明顯大於定位這個塊開始位置所需的時間。於是,傳輸一個由多個塊組成的大文件的時間取決於磁盤傳輸速率。

         對分佈式文件系統中的塊進行抽象的好處:① 一個文件的大小能夠大於網絡中任意一個磁盤的容量,文件的全部塊並不須要存儲在同一個磁盤上;② 大大簡化了存儲子系統的設計;③ 塊適合於數據備份進而提供數據容錯能力和提升可用性,將每一個塊複製到少數幾個物理上相互獨立的機器上(默認爲3個),能夠確保在塊、磁盤或機器發生故障後數據不會丟失,一個因損壞或機器故障而丟失的塊能夠從其餘候選地點複製到另外一臺能夠正常運行的機器上,以保證複本的數量回到正常水平。

二、namenode和datanode

         HDFS集羣由兩類節點以管理節點-工做節點模式運行,即一個namenode(管理節點)和多個datanode(工做節點)。

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

  datanode是文件系統的工做節點。它們須要存儲並檢索數據塊,而且按期向namenode發送它們所存儲的塊的列表。

  沒有namenode,文件系統將沒法使用。Hadoop提供了兩種namenode容錯機制:① 備份組成文件系統元數據持久狀態的文件,通常配置是將持久狀態寫入本地磁盤的同時,寫入一個遠程掛載的網絡文件系統(NFS);② 運行一個輔助namenode,但它不能被用做namenode,輔助namenode做用是按期合併並編輯日誌與命名空間鏡像,以防止編輯日誌過大。可是,輔助namenode保存的狀態老是滯後於主節點,因此在主節點所有失效時,不免會丟失部分數據。在這種狀況下,通常把存儲在NFS上的namenode元數據複製到輔助namenode並做爲新的主namenode運行。

三、塊緩存

  一般datanode從磁盤中讀取塊,但對於訪問頻繁的文件,其對應的塊可能被顯式地緩存在datanode的內存中,以堆外塊緩存的形式存在。做業調度器經過在緩存塊的datanode上運行任務,能夠利用塊緩存的優點提升讀操做的性能。用戶或應用經過在緩存池中增長一個cache directive來告訴namenode須要緩存哪些文件以及存多久。緩存池是一個用於管理緩存權限和資源使用的管理性分組。

四、聯邦HDFS

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

  在聯邦環境下,每一個namenode維護一個命名空間卷,由命名空間的元數據和一個數據塊池組成,數據塊池包含該命名空間下文件的全部數據塊。命名空間卷之間是相互獨立的,兩兩之間並不相互通訊,數據塊池再也不進行切分。

  要訪問聯邦HDFS集羣,客戶端須要使用客戶端掛載數據表將文件路徑映射到namenode。該功能能夠經過ViewFileSystem和viewfs://URI進行配置和管理。

五、HDFS的高可用性

  Hadoop2針對namenode失效恢復的問題增長了HA支持,配置了一對活動-備用namenode。當活動namenode失效,備用namenode就會接管它的任務並開始服務於來自客戶端的請求,不會有任何明顯的中斷。目標實現須要作如下修改:

    1) namenode之間須要經過高可用共享存儲實現編輯日誌的共享;

    2) datanode須要同時向兩個namenode發送數據塊處理報告;

    3) 輔助namenode的角色被備用namenode所包含,備用namenode爲活動的namenode命名空間設置週期性檢查點。

  有兩種高可用性共享存儲:NFS過濾器或羣體日誌管理器(QJM)。QJM以一組日誌節點的形式運行,每一次編輯必須寫入多很多天志節點。

  系統中有一個故障轉移控制器的新實體,管理着將活動namenode轉移爲備用namenode的轉換過程。有多種故障轉移控制器,但默認的一種是使用了ZooKeeper來確保有且僅有一個活動namenode。每個namenode運行着一個輕量級的故障轉移控制器,其工做就是監視宿主namenode是否失效並在namenode失效時進行故障切換。

  但在非平穩故障轉移的狀況下,沒法確切知道失效namenode是否已經中止運行。高可用實現作了更進一步的優化,以確保先前活動的namenode不會執行危害系統並致使系統崩潰的操做,該方法稱爲規避。

  同一時間QJM僅容許一個namenode向編輯日誌中寫入數據。規避機制包括:撤銷namenode訪問共享存儲目錄的權限、經過遠程管理命令屏蔽相應的網絡端口。訴諸的最後手段是,經過一個特定的供電單元對相應主機進行斷電操做。

 

3、命令行接口

         在設置僞分佈式配置時,有兩個屬性項須要注意。第一項是fs.defaultFS,設置爲hdfs://localhost/,用於設置Hadoop的默認文件系統。第二項是dfs.replication,設爲1,HDFS就不會按默認設置將文件系統複本設爲3.在單獨一個datanode上運行時,HDFS沒法將塊複製到3個datanode上,因此會持續給出複本不足的警告。設置這個屬性以後,上述問題就不會再出現了。

         文件系統的基本操做:讀取文件、移動文件、刪除數據、列出目錄等。

         從本地文件系統將一個文件複製到HDFS:

                   hadoop fs –copyFromLocal input/docs/test.txt \ hdfs://localhost/user/tom/test.txt

         其中,能夠省略hdfs://localhost,由於該項已經在core-site.xml中指定。也可使用相對路徑,並將文件複製到HDFS的home目錄中:

                   hadoop fs -copyFromLocal input/docs/test.txt test.txt

         將文件複製回本地文件系統,並檢查是否一致:

                   hadoop fs –copyToLocal test.txt test.copy.txt

                   md5 input/docs/test.txt test.copy.txt

         MD5鍵值相同,代表這個文件在HDFS之旅中得以倖存並保持完整。

         新建目錄,查看HDFS文件列表:

                   hadoop fs –mkdir books

                   hadoop fs –ls

         返回結果與Unix命令ls –l輸出結果相似,有一些差異。第一列顯式文件模式。第2列是這個文件的備份數。第3列和第4列顯式文件的所屬用戶和組別。第5列是文件的大小,以字節爲單位,目錄爲0。第6列和第7列是文件的最後修改日期和時間。第8列是文件或目錄的名稱。

 

4、Hadoop文件系統

         Java抽象類org.apache.hadoop.fs.FileSystem定義了Hadoop中一個文件系統的客戶端接口,而且該抽象類有幾個具體實現,其中與Hadoop緊密相關的有Local(file-使用客戶端校驗和的本地磁盤文件系統)、HDFS(hdfs-Hadoop分佈式文件系統)、WebHDFS(Webhdfs-基於HTTP的文件系統)、SecureWebHDFS(swebhdfs-WebHDFS的HTTPS版本)、HAR(har-構建在其餘文件系統之上用於文件存檔的文件系統)、View(viewfs-針對其餘Hadoop文件系統的客戶端掛載表,一般用於爲聯邦namenode建立掛載點)、FTP(ftp-FTP服務器支持的文件系統)、S3(S3a-Amazon S3支持的文件系統)、Azure(wasb-Microsoft Azure支持的文件系統)、Swift(swift-OpenStack Swift支持的文件系統)。

         [上述文件系統中均依照 文件系統(URI方案-描述) 的格式]

         Hadoop通常使用URI方案來選取合適的文件系統實例進行交互。

         Hadoop以Java API的形式提供文件系統訪問接口,非Java開發的應用訪問HDFS會很不方便。Hadoop提供了其餘一些文件系統接口的支持:

         1) HTTP

         HTTP接口比原生的Java客戶端要慢,儘可能不要用來傳輸特大數據。經過HTTP訪問HDFS有兩種方法:直接訪問,HDFS守護進程直接服務於來自客戶端的HTTP請求;經過代理訪問,客戶端一般使用DistributedFileSystem API訪問HDFS。

第一種狀況中,namenode和datanode內嵌的web服務器做爲WebHDFS的端節點運行。文件元數據操做由namenode管理,文件讀(寫)操做首先被髮往namenode,由namenode發送一個HTTP重定向至某個客戶端,指示以流方式傳輸文件數據的目的或源datanode。

第二種方法依靠一個或者多個獨立代理服務器經過HTTP訪問HDFS。全部到集羣的網絡通訊都須要通過代理,所以客戶端歷來不直接訪問namenode和datanode。使用代理服務器後可使用更嚴格的防火牆策略和帶寬限制策略。一般狀況下都經過代理服務器,實如今不一樣數據中心部署的Hadoop集羣之間的數據傳輸,或從外網訪問雲端運行的Hadoop集羣。

  2) C語言

  Hadoop提供了一個名爲libhdfs的C語言庫,該語言庫是Java FileSystem接口類的一個鏡像。它使用Java原生接口(JNI)調用Java文件系統客戶端。一樣還有一個libwebhdfs庫,該庫使用了WebHDFS接口。

  3) NFS

  使用Hadoop的NFSv3網關將HDFS掛載爲本地客戶端的文件系統。

  4) FUSE

  用戶空間文件系統(FUSE,FileSystem in Userspace)容許將用戶空間實現的文件系統做爲Unix文件系統進行集成。

 

5、Java接口

一、從Hadoop URL讀取數據

         從Hadoop文件系統讀取文件,最簡單的方法是使用java.net.URL對象打開數據流,從中讀取數據。爲使Java程序可以識別Hadoop的hdfs URL方案,還須要經過FsUrlStreamHandlerFactory實例調用java.net.URL對象的setURLStreameHandlerFactory()方法。每一個Java虛擬機只能調用一次這個方法,所以一般在靜態方法中調用。這個限制意味着若是程序的其餘組件已經聲明一個URLStreamHandlerFactory實例,你將沒法使用這種方法從Hadoop中讀取數據。

         public class URLCat {

                   static {

                            URL.setURLStreamHandler(new FsUrlStreamHandlerFactory());

      }

 

      public static void main(String[] args) throws Exception {

              InputStream in = null;

              try {

                       in = new URL(args[0].openStream());

                       IOUtils.copyBytes(in, System.out, 4096, false);

         } finally {

               IOUtils.closeStream(in);

         }

      }

    }

    copyBytes方法最後兩個參數,第一個設置用於複製的緩衝區大小,第二個設置複製結束後是否關閉數據流。

二、經過FileSystem API讀取數據

  Hadoop文件系統中經過Hadoop Path對象來表明文件,能夠將路徑視爲一個Hadoop文件系統URI。

  1) 獲取FileSystem實例

    public static FileSystem get(Configuration conf) throws IOException

    public static FileSystem get(URI uri, Configuration conf) throws IOException

    public static FileSystem get(URI uri, Configuration conf, String user) throws IOException

  Configuration對象封裝了客戶端或服務器的配置,經過設置配置文件讀取類路徑來實現。

  2) 獲取本地文件系統的運行實例

    public static LocalFileSystem getLocal(Configuration conf) throws IOException

  3) 獲取文件的輸入流

    public FSDataInputStream open(Path f) throws IOException  --默認緩衝大小4KB

    public abstract FSDataInputStream open(Path f, int bufferSize) throws IOException

  FSDataInputStream對象是繼承了java.io.DataInputStream的一個特殊類,支持隨機訪問,能夠從流的任意位置讀取數據。

三、寫入數據

  FileSystem新建文件的方法:給準備建的文件指定一個Path對象,而後返回一個用於寫入數據的輸出流:

    public FSDataOutputStream create(Path f) throws IOException

  此方法由多個重載版本,容許指定須要強制覆蓋現有的文件、文件備份數量、寫入文件時所用緩衝區大小、文件塊大小以及文件權限。

  另外一種新建文件的方法是使用append()方法在一個現有文件末尾追加數據:

    public FSDataOutputStream append(Path f) throws IOException

  FSDataOutputStream和FSDataInputStream類類似,也有一個查詢文件當前位置的方法。但與FSDataInputStream類不一樣的是,FSDataOutputStream類不容許在文件中定位。這是由於HDFS只容許對一個已打開的文件順序寫入,或在現有文件的末尾追加數據。

四、目錄

    public boolean mkdirs(Path f) throws IOException

  這個方法能夠一次性新建全部必要但尚未的父目錄。

五、查詢文件系統

  1) 文件元數據

    FileSystem的getFileStatus()方法用於獲取文件或目錄的FileStatus對象。FileStatus封裝了文件系統中文件和目錄的元數據,包括文件長度、塊大小、複本、修改時間、全部者以及權限信息。

  2) 列出文件

         listStatus()方法能夠列出目錄中的內容:

           public FileStatus[] listStatus(Path f) throws IOException

              public FileStatus[] listStatus(Path f, PathFilter filter) throws IOException

              public FileStatus[] listStatus(Path f[] files) throws IOException

            public FileStatus[] listStatus(Path[] files, PathFilter filter) throws IOException

          它的重載方法容許使用PathFilter來限制匹配的文件和目錄。

         3) 文件模式

    能夠經過通配來匹配多個文件:

           public FileStatus[] globStatus(Path pathPattern) throws IOException

           public FileStatus[] globStatus(Path pathPattern, PathFilter filter) throws IOException

        globStatus()方法返回路徑格式與指定模式匹配的全部FileStatus對象組成的數組,並按路徑排序。

         通配符及其含義:

通配符

名稱

匹配

*

星號

匹配0或多個字符

?

問號

匹配單一字符

[ab]

字符類

匹配{a, b}集合中的一個字符

[^ab]

非字符類

匹配非{a, b}集合中的一個字符

[a-b]

字符範圍

匹配一個在{a, b}範圍內的字符(包括ab),a在字典順序上要小於或等於b

[^a-b]

非字符範圍

匹配一個不在{a, b}範圍內的字符(包括ab),a在字典順序上要小於或等於b

{a, b}

或選擇

匹配包含a或b中的一個表達式

\c

轉義字符

匹配元字符c

         4) PathFilter對象

           PathFilter對象用來排除一個特定的文件。

         5) 刪除數據

           使用delete()方法能夠永久性刪除文件或目錄。

             public boolean delete(Path f, boolean recursive) throws IOException

           若是f是一個文件或空目錄,那麼recursive的值就會被忽略。只有在recursive值爲true時,非空目錄及其內容纔會被刪除。

 

6、數據流

一、圖解文件讀取

   

 

  ① 客戶端調用FileSystem對象的open()方法來打開但願讀取的文件,對於HDFS來講,這個對象是DistributedFileSystem的一個實例。

  ② DistributedFileSystem經過使用遠程過程調用(RPC)來調用namenode,以肯定文件起始塊的位置。對於每個塊,namenode返回存有該塊副本的datanode地址,這些datanode根據它們與客戶端的距離來排序。DistributedFileSystem類返回一個FSDataInputStream對象給客戶端以便讀取數據。FSDataInputStream類轉而封裝DFSInputStream對象,該對象管理着datanode和namenode的I/O。

  ③ 客戶端對這個輸入流調用read()方法。

  ④ 存儲着文件起始幾個塊的datanode地址的DFSInputStream隨即鏈接距離最近的文件中第一個塊所在的datanode。經過對數據流反覆調用read()方法,能夠將數據從datanode傳輸到客戶端。

  ⑤ 到達塊的末端時,DFSInputStream關閉與該datanode的鏈接,而後尋找下一個塊的最佳datanode。客戶端從流中讀取數據時,塊是按照打開DFSInputStream與datanode新建鏈接的順序讀取的。它也會根據須要詢問namenode來檢索下一批數據塊的datanode位置。

  ⑥ 一旦客戶端完成讀取,就對FSDataInputStream調用close()方法。

  在讀取數據的時候,若是DFSInputStream在與datanode通訊時遇到錯誤,會嘗試從這個塊的另一個最鄰近datanode讀取數據。它也會記住那個故障datanode,以保證之後不會反覆讀取該節點上後續的塊。DFSInputStream也會經過校驗和確認從datanode發來的數據是否完整。若是發現有損壞的塊,DFSInputStream會試圖從其餘datanode讀取其複本,也會將損壞的塊通知給namenode。

二、圖解文件寫入

   

         ① DistributedFileSystem對象調用create()來新建文件。

         ② DistributedFileSystem對namenode建立一個RPC調用,在文件系統的命名空間中新建一個文件,此時該文件中尚未相應的數據塊。

③ DistributedFileSystem向客戶端返回一個FSDataOutputStream對象,由此客戶端開始寫入數據。

         ④ 在客戶端寫入數據時,DFSOutputStream將它分紅一個個的數據包,並寫入內部隊列,稱爲「數據隊列」。DataStreamer將數據包流式傳輸到管線中第1個datanode,該datanode存儲數據包並將它發送到管線中的第2個datanode。一樣,第2個datanode存儲該數據包而且發送給第3個datanode(最後一個)。

         ⑤ DFSOutputStream也維護着一個內部數據包來等待datanode的收到確認回執,稱爲「確認隊列」。收到管道中全部datanode確認信息後,該數據包纔會從確認隊列刪除。

         ⑥ 客戶端完成數據的寫入後,對數據流調用close()。

         ⑦ 該操做將剩餘的全部數據包寫入datanode管線,並在聯繫到namenode告知其文件寫入完成以前,等待確認。

         Hadoop默認複本佈局策略:在運行客戶端的節點上放第1個複本(若是客戶端運行在集羣以外,就隨即選擇一個節點,不過系統會避免挑選哪些存儲太滿或太忙的節點);第2個複本放在與第1個不一樣且隨即另外選擇的機架中節點上。第3個複本與第2個複本放在同一個機架上,且隨機選擇另外一個節點。其餘複本放在集羣中隨機選擇的節點上,不過系統會盡可能避免在同一個的機架上放太多複本。一旦選定複本的放置位置,就根據網絡拓撲建立一個管線。

三、一致模型

         文件系統的一致模型描述了文件讀/寫的數據可見性。新建一個文件以後,它能在文件系統的命名空間中當即可見。可是,寫入文件的內容不能保證當即可見,即便數據流已經刷新並存儲。

當寫入的數據超過一個塊後,第一個數據塊對新的reader就是可見的。以後的塊也不例外。總之,當前正在寫入的塊對其餘reader不可見。

HDFS提供了一種強行將全部緩存刷新到datanode中的手段,即對FSDataOutputStream調用hflush()方法。hflush()不保證datanode已經將數據寫到磁盤上,僅確保數據在datanode的內存中。爲確保數據寫入到磁盤上,能夠用hsync()替代。

 

7、經過distcp並行複製

         Distcp的一種用法是替代hadoop fs –cp。例如,能夠將文件複製到另外一個文件中:

                   hadoop distcp file1 file2

         也能夠複製目錄:

                   hadoop distcp dir1 dir2

         若是dir2不存在,將新建dir2,目錄dir1的內容所有複製到dir2下。能夠指定多個源路徑,全部源路徑下的內容都將被複制到目標路徑下。

         若是dir2已經存在,目錄dir1將被複制到dir2下,造成目錄結構dir2/dir1。若是這不是你所需的,你能夠補充使用-overwrite選項,在保持一樣的目錄結構的同時強制覆蓋原文件。你也可使用-update選項,僅更新發生變化的文件。

         distcp是做爲一個MapReduce做業來實現的,該複製做業是經過集羣中並行運行的map來完成。每一個文件經過一個map進行復制,而且distcp試圖爲每個map分配大體相等的數據來執行。

         關於distcp的一個經常使用使用實例是在兩個HDFS集羣間傳送數據:

                   hadoop distcp –update –delete –p hdfs://namenode1/foo hdfs://namenode2/foo

         -delete選項使得distcp能夠刪除目標路徑中任意沒在源路徑出現的文件或目錄,-p選項意味着文件狀態屬性如權限、塊大小和複本數被保留。

         若是兩個集羣運行的是HDFS的不兼容版本,能夠將webhdfs協議用於它們之間的distcp。另外一個變種是使用HttpFs代理做爲distcp源或目標,這樣具備設置防火牆和控制帶寬的優勢。

相關文章
相關標籤/搜索