Hadoop之HDFS基礎

一。 HDFS概念

1.1 概念

    HDFS是一個分佈式文件系統,用於存儲文件,經過目錄樹來定位文件,適合一次寫入,屢次讀出的場景,且不支持文件的修改。適合用來作數據分析,並不適合用來作網盤應用。html

1.2 組成

1)HDFS集羣包括,NameNode和DataNode以及Secondary Namenode。java

2)NameNode負責管理整個文件系統的元數據,以及每個路徑(文件)所對應的數據塊信息。node

3)DataNode 負責管理用戶的文件數據塊,每個數據塊均可以在多個datanode上存儲多個副本。linux

4)Secondary NameNode用來監控HDFS狀態的輔助後臺程序,每隔一段時間獲取HDFS元數據的快照。web

1.3 HDFS 文件塊大小

    HDFS中的文件在物理上是分塊存儲(block),塊的大小能夠經過配置參數( dfs.blocksize)來規定,默認大小在hadoop2.x版本中是128M,老版本中是64M。apache

    HDFS的塊比磁盤的塊大,其目的是爲了最小化尋址開銷,且傳輸一個由多個塊組成的文件的時間取決於磁盤傳輸速率。緩存

    若是尋址時間約爲10ms,而傳輸速率爲100MB/s,爲了使尋址時間僅佔傳輸時間的1%,咱們要將塊大小設置約爲100MB。默認的塊大小實際爲64MB,可是不少狀況下HDFS使用128MB的塊設置。安全

    塊的大小:10ms*100*100M/s = 100M服務器

二 。HFDS命令行操做

1)基本語法網絡

    hadoop fs 具體命令

2)參數大全

