HDFS知識總結

轉自:http://www.javashuo.com/article/p-qpwiqace-bx.htmlhtml

學習完Hadoop權威指南有一段時間了,如今再回顧和總結一下HDFS的知識點。java

一、HDFS的設計node

HDFS是什麼:HDFS即Hadoop分佈式文件系統(Hadoop Distributed Filesystem),以流式數據訪問模式來存儲超大文件,運行於商用硬件集羣上,是管理網絡中跨多臺計算機存儲的文件系統。數據庫

HDFS不適合用在:要求低時間延遲數據訪問的應用,存儲大量的小文件,多用戶寫入,任意修改文件。apache

 

二、HDFS的概念數組

HDFS數據塊:HDFS上的文件被劃分爲塊大小的多個分塊,做爲獨立的存儲單元,稱爲數據塊,默認大小是64MB。網絡

使用數據塊的好處是:架構

  • 一個文件的大小能夠大於網絡中任意一個磁盤的容量。文件的全部塊不須要存儲在同一個磁盤上,所以它們能夠利用集羣上的任意一個磁盤進行存儲。
  • 簡化了存儲子系統的設計,將存儲子系統控制單元設置爲塊,可簡化存儲管理,同時元數據就不須要和塊一同存儲,用一個單獨的系統就能夠管理這些塊的元數據。
  • 數據塊適合用於數據備份進而提供數據容錯能力和提升可用性。

查看塊信息tcp

 

 HDFS的三個節點:Namenode,Datanode,Secondary Namenode分佈式

Namenode:HDFS的守護進程,用來管理文件系統的命名空間,負責記錄文件是如何分割成數據塊,以及這些數據塊分別被存儲到那些數據節點上,它的主要功能是對內存及IO進行集中管理。

Datanode:文件系統的工做節點,根據須要存儲和檢索數據塊,而且按期向namenode發送他們所存儲的塊的列表。

Secondary Namenode:輔助後臺程序,與NameNode進行通訊,以便按期保存HDFS元數據的快照。

 

HDFS Federation(聯邦HDFS):

經過添加namenode實現擴展,其中每一個namenode管理文件系統命名空間中的一部分。每一個namenode維護一個命名空間卷,包括命名空間的源數據和該命名空間下的文件的全部數據塊的數據塊池。

 

HDFS的高可用性(High-Availability)

 Hadoop的2.x發行版本在HDFS中增長了對高可用性(HA)的支持。在這一實現中,配置了一對活動-備用(active-standby)namenode。當活動namenode失效,備用namenode就會接管它的任務並開始服務於來自客戶端的請求,不會有明顯的中斷。

架構的實現包括:

  • namenode之間經過高可用的共享存儲實現編輯日誌的共享。
  • datanode同時向兩個namenode發送數據塊處理報告。
  • 客戶端使用特定的機制來處理namenode的失效問題,這一機制對用戶是透明的。

故障轉移控制器:管理着將活動namenode轉移給備用namenode的轉換過程,基於ZooKeeper並由此確保有且僅有一個活動namenode。每個namenode運行着一個輕量級的故障轉移控制器,其工做就是監視宿主namenode是否失效並在namenode失效時進行故障切換。

 

三、命令行接口

兩個屬性項: fs.default.name 用來設置Hadoop的默認文件系統,設置hdfs URL則是配置HDFS爲Hadoop的默認文件系統。dfs.replication  設置文件系統塊的副本個數

文件系統的基本操做:hadoop fs -help能夠獲取全部的命令及其解釋

經常使用的有:

  • hadoop fs -ls /   列出hdfs文件系統根目錄下的目錄和文件
  • hadoop fs -copyFromLocal <local path> <hdfs path> 從本地文件系統將一個文件複製到HDFS
  • hadoop fs -rm -r <hdfs dir or file> 刪除文件或文件夾及文件夾下的文件
  • hadoop fs -mkdir <hdfs dir>在hdfs中新建文件夾

HDFS的文件訪問權限:只讀權限(r),寫入權限(w),可執行權限(x)

 

 四、Hadoop文件系統

