Hadoop HDFS入門

Hadoop 附帶了一個名爲 HDFS(Hadoop分佈式文件系統)的分佈式文件系統,基於 Hadoop 的應用程序使用 HDFS 。HDFS 是專爲存儲超大數據文件,運行在集羣的商品硬件上。它是容錯的,可伸縮的,並且非常易於擴展。

    你知道嗎?  當數據超過一個單個物理機器上存儲的容量,除以跨獨立機器數。管理跨越機器的網絡存儲特定操作被稱爲分佈式文件系統。

HDFS集羣主要由 NameNode 管理文件系統 Metadata 和 DataNodes 存儲的實際數據。

  • NameNode: NameNode可以被認爲是系統的主站。它維護所有系統中存在的文件和目錄的文件系統樹和元數據 。 兩個文件:「命名空間映像「和」編輯日誌「是用來存儲元數據信息。Namenode 有所有包含數據塊爲一個給定的文件中的數據節點的知識,但是不存儲塊的位置持續。從數據節點在系統每次啓動時信息重構一次。

  • DataNode : DataNodes作爲從機,每臺機器位於一個集羣中,並提供實際的存儲. 它負責爲客戶讀寫請求服務。

HDFS中的讀/寫操作運行在塊級。HDFS數據文件被分成塊大小的塊,這是作爲獨立的單元存儲。默認塊大小爲64 MB。

HDFS操作上是數據複製的概念,其中在數據塊的多個副本被創建,分佈在整個節點的羣集以使在節點故障的情況下數據的高可用性。

注:  在HDFS的文件,比單個塊小,不佔用塊的全部存儲。

在HDFS讀操作

數據讀取請求將由 HDFS,NameNode和DataNode來服務。讓我們把讀取器叫 「客戶」。下圖描繪了文件的讀取操作在 Hadoop 中。
Hadoop

  1. 客戶端啓動通過調用文件系統對象的 open() 方法讀取請求; 它是 DistributedFileSystem 類型的對象。

  2. 此對象使用 RPC 連接到 namenode 並獲取的元數據信息,如該文件的塊的位置。 請注意,這些地址是文件的前幾個塊。

  3. 響應該元數據請求,具有該塊副本的 DataNodes 地址被返回。

  4. 一旦接收到 DataNodes 的地址,FSDataInputStream 類型的一個對象被返回到客戶端。 FSDataInputStream 包含 DFSInputStream 這需要處理交互 DataNode 和 NameNode。在上圖所示的步驟4,客戶端調用 read() 方法,這將導致 DFSInputStream 建立與第一個 DataNode 文件的第一個塊連接。

  5. 以數據流的形式讀取數據,其中客戶端多次調用 「read() 」 方法。 read() 操作這個過程一直持續,直到它到達塊結束位置。

  6. 一旦到模塊的結尾,DFSInputStream 關閉連接,移動定位到下一個 DataNode 的下一個塊

  7. 一旦客戶端已讀取完成後,它會調用 close()方法。

HDFS寫操作

在本節中,我們將瞭解如何通過的文件將數據寫入到 HDFS。
Hadoop

  1. 客戶端通過調用 DistributedFileSystem對象的 create() 方法創建一個新的文件,並開始寫操作 - 在上面的圖中的步驟1
  2. DistributedFileSystem對象使用 RPC 調用連接到 NameNode,並啓動新的文件創建。但是,此文件創建操作不與文件任何塊相關聯。NameNode 的責任是驗證文件(其正被創建的)不存在,並且客戶端具有正確權限來創建新文件。如果文件已經存在,或者客戶端不具有足夠的權限來創建一個新的文件,則拋出 IOException 到客戶端。否則操作成功,並且該文件新的記錄是由 NameNode 創建。
  3. 一旦 NameNode 創建一條新的記錄,返回FSDataOutputStream 類型的一個對象到客戶端。客戶端使用它來寫入數據到 HDFS。數據寫入方法被調用(圖中的步驟3)。
  4. FSDataOutputStream包含DFSOutputStream對象,它使用 DataNodes 和 NameNode 通信後查找。當客戶機繼續寫入數據,DFSOutputStream 繼續創建這個數據包。這些數據包連接排隊到一個隊列被稱爲 DataQueue
  5. 還有一個名爲 DataStreamer 組件,用於消耗DataQueue。DataStreamer 也要求 NameNode 分配新的塊,揀選 DataNodes 用於複製。
  6. 現在,複製過程始於使用 DataNodes 創建一個管道。 在我們的例子中,選擇了複製水平3,因此有 3 個 DataNodes 管道。
  7. 所述 DataStreamer 注入包分成到第一個 DataNode 的管道中。
  8. 在每個 DataNode 的管道中存儲數據包接收並同樣轉發在第二個 DataNode 的管道中。
  9. 另一個隊列,「Ack Queue」是由 DFSOutputStream 保持存儲,它們是 DataNodes 等待確認的數據包。
  10. 一旦確認在隊列中的分組從所有 DataNodes 已接收在管道,它從 'Ack Queue' 刪除。在任何 DataNode 發生故障時,從隊列中的包重新用於操作。
  11. 在客戶端的數據寫入完成後,它會調用close()方法(第9步圖中),調用close()結果進入到清理緩存剩餘數據包到管道之後等待確認。
  12. 一旦收到最終確認,NameNode 連接告訴它該文件的寫操作完成。