3)經常使用命令實操

    (1)-help:輸出這個命令參數

    (2)-ls: 顯示目錄信息

  (3)-mkdir:在hdfs上建立目錄

         hadoop fs  -mkdir  -p  /aaa/bbb/cc/dd

  (4)-moveFromLocal從本地剪切粘貼到hdfs

        hadoop  fs  - moveFromLocal  /home/hadoop/a.txt  /aaa/bbb/cc/dd

  (5)-moveToLocal:從hdfs剪切粘貼到本地

        hadoop  fs  - moveToLocal   /aaa/bbb/cc/dd  /home/hadoop/a.txt

  (6)--appendToFile  :追加一個文件到已經存在的文件末尾

        hadoop  fs  -appendToFile  ./hello.txt  /hello.txt

  (7)-cat :顯示文件內容

        hadoop  fs  -cat  /hello.txt

  (8)-tail:顯示一個文件的末尾

         hadoop  fs  -tail  /weblog/access_log.1

  (9)-text:以字符形式打印一個文件的內容

        hadoop  fs  -text  /weblog/access_log.1

  (10)-chgrp 、-chmod、-chown:linux文件系統中的用法同樣,修改文件所屬權限

        hadoop  fs  -chmod  666  /hello.txt

        hadoop  fs  -chown  someuser:somegrp   /hello.txt

  (11)-copyFromLocal:從本地文件系統中拷貝文件到hdfs路徑去

        hadoop  fs  -copyFromLocal  ./jdk.tar.gz  /aaa/

  (12)-copyToLocal:從hdfs拷貝到本地

        hadoop fs -copyToLocal /aaa/jdk.tar.gz

  (13)-cp :從hdfs的一個路徑拷貝到hdfs的另外一個路徑

        hadoop  fs  -cp  /aaa/jdk.tar.gz  /bbb/jdk.tar.gz.2

  (14)-mv:在hdfs目錄中移動文件

        hadoop  fs  -mv  /aaa/jdk.tar.gz  /

  (15)-get:等同於copyToLocal,就是從hdfs下載文件到本地

        hadoop fs -get  /aaa/jdk.tar.gz

  (16)-getmerge  :合併下載多個文件,好比hdfs的目錄 /aaa/下有多個文件:log.1, log.2,log.3,...

        hadoop fs -getmerge /aaa/log.* ./log.sum

  (17)-put:等同於copyFromLocal

        hadoop  fs  -put  /aaa/jdk.tar.gz  /bbb/jdk.tar.gz.2

  (18)-rm:刪除文件或文件夾

        hadoop fs -rm -r /aaa/bbb/

  (19)-rmdir:刪除空目錄

        hadoop  fs  -rmdir   /aaa/bbb/ccc

  (20)-df :統計文件系統的可用空間信息

        hadoop  fs  -df  -h  /

  (21)-du統計文件夾的大小信息

        hadoop  fs  -du  -s  -h /aaa/*

  (22)-count:統計一個指定目錄下的文件節點數量

        hadoop fs -count /aaa/

  (23)-setrep:設置hdfs中文件的副本數量

        hadoop fs -setrep 3 /aaa/jdk.tar.gz

        這裏設置的副本數只是記錄在namenode的元數據中,是否真的會有這麼多副本,還得看datanode的數量。

三。HDFS客戶端操做

3.1 一個完整的Java操做,在hdfs上建立目錄

package com.hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class HDFSApp {
    public static final String HDFS_PATH ="hdfs://hadoop102:9000";

    Configuration configuration = null ;
    FileSystem fileSystem = null;

    @Before
    public void setUp() throws Exception {
        System.out.println("HDFSApp.setUp()");
        configuration = new Configuration();
        fileSystem = FileSystem.get(new URI(HDFS_PATH), configuration);
    }

    @After
    public void tearDown(){
        fileSystem = null;
        configuration = null;
        System.out.println("HDFSApp.tearDown()");
    }

    // 建立目錄,不會覆蓋已經存在的目錄
    @Test
    public void mkdir() throws IOException {
        fileSystem.mkdirs(new Path("/hdfsApi/test"));
    }
}

能夠查看到hdfs建立的目錄

3.2 經過API操做HDFS

3.2.1 HDFS獲取文件系統

1)詳細代碼

    @Test
    public void initHDFS() throws Exception{
        // 1 建立配置信息對象
        // new Configuration();的時候,它就會去加載jar包中的hdfs-default.xml
        // 而後再加載classpath下的hdfs-site.xml
        Configuration configuration = new Configuration();
        
        // 2 設置參數 
        // 參數優先級: 一、客戶端代碼中設置的值  二、classpath下的用戶自定義配置文件 三、而後是服務器的默認配置
        //  configuration.set("fs.defaultFS", "hdfs://hadoop102:9000");
        configuration.set("dfs.replication", "3");
        
        // 3 獲取文件系統
        FileSystem fs = FileSystem.get(configuration);
        
        // 4 打印文件系統
        System.out.println(fs.toString());
    }

2)將core-site.xml拷貝到項目的根目錄下

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
<!-- 指定HDFS中NameNode的地址 -->
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://hadoop102:9000</value>
    </property>

    <!-- 指定hadoop運行時產生文件的存儲目錄 -->
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/opt/module/hadoop/data/tmp</value>
    </property>
</configuration>

3.2.2 HDFS文件上傳

    @Test
    public void putFileToHDFS() throws Exception{
        // 1 建立配置信息對象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
        // 2 建立要上傳文件所在的本地路徑
        Path src = new Path("e:/hello.txt");
        
        // 3 建立要上傳到hdfs的目標路徑
        Path dst = new Path("hdfs://hadoop102:9000/user/gh/hello.txt");
        
        // 4 拷貝文件
        fs.copyFromLocalFile(src, dst);
        fs.close();    
}

3.2.3 HDFS文件下載

@Test
public void getFileFromHDFS() throws Exception{
        
    // 1 建立配置信息對象
    Configuration configuration = new Configuration();
        
    FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");    
    
//    fs.copyToLocalFile(new Path("hdfs://hadoop102:9000/user/gh/hello.txt"), new Path("d:/hello.txt"));
    // boolean delSrc 指是否將原文件刪除
    // Path src 指要下載的文件路徑
    // Path dst 指將文件下載到的路徑
    // boolean useRawLocalFileSystem 是否開啓文件效驗
    // 2 下載文件
    fs.copyToLocalFile(false, new Path("hdfs://hadoop102:9000/user/gh/hello.txt"), new Path("e:/hellocopy.txt"), true);
    fs.close();
}

3.2.4 HDFS目錄建立

    @Test
    public void mkdirAtHDFS() throws Exception{
        // 1 建立配置信息對象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");    
        
        //2 建立目錄
        fs.mkdirs(new Path("hdfs://hadoop102:9000/user/gh/output"));
    }

3.2.5 HDFS文件夾刪除

    @Test
    public void deleteAtHDFS() throws Exception{
        // 1 建立配置信息對象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");    
        
        //2 刪除文件夾 ,若是是非空文件夾,參數2必須給值true
        fs.delete(new Path("hdfs://hadoop102:9000/user/gh/output"), true);
    }

3.2.6 HDFS文件名更改

    @Test
    public void renameAtHDFS() throws Exception{
        // 1 建立配置信息對象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
        //2 重命名文件或文件夾
        fs.rename(new Path("hdfs://hadoop102:9000/user/gh/hello.txt"), new Path("hdfs://hadoop102:9000/user/gh/hellonihao.txt"));
    }

3.2.7 HDFS文件詳情查看

@Test
public void readListFiles() throws Exception {
    // 1 建立配置信息對象
    Configuration configuration = new Configuration();
        
    FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
    // 思考:爲何返回迭代器,而不是List之類的容器
    RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);

    while (listFiles.hasNext()) {
        LocatedFileStatus fileStatus = listFiles.next();
            
        System.out.println(fileStatus.getPath().getName());
        System.out.println(fileStatus.getBlockSize());
        System.out.println(fileStatus.getPermission());
        System.out.println(fileStatus.getLen());
            
        BlockLocation[] blockLocations = fileStatus.getBlockLocations();
            
        for (BlockLocation bl : blockLocations) {
                
            System.out.println("block-offset:" + bl.getOffset());
                
            String[] hosts = bl.getHosts();
                
            for (String host : hosts) {
                System.out.println(host);
            }
        }
            
        System.out.println("----------------------------");
    }
    }

3.2.8 HDFS文件夾查看

@Test
public void findAtHDFS() throws Exception, IllegalArgumentException, IOException{
        
    // 1 建立配置信息對象
    Configuration configuration = new Configuration();
        
    FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
    // 2 獲取查詢路徑下的文件狀態信息
    FileStatus[] listStatus = fs.listStatus(new Path("/"));

    // 3 遍歷全部文件狀態
    for (FileStatus status : listStatus) {
        if (status.isFile()) {
            System.out.println("f--" + status.getPath().getName());
        } else {
            System.out.println("d--" + status.getPath().getName());
        }
    }
}

3.3 經過IO流操做HDFS

3.3.1 HDFS文件上傳

    @Test
    public void putFileToHDFS() throws Exception{
        // 1 建立配置信息對象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
        // 2 建立輸入流
        FileInputStream inStream = new FileInputStream(new File("e:/hello.txt"));
        
        // 3 獲取輸出路徑
        String putFileName = "hdfs://hadoop102:9000/user/gh/hello1.txt";
        Path writePath = new Path(putFileName);

        // 4 建立輸出流
        FSDataOutputStream outStream = fs.create(writePath);

        // 5 流對接
        try{
            IOUtils.copyBytes(inStream, outStream, 4096, false);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            IOUtils.closeStream(inStream);
            IOUtils.closeStream(outStream);
        }
    }

3.3.2 HDFS文件下載

    @Test
    public void getFileToHDFS() throws Exception{
        // 1 建立配置信息對象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
        // 2 獲取讀取文件路徑
        String filename = "hdfs://hadoop102:9000/user/gh/hello1.txt";
        
        // 3 建立讀取path
        Path readPath = new Path(filename);
        
        // 4 建立輸入流
        FSDataInputStream inStream = fs.open(readPath);
        
        // 5 流對接輸出到控制檯
        try{
            IOUtils.copyBytes(inStream, System.out, 4096, false);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            IOUtils.closeStream(inStream);
        }
    }

3.3.3 定位文件讀取

1)下載第一塊

@Test
// 定位下載第一塊內容
public void readFileSeek1() throws Exception {

    // 1 建立配置信息對象
    Configuration configuration = new Configuration();

    FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "gh");

    // 2 獲取輸入流路徑
    Path path = new Path("hdfs://hadoop102:9000/user/gh/tmp/hadoop.tar.gz");

    // 3 打開輸入流
    FSDataInputStream fis = fs.open(path);

    // 4 建立輸出流
    FileOutputStream fos = new FileOutputStream("e:/hadoop.tar.gz.part1");

    // 5 流對接
    byte[] buf = new byte[1024];
    for (int i = 0; i < 128 * 1024; i++) {
        fis.read(buf);
        fos.write(buf);
    }

    // 6 關閉流
    IOUtils.closeStream(fis);
    IOUtils.closeStream(fos);
    }

2)下載第二塊

    @Test
    // 定位下載第二塊內容
    public void readFileSeek2() throws Exception{
        
        // 1 建立配置信息對象
        Configuration configuration = new Configuration();

        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "gh");
        
        // 2 獲取輸入流路徑
        Path path = new Path("hdfs://hadoop102:9000/user/gh/tmp/hadoop.tar.gz");
        
        // 3 打開輸入流
        FSDataInputStream fis = fs.open(path);
        
        // 4 建立輸出流
        FileOutputStream fos = new FileOutputStream("e:/hadoop.tar.gz.part2");
        
        // 5 定位偏移量(第二塊的首位)
        fis.seek(1024 * 1024 * 128);
        
        // 6 流對接
        IOUtils.copyBytes(fis, fos, 1024);
        
        // 7 關閉流
        IOUtils.closeStream(fis);
        IOUtils.closeStream(fos);
    }

3)合併文件

    在window命令窗口中執行

    type hadoop.tar.gz.part2 >> hadoop.tar.gz.part1

四。HDFS的數據流

4.1 HDFS寫數據流程

4.1.1 剖析文件寫入

1)客戶端向namenode請求上傳文件,namenode檢查目標文件是否已存在,父目錄是否存在。

2)namenode返回是否能夠上傳。

3)客戶端請求第一個 block上傳到哪幾個datanode服務器上。

4)namenode返回3個datanode節點,分別爲dn一、dn二、dn3。

5)客戶端請求dn1上傳數據,dn1收到請求會繼續調用dn2,而後dn2調用dn3,將這個通訊管道創建完成

6)dn一、dn二、dn3逐級應答客戶端

7)客戶端開始往dn1上傳第一個block(先從磁盤讀取數據放到一個本地內存緩存),以packet爲單位,dn1收到一個packet就會傳給dn2,dn2傳給dn3;dn1每傳一個packet會放入一個應答隊列等待應答

8)當一個block傳輸完成以後,客戶端再次請求namenode上傳第二個block的服務器。(重複執行3-7步)

4.1.2 網絡拓撲概念

        在本地網絡中,兩個節點被稱爲「彼此近鄰」是什麼意思?在海量數據處理中,其主要限制因素是節點之間數據的傳輸速率——帶寬很稀缺。這裏的想法是將兩個節點間的帶寬做爲距離的衡量標準。

       節點距離:兩個節點到達最近的共同祖先的距離總和。

        例如,假設有數據中心d1機架r1中的節點n1。該節點能夠表示爲/d1/r1/n1。利用這種標記,這裏給出四種距離描述。

        Distance(/d1/r1/n1, /d1/r1/n1)=0(同一節點上的進程)

        Distance(/d1/r1/n1, /d1/r1/n2)=2(同一機架上的不一樣節點)

        Distance(/d1/r1/n1, /d1/r3/n2)=4(同一數據中心不一樣機架上的節點)

        Distance(/d1/r1/n1, /d2/r4/n2)=6(不一樣數據中心的節點)

4.1.3 機架感知(副本節點選擇)

1)官方ip地址:

        http://hadoop.apache.org/docs/r2.7.3/hadoop-project-dist/hadoop-common/RackAwareness.html

        http://hadoop.apache.org/docs/r2.7.3/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html#Data_Replication

2)低版本Hadoop1.x副本節點選擇

        第一個副本在client所處的節點上。若是客戶端在集羣外,隨機選一個。

        第二個副本和第一個副本位於不相同機架的隨機節點上。

        第三個副本和第二個副本位於相同機架,節點隨機。

3)Hadoop2.x副本節點選擇

       第一個副本在client所處的節點上。若是客戶端在集羣外,隨機選一個。

       第二個副本和第一個副本位於相同機架,隨機節點。

       第三個副本位於不一樣機架,隨機節點。

4.2 HDFS讀數據流程

1)客戶端向namenode請求下載文件,namenode經過查詢元數據,找到文件塊所在的datanode地址。

2)挑選一臺datanode(就近原則,而後隨機)服務器,請求讀取數據。

3)datanode開始傳輸數據給客戶端(從磁盤裏面讀取數據放入流,以packet(數據包)爲單位來作校驗)。

4)客戶端以packet爲單位接收,先在本地緩存,而後寫入目標文件。

4.3 一致性模型

1)debug調試以下代碼

@Test
    public void writeFile() throws Exception{
        // 1 建立配置信息對象
        Configuration configuration = new Configuration();
        fs = FileSystem.get(configuration);
        
        // 2 建立文件輸出流
        Path path = new Path("hdfs://hadoop102:9000/user/gh/hello.txt");
        FSDataOutputStream fos = fs.create(path);
        
        // 3 寫數據
        fos.write("hello".getBytes());
        // 4 一致性刷新
        fos.hflush();
        
        fos.close();
    }

2)總結

        寫入數據時,若是但願數據被其餘client當即可見,調用以下方法

        FsDataOutputStream. hflush ();           //清理客戶端緩衝區數據,被其餘client當即可見

五。NameNode工做機制

 5.1 NameNode&Secondary NameNode工做機制

1)第一階段:namenode啓動

        (1)第一次啓動namenode格式化後,建立fsimage和edits文件。若是不是第一次啓動,直接加載編輯日誌和鏡像文件到內存。

        (2)客戶端對元數據進行增刪改的請求

        (3)namenode記錄操做日誌,更新滾動日誌。

        (4)namenode在內存中對數據進行增刪改查

2)第二階段:Secondary NameNode工做

       (1)Secondary NameNode詢問namenode是否須要checkpoint。直接帶回namenode是否檢查結果。

       (2)Secondary NameNode請求執行checkpoint。

       (3)namenode滾動正在寫的edits日誌

       (4)將滾動前的編輯日誌和鏡像文件拷貝到Secondary NameNode

       (5)Secondary NameNode加載編輯日誌和鏡像文件到內存,併合並。

       (6)生成新的鏡像文件fsimage.chkpoint

       (7)拷貝fsimage.chkpoint到namenode

       (8)namenode將fsimage.chkpoint從新命名成fsimage

4)chkpoint檢查時間參數設置

        (1)一般狀況下,SecondaryNameNode每隔一小時執行一次。

          [hdfs-default.xml]

<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600</value>
</property>

        (2)一分鐘檢查一次操做次數,當操做次數達到1百萬時,SecondaryNameNode執行一次。

<property>
  <name>dfs.namenode.checkpoint.txns</name>
  <value>1000000</value>
<description>操做動做次數</description>
</property>

<property>
  <name>dfs.namenode.checkpoint.check.period</name>
  <value>60</value>
<description> 1分鐘檢查一次操做次數</description>
</property>

5.2 鏡像文件和編輯日誌文件

1)概念

       namenode被格式化以後,將在設置的存放目錄 ---name/current目錄中產生以下文件(hdfs-site.xml裏面設置存放目錄)

edits_0000000000000000000
fsimage_0000000000000000000.md5
seen_txid
VERSION

    (1)Fsimage文件:HDFS文件系統元數據的一個永久性的檢查點,其中包含HDFS文件系統的全部目錄和文件idnode的序列化信息。 

    (2)Edits文件:存放HDFS文件系統的全部更新操做的路徑,文件系統客戶端執行的全部寫操做首先會被記錄到edits文件中。 

    (3)seen_txid文件保存的是一個數字,就是最後一個edits_的數字

    (4)每次Namenode啓動的時候都會將fsimage文件讀入內存,並從00001開始到seen_txid中記錄的數字依次執行每一個edits裏面的更新操做,保證內存中的元數據信息是最新的、同步的,能夠當作Namenode啓動的時候就將fsimage和edits文件進行了合併。

2)oiv查看fsimage文件

    (1)查看oiv和oev命令

       hdfs

       oiv                  apply the offline fsimage viewer to an fsimage

       oev                  apply the offline edits viewer to an edits file

    (2)基本語法

      hdfs oiv -p 文件類型 -i 鏡像文件 -o 轉換後文件輸出路徑

   (3)案例

         將顯示的xml文件內容拷貝到idea或者eclipse中,並格式化。

3)oev查看edits文件

    (1)基本語法

        hdfs oev -p 文件類型 -i 編輯日誌 -o 轉換後文件輸出路徑

   (2)案例

     將顯示的xml文件內容拷貝到idea或者eclipse中,並格式化。

5.3 滾動編輯日誌

    正常狀況HDFS文件系統有更新操做時,就會滾動編輯日誌。也能夠用命令強制滾動編輯日誌。

    1)滾動編輯日誌(前提必須啓動集羣)

    hdfs dfsadmin -rollEdits

    2)鏡像文件何時產生

    Namenode啓動時加載鏡像文件

5.4 namenode版本號

1)查看namenode版本號

    在----/name/current這個目錄下查看VERSION

2)namenode版本號具體解釋

    (1)namespaceID在HDFS上,會有多個Namenode,因此不一樣Namenode的namespaceID是不一樣的,分別管理一組blockpoolID。

    (2)clusterID集羣id,全局惟一

    (3)cTime屬性標記了namenode存儲系統的建立時間,對於剛剛格式化的存儲系統,這個屬性爲0;可是在文件系統升級以後,該值會更新到新的時間戳。

    (4)storageType屬性說明該存儲目錄包含的是namenode的數據結構。

    (5)blockpoolID:一個block pool id標識一個block pool,而且是跨集羣的全局惟一。當一個新的Namespace被建立的時候(format過程的一部分)會建立並持久化一個惟一ID。在建立過程構建全局惟一的BlockPoolID比人爲的配置更可靠一些。NN將BlockPoolID持久化到磁盤中,在後續的啓動過程當中,會再次load並使用。

    (6)layoutVersion是一個負整數。一般只有HDFS增長新特性時纔會更新這個版本號。

5.5 SecondaryNameNode目錄結構

     Secondary NameNode用來監控HDFS狀態的輔助後臺程序,每隔一段時間獲取HDFS元數據的快照。

     在----/namesecondary/current這個目錄中查看SecondaryNameNode目錄結構。

     SecondaryNameNode的namesecondary/current目錄和主namenode的current目錄的佈局相同。   

    好處:在主namenode發生故障時(假設沒有及時備份數據),能夠從SecondaryNameNode恢復數據。

    方法一:將SecondaryNameNode中數據拷貝到namenode存儲數據的目錄;

    方法二:使用-importCheckpoint選項啓動namenode守護進程,從而將SecondaryNameNode用做新的主namenode。

1)案例(一):

    模擬namenode故障,並採用方法一,恢復namenode數據。

    (1)kill -9 namenode進程

    (2)刪除namenode存儲的數據

 

    (3)拷貝SecondaryNameNode中數據到原namenode存儲數據目錄

 

    (4)從新啓動namenode

    能夠查看到原來的數據被還原了

    2)案例(二):

    模擬namenode故障,並採用方法二,恢復namenode數據。

    首先須要在hdfs-site.xml中加入nameNode的存儲路徑。

    <property>
          <name>dfs.namenode.name.dir</name>
          <value>/data/hadoop/tmp/dfs/name</value>
    </property>

  (1)kill -9 namenode進程

  (2)刪除namenode存儲的數據

  (3)若是SecondaryNameNode不和Namenode在一個主機節點上,須要將SecondaryNameNode存儲數據的目錄拷貝到Namenode存儲數據的平級目錄。

  (4)導入檢查點數據(等待一會ctrl+c結束掉)

  (5)啓動namenode

  (6)若是提示文件鎖了,能夠刪除SecondaryNameNode存儲目錄裏面的 in_use.lock

5.6 集羣安全模式操做

1)概述

       Namenode啓動時,首先將映像文件(fsimage)載入內存,並執行編輯日誌(edits)中的各項操做。一旦在內存中成功創建文件系統元數據的映像,則建立一個新的fsimage文件和一個空的編輯日誌。此時,namenode開始監聽datanode請求。可是此刻,namenode運行在安全模式,即namenode的文件系統對於客戶端來講是隻讀的。

       系統中的數據塊的位置並非由namenode維護的,而是以塊列表的形式存儲在datanode中。在系統的正常操做期間,namenode會在內存中保留全部塊位置的映射信息。在安全模式下,各個datanode會向namenode發送最新的塊列表信息,namenode瞭解到足夠多的塊位置信息以後,便可高效運行文件系統。

       若是知足「最小副本條件」,namenode會在30秒鐘以後就退出安全模式。所謂的最小副本條件指的是在整個文件系統中99.9%的塊知足最小副本級別(默認值:dfs.replication.min=1)。在啓動一個剛剛格式化的HDFS集羣時,由於系統中尚未任何塊,因此namenode不會進入安全模式。

2)基本語法

        集羣處於安全模式,不能執行重要操做(寫操做)。集羣啓動完成後,自動退出安全模式。

  (1)bin/hdfs dfsadmin -safemode get        (功能描述:查看安全模式狀態)

  (2)bin/hdfs dfsadmin -safemode enter    (功能描述:進入安全模式狀態)

  (3)bin/hdfs dfsadmin -safemode leave     (功能描述:離開安全模式狀態)

  (4)bin/hdfs dfsadmin -safemode wait       (功能描述:等待安全模式狀態)

3)案例

  模擬等待安全模式

  1)先進入安全模式

  2)執行下面的命令

  3)在另外一個窗口中對hdfs進行寫操做

  4)離開安全模式

5.7 Namenode多目錄配置

1)namenode的本地目錄能夠配置成多個,且每一個目錄存放內容相同,增長了可靠性。

2)具體配置以下:

  hdfs-site.xml

<property>
    <name>dfs.namenode.name.dir</name>
<value>file:///${hadoop.tmp.dir}/dfs/name1,file:///${hadoop.tmp.dir}/dfs/name2</value>
</property>

六。DataNode工做機制

6.1 DataNode工做機制

  1)一個數據塊在datanode上以文件形式存儲在磁盤上,包括兩個文件,一個是數據自己,一個是元數據包括數據塊的長度,塊數據的校驗和,以及時間戳。

  2)DataNode啓動後向namenode註冊,經過後,週期性(1小時)的向namenode上報全部的塊信息。

  3)心跳是每3秒一次,心跳返回結果帶有namenode給該datanode的命令如複製塊數據到另外一臺機器,或刪除某個數據塊。若是超過10分鐘沒有收到某個datanode的心跳,則認爲該節點不可用。

  4)集羣運行中能夠安全加入和退出一些機器

6.2 數據完整性

1)當DataNode讀取block的時候,它會計算checksum

2)若是計算後的checksum,與block建立時值不同,說明block已經損壞。

3)client讀取其餘DataNode上的block.

4)datanode在其文件建立後周期驗證checksum

6.3 掉線時限參數設置

  datanode進程死亡或者網絡故障形成datanode沒法與namenode通訊,namenode不會當即把該節點斷定爲死亡,要通過一段時間,這段時間暫稱做超時時長。HDFS默認的超時時長爲10分鐘+30秒。若是定義超時時間爲timeout,則超時時長的計算公式爲:

       timeout  = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。

       而默認的dfs.namenode.heartbeat.recheck-interval 大小爲5分鐘,dfs.heartbeat.interval默認爲3秒。

       須要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的單位爲毫秒,dfs.heartbeat.interval的單位爲秒。

<property>
    <name>dfs.namenode.heartbeat.recheck-interval</name>
    <value>300000</value>
</property>
<property>
    <name> dfs.heartbeat.interval </name>
    <value>3</value>
</property>

6.4 DataNode的目錄結構

  和namenode不一樣的是,datanode的存儲目錄是初始階段自動建立的,不須要額外格式化。

  1)在----/tmp/dfs/data/current這個目錄下查看版本號

  2)具體解釋

         (1)storageID:存儲id號

         (2)clusterID集羣id,全局惟一

         (3)cTime屬性標記了datanode存儲系統的建立時間,對於剛剛格式化的存儲系統,這個屬性爲0;可是在文件系統升級以後,該值會更新到新的時間戳。

         (4)datanodeUuid:datanode的惟一識別碼

         (5)storageType:存儲類型

         (6)layoutVersion是一個負整數。一般只有HDFS增長新特性時纔會更新這個版本號。

  3)在-----tmp/dfs/data/current/BP-639183006-10.20.0.130-1555500554508/current這個目錄下查看該數據塊的版本號

 

  4)具體解釋

  (1)namespaceID:是datanode首次訪問namenode的時候從namenode處獲取的storageID對每一個datanode來講是惟一的(但對於單個datanode中全部存儲目錄來講則是相同的),namenode可用這個屬性來區分不一樣datanode。

  (2)cTime屬性標記了datanode存儲系統的建立時間,對於剛剛格式化的存儲系統,這個屬性爲0;可是在文件系統升級以後,該值會更新到新的時間戳。

  (3)blockpoolID:一個block pool id標識一個block pool,而且是跨集羣的全局惟一。當一個新的Namespace被建立的時候(format過程的一部分)會建立並持久化一個惟一ID。在建立過程構建全局惟一的BlockPoolID比人爲的配置更可靠一些。NN將BlockPoolID持久化到磁盤中,在後續的啓動過程當中,會再次load並使用。

  (4)layoutVersion是一個負整數。一般只有HDFS增長新特性時纔會更新這個版本號。

6.5 服役新數據節點

0)需求:

  在原有集羣基礎上動態添加新的數據節點。

  略

6.6 退役舊數據節點

  在原有集羣基礎上動態刪除舊的數據節點。

  略

6.7 Datanode多目錄配置

1)datanode也能夠配置成多個目錄,每一個目錄存儲的數據不同。即:數據不是副本。

2)具體配置以下:

       hdfs-site.xml

    <property>
        <name>dfs.datanode.data.dir</name>
        <value>file:///${hadoop.tmp.dir}/dfs/data1,file:///${hadoop.tmp.dir}/dfs/data2</value>
    </property>

七。HDFS其餘功能

7.1 集羣間數據拷貝

1)scp實現兩個遠程主機之間的文件複製

       scp -r hello.txt root@hadoop103:/hello.txt             // 推 push

       scp -r root@hadoop103:/hello.txt  hello.txt           // 拉 pull

       scp -r root@hadoop103:/hello.txt root@hadoop104:/   //是經過本地主機中轉實現兩個遠程主機的文件複製;若是在兩個遠程主機之間ssh沒有配置的狀況下可使用該方式。

2)採用discp命令實現兩個hadoop集羣之間的遞歸數據複製

  hadoop distcp hdfs://haoop102:9000/hello.txt hdfs://hadoop103:9000/hello.txt

7.2 Hadoop存檔

1)理論概述

  每一個文件均按塊存儲,每一個塊的元數據存儲在namenode的內存中,所以hadoop存儲小文件會很是低效。由於大量的小文件會耗盡namenode中的大部份內存。但注意,存儲小文件所須要的磁盤容量和存儲這些文件原始內容所須要的磁盤空間相比也不會增多。例如,一個1MB的文件以大小爲128MB的塊存儲,使用的是1MB的磁盤空間,而不是128MB。

  Hadoop存檔文件或HAR文件,是一個更高效的文件存檔工具,它將文件存入HDFS塊,在減小namenode內存使用的同時,容許對文件進行透明的訪問。具體說來,Hadoop存檔文件能夠用做MapReduce的輸入。

2)案例

(1)須要啓動yarn進程

       start-yarn.sh

(2)歸檔文件

       歸檔成一個叫作xxx.har的文件夾,該文件夾下有相應的數據文件。Xx.har目錄是一個總體,該目錄當作是一個歸檔文件便可。

[root@master001 dfs]# hadoop archive -archiveName myhar.har -p /hdfsApi /my

3)查看歸檔

4)解歸檔文件

[root@master001 dfs]# hadoop fs -cp har:///my/myhar.har/* /ghh

7.3 快照管理

  快照至關於對目錄作一個備份。並不會當即複製全部文件,而是指向同一個文件。當寫入發生時,纔會產生新文件。

1)基本語法

       (1)hdfs dfsadmin -allowSnapshot 路徑   (功能描述:開啓指定目錄的快照功能)

       (2)hdfs dfsadmin -disallowSnapshot 路徑 (功能描述:禁用指定目錄的快照功能,默認是禁用)

       (3)hdfs dfs -createSnapshot 路徑        (功能描述:對目錄建立快照)

       (4)hdfs dfs -createSnapshot 路徑 名稱   (功能描述:指定名稱建立快照)

       (5)hdfs dfs -renameSnapshot 路徑 舊名稱 新名稱 (功能描述:重命名快照)

       (6)hdfs lsSnapshottableDir         (功能描述:列出當前用戶全部可快照目錄)

       (7)hdfs snapshotDiff 路徑1 路徑2 (功能描述:比較兩個快照目錄的不一樣之處)

       (8)hdfs dfs -deleteSnapshot <path> <snapshotName>  (功能描述:刪除快照)

2)案例

  略

7.4 回收站

八。HDFS HA高可用

相關文章
相關標籤/搜索