Hadoop有一個抽象的文件系統概念,HDFS只是其中的一個實現。Java抽象接口org.apache.hadoop.fs.FileSystem定義了Hadoop中的一個文件系統接口。該抽象類實現HDFS的具體實現是 hdfs.DistributedFileSystem

 

五、Java接口

最簡單的從Hadoop URL讀取數據 (這裏在Eclipse上鍊接HDFS編譯運行)

複製代碼
package filesystem;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;

public class URLCat {
    static {
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }
    public static void main(String[] args) throws MalformedURLException, IOException {
        InputStream in = null;
        String input = "hdfs://192.168.92.138:9000/user/test.txt";
        try {
            in = new URL(input).openStream();
            IOUtils.copyBytes(in, System.out, 4096,false);
        }finally {
            IOUtils.closeStream(in);
        }
    }
}
複製代碼

這裏調用Hadoop的IOUtils類,在輸入流和輸出流之間複製數據(in和System.out)最後兩個參數用於第一個設置複製的緩衝區大小,第二個設置結束後是否關閉數據流。

 

還能夠經過FileSystem API讀取數據

代碼以下:

複製代碼
package filesystem;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;

public class FileSystemCat {

    public static void main(String[] args) throws IOException {
        String uri = "hdfs://192.168.92.136:9000/user/test.txt";
        Configuration conf = new Configuration();

        FileSystem fs = FileSystem.get(URI.create(uri),conf);
        InputStream in = null;
        try {
            in = fs.open(new Path(uri));
            IOUtils.copyBytes(in, System.out, 1024,false);
        }finally {
            IOUtils.closeStream(in);
        }
    }
}
複製代碼

這裏調用open()函數來獲取文件的輸入流,FileSystem的get()方法獲取FileSystem實例。

 

使用FileSystem API寫入數據

代碼以下:

複製代碼
package filesystem;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;

public class FileCopyWithProgress {

    public static void main(String[] args) throws Exception {
        String localSrc = "E:\\share\\input\\2007_12_1.txt";
        String dst = "hdfs://192.168.92.136:9000/user/logs/2008_10_2.txt";
        
        InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
        
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(dst),conf);
        OutputStream out = fs.create(new Path(dst),new Progressable() {
            public void progress() {
                System.out.print("*");
            }
        });
        IOUtils.copyBytes(in, out, 1024,true);
    }
}
複製代碼

FileSystem的create()方法用於新建文件,返回FSDataOutputStream對象。 Progressable()用於傳遞迴掉窗口,能夠用來把數據寫入datanode的進度通知給應用。

使用FileSystem API刪除數據

代碼以下:

複製代碼
package filesystem;

import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class FileDelete {

    public static void main(String[] args) throws Exception{
        String uri = "hdfs://192.168.92.136:9000/user/1400.txt";
        
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(uri),conf);
        fs.delete(new Path(uri));

    }

}
複製代碼

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

 

FileSystem的其它一些方法:

  • public boolean mkdirs(Path f)  throws IOException  用來建立目錄,建立成功返回true。
  • public FileStatus getFileStates(Path f) throws FIleNotFoundException 用來獲取文件或目錄的FileStatus對象。
  • public FileStatus[ ] listStatus(Path f)throws IOException  列出目錄中的內容
  • public FileStatus[ ] globStatu(Path pathPattern) throws IOException 返回與其路徑匹配於指定模式的全部文件的FileStatus對象數組,並按路徑排序 

 

六、數據流

HDFS讀取文件過程:

               

過程描述:

  (1)客戶端調用FileSyste對象的open()方法在分佈式文件系統中打開要讀取的文件

  (2)分佈式文件系統經過使用RPC(遠程過程調用)來調用namenode,肯定文件起始塊的位置。

  (3)分佈式文件系統的DistributedFileSystem類返回一個支持文件定位的輸入流FSDataInputStream對象,FSDataInputStream對象接着封裝DFSInputStream對象(存儲着文件起始幾個塊的datanode地址),客戶端對這個輸入流調用read()方法。

  (4)DFSInputStream鏈接距離最近的datanode,經過反覆調用read方法,將數據從datanode傳輸到客戶端

  (5) 到達塊的末端時,DFSInputStream關閉與該datanode的鏈接,尋找下一個塊的最佳datanode

  (6)客戶端完成讀取,對FSDataInputStream調用close()方法關閉鏈接

 