使用JAVA API訪問HDFS

在本節中,我們來了解 Java 接口並用它們來訪問Hadoop的文件系統。

爲了使用編程方式與 Hadoop 文件系統進行交互,Hadoop 提供多種 Java 類。**org.apache.hadoop.fs** 包中包含操縱 Hadoop 文件系統中的文件類工具。這些操作包括,打開,讀取,寫入,和關閉。實際上,對於 Hadoop 文件 API 是通用的,可以擴展到 HDFS 的其他文件系統交互。

編程從 HDFS 讀取文件

java.net.URL 對象是用於讀取文件的內容。首先,我們需要讓 Java 識別 Hadoop 的 HDFS URL架構。這是通過調用 URL 對象的 setURLStreamHandlerFactory方法和 FsUrlStreamHandlerFactory 的一個實例琮傳遞給它。此方法只需要執行一次在每個JVM,因此,它被封閉在一個靜態塊中。

示例代碼

 

publicclassURLCat {

    static{

        URL.setURLStreamHandlerFactory(newFsUrlStreamHandlerFactory());

    }

    publicstaticvoidmain(String[] args) throwsException {

        InputStream in = null;

        try{

            in = newURL(args[0]).openStream();

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

        } finally{

            IOUtils.closeStream(in);

        }

    }

}

這段代碼用於打開和讀取文件的內容。HDFS文件的路徑作爲命令行參數傳遞給該程序。

使用命令行界面訪問HDFS

這是與 HDFS 交互的最簡單的方法之一。 命令行接口支持對文件系統操作,例如:如讀取文件,創建目錄,移動文件,刪除數據,並列出目錄。

可以執行 '$HADOOP_HOME/bin/hdfs dfs -help' 來獲得每一個命令的詳細幫助。這裏, 'dfs' HDFS是一個shell命令,它支持多個子命令。首先要啓動 Haddop 服務(使用 hduser_用戶),執行命令如下:

hduser_@ubuntu:$ su hduser_
hduser_@ubuntu:
$ $HADOOP_HOME/sbin/start-dfs.sh
hduser_@ubuntu:~$ $HADOOP_HOME/sbin/start-yarn.sh

一些廣泛使用的命令的列表如下

1. 從本地文件系統複製文件到 HDFS

hduser_@ubuntu:~$ $HADOOP_HOME/bin/hdfs dfs -copyFromLocal temp.txt /

此命令將文件從本地文件系統拷貝 temp.txt 文件到 HDFS。

2. 我們可以通過以下命令列出一個目錄下存在的文件 -ls

hduser_@ubuntu:~$ $HADOOP_HOME/bin/hdfs dfs -ls /

Hadoop

我們可以看到一個文件 'temp.txt「(之前複製)被列在」/「目錄。

3. 以下命令將文件從 HDFS 拷貝到本地文件系統

hduser_@ubuntu:~$ $HADOOP_HOME/bin/hdfs dfs -copyToLocal /temp.txt

我們可以看到 temp.txt 已經複製到本地文件系統。

4. 以下命令用來創建新的目錄

hduser_@ubuntu:~$ $HADOOP_HOME/bin/hdfs dfs -mkdir /mydirectory

接下來檢查是否已經建立了目錄。現在,應該知道怎麼做了吧?