HDFS文件寫入的過程:

                 

過程描述:

寫文件過程分析:

  (1) 客戶端經過對DistributedFileSystem對象調用create()函數來新建文件

  (2) 分佈式文件系統對namenod建立一個RPC調用,在文件系統的命名空間中新建一個文件

  (3)Namenode對新建文件進行檢查無誤後,分佈式文件系統返回給客戶端一個FSDataOutputStream對象,FSDataOutputStream對象封裝一個DFSoutPutstream對象,負責處理namenode和datanode之間的通訊,客戶端開始寫入數據

  (4)FSDataOutputStream將數據分紅一個一個的數據包,寫入內部隊列「數據隊列」,DataStreamer負責將數據包依次流式傳輸到由一組namenode構成的管線中。

  (5)DFSOutputStream維護着確認隊列來等待datanode收到確認回執,收到管道中全部datanode確認後,數據包從確認隊列刪除

  (6)客戶端完成數據的寫入,對數據流調用close()方法。

  (7)namenode確認完成

namenode如何選擇在那個datanode存儲複本?

須要對可靠性,寫入帶寬和讀取帶寬進行權衡。默認佈局是:在運行客戶端的節點上放第一個複本(若是客戶端運行在集羣以外,則在避免挑選存儲太滿或太忙的節點的狀況下隨機選擇一個節點。)第二個複本放在與第一個不一樣且隨機另外選擇的機架中節點上。第三個複本與第二個複本放在同一個機架上,且隨機選擇另外一個節點。其它複本放在集羣中隨機選擇的節點中,儘可能避免在同一個機架上放太多複本。

一個複本個數爲3的集羣放置位置如圖:

             

HDFS一致性:HDFS在寫數據務必要保證數據的一致性與持久性,目前HDFS提供的兩種兩個保證數據一致性的方法hsync()方法和hflush()方法

hflush: 保證flush的數據被新的reader讀到,可是不保證數據被datanode持久化。
hsync: 與hflush幾乎同樣,不一樣的是hsync保證數據被datanode持久化。

 深刻hsync()和hflush()參考兩篇博客

http://www.cnblogs.com/foxmailed/p/4145330.html

http://www.cnblogs.com/yangjiandan/p/3540498.html

 

七、經過Flume和Sqoop導入數據

 能夠考慮使用一些現成的工具將數據導入。

Apache Fluem是一個將大規模流數據導入HDFS的工具。典型應用是從另一個系統中收集日誌數據並實如今HDFS中的彙集操做以便用於後期的分析操做。

Apache Sqoop用來將數據從結構化存儲設備批量導入HDFS中,例如關係數據庫。Sqoop應用場景是組織將白天生產的數據庫中的數據在晚間導入Hive數據倉庫中進行分析。

 

八、經過distcp並行複製

distcp分佈式複製程序,它從Hadoop文件系統間複製大量數據,也能夠將大量的數據複製到Hadoop。

典型應用場景是在HDFS集羣之間傳輸數據。

% hadoop  distcp  hdfs://namenode1/foo  hdfs://namenode2/bar

 

九、Hadoop存檔

HDFS中每一個文件均按塊方式存儲,每一個塊的元數據存儲在namenode的內存中,所以Hadoop存儲小文件會很是低效。由於大量的小文件會耗盡namenode中的大部份內存。Hadoop的存檔文件或HAR文件,將文件存入HDFS塊,減小namenode內存使用,容許對文件進行透明地訪問。

Hadoop存檔是經過archive工具根據一組文件建立而來的。運行archive指令:

% hadoop  archive  -archiveName  files.har  /my/files  /my

列出HAR文件的組成部分:

% hadoop  fs  -ls  /my/files.har

files.har是存檔文件的名稱,這句指令存儲 HDFS下/my/files中的文件。

HAR文件的組成部分:兩個索引文件以及部分文件的集合。

存檔的不足:

新建一個存檔文件會建立原始文件的一個副本,所以須要與要存檔的文件容量相同大小的磁盤空間。

一旦存檔文件,不能從中增長或刪除文件。

相關文章
相關標籤/搜索