一文弄懂HDFS

產(chǎn)生背景

隨著數(shù)據(jù)量越來越大奠蹬,在一個操作系統(tǒng)存不下所有的數(shù)據(jù)掺冠,那么就分配到更多的操作系統(tǒng)管理的磁盤中菇曲,但是不方便管理和維護(hù)冠绢,迫切需要一種系統(tǒng)來管理多臺機(jī)器上的文件,這就是分布式文件管理系統(tǒng)常潮,HDFS只是分布式文件管理系統(tǒng)中的一種弟胀。

HDFS(Hadoop Distributed File System),它是一個文件系統(tǒng)喊式,用于存儲文件邮利,通過目錄樹來定位文件; 其次垃帅,它是分布式的延届,由很多服務(wù)器聯(lián)合起來來實現(xiàn)其功能,集群中的服務(wù)器有各自的角色贸诚。

HDFS的使用場景方庭,適合一次寫入,多次讀出的場景酱固,且不支持對文件的修改械念,適合用來做數(shù)據(jù)分析。

HDFS優(yōu)缺點(diǎn)

優(yōu)點(diǎn)
高容錯性

  1. 數(shù)據(jù)自動保存多個副本运悲,它通過增加副本的形式龄减,提高容錯性。


    image.png
  2. 某一個副本丟失以后班眯,它可以自動恢復(fù)


    image.png

適合處理大數(shù)據(jù)

  1. 數(shù)據(jù)規(guī)模: 能夠處理數(shù)據(jù)規(guī)模達(dá)到GB, TB,甚至PB級別的數(shù)據(jù)
  2. 文件規(guī)模: 能夠處理百萬規(guī)模以上的文件數(shù)量希停。

可構(gòu)建在廉價機(jī)器上烁巫,通過多副本機(jī)制,提高可靠性

缺點(diǎn)

  1. 不適合低延時的數(shù)據(jù)訪問宠能,比如毫秒級別的存儲數(shù)據(jù)亚隙,是做不到的
  2. 無法高效的對大量小文件進(jìn)行存儲。
  • 存儲大量小文件的話违崇,它會占用NameNode大量的內(nèi)存來存儲文件目錄和塊信息阿弃,這樣是不可取的,因為namenode的內(nèi)存總是有限的羞延。
  • 小文件存儲的尋址時間會超過讀取時間渣淳,它違反了HDFS的設(shè)計目標(biāo)。
  1. 不支持并發(fā)寫入伴箩,文件隨機(jī)修改入愧。
  • 一個文件只能一個寫,不允許多個線程同時寫赛蔫;
  • 僅支持?jǐn)?shù)據(jù)追加(append),不支持對文件的隨機(jī)修改砂客。


    image.png

HDFS組成架構(gòu)

image.png

NameNode: 就是Master泥张, 它是一個主管呵恢, 管理者

  • 管理HDFS的namespace
  • 配置副本策略
  • 管理數(shù)據(jù)塊(Block)映射信息
  • 處理客戶端讀寫請求

DataNode
就是slave,NameNode下達(dá)命令媚创,DataNode執(zhí)行實際的操作渗钉。

  1. 存儲實際的塊
  2. 執(zhí)行實際數(shù)據(jù)塊的讀/寫操作

Client 就是客戶端

  • 文件切分。文件上傳HDFS的時候钞钙,Client將文件切分成一個一個的Block,然后進(jìn)行上傳鳄橘。
  • 與NameNode交互,獲取文件的位置信息
  • 與DataNode交互芒炼,讀取或者寫入數(shù)據(jù)
  • Client提供一些命令來管理HDFS瘫怜,比如NameNode格式化
  • Client可以通過一些命令來訪問HDFS,比如對HDFS增刪改查操作本刽。

Secondary NameNode
并非NameNode的熱備鲸湃,當(dāng)NameNode掛掉的時候,它并不能馬上替換NameNode并提供服務(wù)子寓。

  • 輔助NameNode,分擔(dān)其工作量暗挑,比如定期合并Fsimage和Edits, 并推送給NameNode
  • 在緊急情況下,可輔助恢復(fù)NameNode(做HA)

HDFS 文件塊大小

HDFS中的文件在物理上都是分塊存儲(Block)斜友,塊的大小可以通過配置參數(shù)(dfs.blocksize)來規(guī)定炸裆,Hadoop2.x,默認(rèn)大小是128M鲜屏,老版本是64m.

image.png

為什么塊的大小不能設(shè)置太小或者太大烹看?

  • HDFS塊設(shè)置的太小国拇,會增加尋址時間,(程序一直在找塊的開始位置)
  • 如果塊設(shè)置的太大听系,從磁盤傳輸數(shù)據(jù)的時間會明顯大于定位這個塊開始位置所需的時間贝奇,導(dǎo)致程序在處理這塊數(shù)據(jù)時,會非常慢

HDFS塊的大小設(shè)置和磁盤傳輸速率有很大關(guān)系靠胜。

HDFS操作

package com.zouxxyy.hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class HDFSClient {

    private FileSystem fs;

    @Before
    public void before() throws IOException, InterruptedException {
        // 獲取HDFS的抽象對象
        fs = FileSystem.get(URI.create("hdfs://server-2:9000"), new Configuration(), "xxx");
    }

    @Test
    public void put() throws IOException, InterruptedException {

        Configuration configuration = new Configuration();

        configuration.setInt("dfs.replication", 1);

        fs = FileSystem.get(URI.create("hdfs://server-2:9000"), configuration, "xxx");

        // 本地文件上傳到HDFS
        fs.copyFromLocalFile(new Path("data/input/wordCount/1.txt"), new Path("/"));
    }

    @Test
    public void get() throws IOException{

         // HDFS文件下載到本地
         fs.copyToLocalFile(new Path("/1.txt"), new Path("./"));
    }

    @Test
    public void rename() throws IOException{

        // HDFS重命名
        fs.rename(new Path("/1.txt"), new Path("/2.txt"));
    }

    @Test
    public void delete() throws IOException{

        // HDFS刪除
        boolean delete = fs.delete(new Path("/1.txt"), true);
        if (delete) {
            System.out.println("刪除成功");
        }
        else{
            System.out.println("刪除失敗");
        }
    }

    @Test
    public void append() throws IOException{

        // HDFS 文件追加測試
        FSDataOutputStream append = fs.append(new Path("/2.txt"), 1024);
        FileInputStream open = new FileInputStream("data/input/wordCount/1.txt");
        IOUtils.copyBytes(open, append, 1024, true);
    }

    @Test
    public void ls() throws IOException{

        // fileStatuses包含文件和文件夾
        FileStatus[] fileStatuses = fs.listStatus(new Path("/"));

        for (FileStatus fileStatus : fileStatuses) {
            if(fileStatus.isFile()) {
                System.out.println("文件:");
                System.out.println(fileStatus.getPath());
                System.out.println(fileStatus.getOwner());
            }
            else {
                System.out.println("文件夾:");
                System.out.println(fileStatus.getModificationTime());
                System.out.println(fileStatus.getPermission());
            }
        }
    }

    @Test
    public void listFiles() throws IOException {

        // 注意listFiles方法只能得到文件
        RemoteIterator<LocatedFileStatus> files = fs.listFiles(new Path("/"), true);

        while (files.hasNext()) {
            LocatedFileStatus file = files.next();

            System.out.println("===========================");
            System.out.println(file.getPath());
            System.out.println("塊信息:");
            BlockLocation[] blockLocations = file.getBlockLocations();
            for (BlockLocation blockLocation : blockLocations) {
                String[] hosts = blockLocation.getHosts();
                System.out.print("塊在: ");
                for(String host : hosts) {
                    System.out.println(host + " ");
                }
            }
        }
    }

    @After
    public void after() throws IOException {
        fs.close();
    }

}

參數(shù)優(yōu)先級: 客戶端代碼中設(shè)置的值 > ClassPath下用戶自定義的配置文件 > 服務(wù)器的默認(rèn)配置

上面的API操作HDFS都是框架封裝好的掉瞳,如果我們想自己實現(xiàn)上述API呢?

HDFS的IO流操作

更底層一點(diǎn)的操作

package com.zouxxyy.hdfs;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.Test;

public class HDFSIO {

    // 把本地e盤上的banhua.txt文件上傳到HDFS根目錄
    @Test
    public void putFileToHDFS() throws IOException, InterruptedException, URISyntaxException{
        
        // 1 獲取對象
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://server-2:9000"), conf , "xxx");
        
        // 2 獲取輸入流
        FileInputStream fis = new FileInputStream(new File("data/input/wordCount/1.txt"));
        
        // 3 獲取輸出流
        FSDataOutputStream fos = fs.create(new Path("/test.txt"));
        
        // 4 流的對拷
        IOUtils.copyBytes(fis, fos, conf);
        
        // 5 關(guān)閉資源
        IOUtils.closeStream(fos);
        IOUtils.closeStream(fis);
        fs.close();
    }
    
    
    // 從HDFS上下載banhua.txt文件到本地e盤上
    @Test
    public void getFileFromHDFS() throws IOException, InterruptedException, URISyntaxException{
        
        // 1 獲取對象
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://server-2:9000"), conf , "xxx");
        
        // 2 獲取輸入流
        FSDataInputStream fis = fs.open(new Path("/banhua.txt"));
        
        // 3 獲取輸出流
        FileOutputStream fos = new FileOutputStream(new File("e:/banhua.txt"));
        
        // 4 流的對拷
        IOUtils.copyBytes(fis, fos, conf);
        
        // 5 關(guān)閉資源
        IOUtils.closeStream(fos);
        IOUtils.closeStream(fis);
        fs.close();
    }
    
    // 下載第一塊
    @Test
    public void readFileSeek1() throws IOException, InterruptedException, URISyntaxException{
        
        // 1 獲取對象
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://server-2:9000"), conf , "xxx");
        
        // 2 獲取輸入流
        FSDataInputStream fis = fs.open(new Path("/1.txt"));

        // 3 獲取輸出流
        FileOutputStream fos = new FileOutputStream(new File("./1.txt.part1"));
        
        // 4 流的對拷(只拷貝128m)
        byte[] buf = new byte[1024];
        for (int i = 0; i < 1024 * 128; i++) {
            fis.read(buf);
            fos.write(buf);
        }
        
        // 5 關(guān)閉資源
        IOUtils.closeStream(fos);
        IOUtils.closeStream(fis);
        fs.close();
    }
    
    // 下載第二塊
    @SuppressWarnings("resource")
    @Test
    public void readFileSeek2() throws IOException, InterruptedException, URISyntaxException{
        
        // 1 獲取對象
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://server-2:9000"), conf , "xxx");
        
        // 2 獲取輸入流
        FSDataInputStream fis = fs.open(new Path("/hadoop-2.7.2.tar.gz"));
        
        // 3 設(shè)置指定讀取的起點(diǎn)
        fis.seek(1024*1024*128);
        
        // 4 獲取輸出流
        FileOutputStream fos = new FileOutputStream(new File("e:/hadoop-2.7.2.tar.gz.part2"));
        
        // 5 流的對拷
        IOUtils.copyBytes(fis, fos, conf);
        
        // 6 關(guān)閉資源
        IOUtils.closeStream(fos);
        IOUtils.closeStream(fis);
        fs.close();
    }
    
    
    
    
    
    
    
}

HDFS的數(shù)據(jù)流

寫數(shù)據(jù)流程

image.png

  1. 客戶端通過Distributed FileSystem模塊向NameNode請求上傳文件浪漠,NameNode檢查目標(biāo)文件是否已存在陕习,父目錄是否存在。
  2. NameNode返回是否可以上傳
  3. 客戶端請求第一個Block上傳到哪幾個DataNode服務(wù)器上址愿。
  4. NameNode返回3個DataNode節(jié)點(diǎn)该镣,分別為dn1,dn2,dn3
  5. 客戶端通過FSDataOutputStream模塊請求dn1上傳數(shù)據(jù),dn1收到請求會繼續(xù)調(diào)用dn2响谓,然后dn2調(diào)用dn3损合,
  6. dn1、dn2娘纷、dn3逐級應(yīng)答客戶端嫁审。
  7. 客戶端開始往dn1上傳第一個block(先從磁盤讀取數(shù)據(jù)放到一個本地內(nèi)存緩存)以packet為單位, dn1收到第一個packet就會傳給dn2赖晶,dn2傳給dn3律适。
  8. 當(dāng)一個Block傳輸完成之后,客戶端再次請求NameNode遏插,請求下一個Block傳到哪幾個DataNode服務(wù)器上捂贿。(重復(fù)執(zhí)行3-7)

節(jié)點(diǎn)距離計算

在HDFS寫數(shù)據(jù)的過程中,NameNode會選擇距離帶上傳數(shù)據(jù)最近的DataNode接收數(shù)據(jù)胳嘲。這個最近距離怎么計算呢厂僧?

image.png

機(jī)架感知

For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on the local machine if the writer is on a datanode, otherwise on a random datanode, another replica on a node in a different (remote) rack, and the last on a different node in the same remote rack.

在默認(rèn)情況下,一個文件有三個副本了牛。當(dāng)writer(執(zhí)行寫請求的客戶端)在datanode上時颜屠,第一個副本寫在本機(jī)上;當(dāng)writer沒在datanode上時白魂,隨機(jī)選一個機(jī)架里的datanode放置汽纤。第二個副本放在和第一個副本不同的機(jī)架上的隨機(jī)daanode上。第三個副本和第二個副本在同一個機(jī)架福荸,但是在不同的datanode上蕴坪。

更多副本:隨機(jī)節(jié)點(diǎn)放置。

image.png

HDFS讀數(shù)據(jù)流程

image.png
  1. 客戶端通過DistributedFileSystem向NameNode請求下載文件,NameNode通過查詢元數(shù)據(jù)背传,找到文件塊所在的DataNode地址呆瞻。(按距離順序)
  2. 客戶端挑選一臺DataNode服務(wù)器,請求讀取數(shù)據(jù)
  3. DataNode開始傳輸數(shù)據(jù)給客戶端(從磁盤里面讀取數(shù)據(jù)輸入流径玖,以packet為單位)
  4. 客戶端以packet為單位接收痴脾,先在本地緩存,然后寫入目標(biāo)文件梳星。

SecondaryNameNode

NameNode中的元數(shù)據(jù)是存儲在哪里赞赖?

首先,我們做個假設(shè)冤灾,如果存儲在NameNode節(jié)點(diǎn)的磁盤中前域,因為經(jīng)常需要進(jìn)行隨機(jī)訪問,還有響應(yīng)客戶請求韵吨,必然是效率過低匿垄。因此,元數(shù)據(jù)需要存放在內(nèi)存中归粉。但如果只存在內(nèi)存中椿疗,一旦斷電,元數(shù)據(jù)丟失糠悼,整個集群就無法工作了届榄。因此產(chǎn)生在磁盤中備份元數(shù)據(jù)的FsImage。

這樣又會帶來新的問題绢掰,當(dāng)在內(nèi)存中的元數(shù)據(jù)更新時痒蓬,如果同時更新FsImage童擎,就會導(dǎo)致效率過低滴劲,但如果不更新,就會發(fā)生一致性問題顾复,一旦NameNode節(jié)點(diǎn)斷電班挖,就會產(chǎn)生數(shù)據(jù)丟失。因此芯砸,引入Edits文件(只進(jìn)行追加操作萧芙,效率很高)。每當(dāng)元數(shù)據(jù)有更新或者添加元數(shù)據(jù)時假丧,修改內(nèi)存中的元數(shù)據(jù)并追加到Edits中双揪。這樣,一旦NameNode節(jié)點(diǎn)斷電包帚,可以通過FsImage和Edits的合并渔期,合成元數(shù)據(jù)。

但是,如果長時間添加數(shù)據(jù)到Edits中疯趟,會導(dǎo)致該文件數(shù)據(jù)過大拘哨,效率降低,而且一旦斷電信峻,恢復(fù)元數(shù)據(jù)需要的時間過長倦青。因此,需要定期進(jìn)行FsImage和Edits的合并盹舞,如果這個操作由NameNode節(jié)點(diǎn)完成产镐,又會效率過低。因此踢步,引入一個新的節(jié)點(diǎn)SecondaryNamenode磷账,專門用于FsImage和Edits的合并。

image.png
  1. 第一階段:NameNode啟動
    (1)第一次啟動NameNode格式化后贾虽,創(chuàng)建Fsimage和Edits文件逃糟。如果不是第一次啟動,直接加載編輯日志和鏡像文件到內(nèi)存蓬豁。
    (2)客戶端對元數(shù)據(jù)進(jìn)行增刪改的請求绰咽。
    (3)NameNode記錄操作日志,更新滾動日志地粪。
    (4)NameNode在內(nèi)存中對元數(shù)據(jù)進(jìn)行增刪改取募。

第二階段:Secondary NameNode工作
(1)Secondary NameNode詢問NameNode是否需要CheckPoint。直接帶回NameNode是否檢查結(jié)果蟆技。
(2)Secondary NameNode請求執(zhí)行CheckPoint玩敏。
(3)NameNode滾動正在寫的Edits日志。
(4)將滾動前的編輯日志和鏡像文件拷貝到Secondary NameNode质礼。
(5)Secondary NameNode加載編輯日志和鏡像文件到內(nèi)存旺聚,并合并。
(6)生成新的鏡像文件fsimage.chkpoint眶蕉。
(7)拷貝fsimage.chkpoint到NameNode砰粹。
(8)NameNode將fsimage.chkpoint重新命名成fsimage

NN和2NN工作機(jī)制詳解

  • Fsimage:NameNode內(nèi)存中元數(shù)據(jù)序列化后形成的文件。
  • Edits:記錄客戶端更新元數(shù)據(jù)信息的每一步操作(可通過Edits運(yùn)算出元數(shù)據(jù))造挽。

NameNode啟動時碱璃,先滾動Edits并生成一個空的edits.inprogress,然后加載Edits和Fsimage到內(nèi)存中饭入,此時NameNode內(nèi)存就持有最新的元數(shù)據(jù)信息嵌器。Client開始對NameNode發(fā)送元數(shù)據(jù)的增刪改的請求,這些請求的操作首先會被記錄到edits.inprogress中(查詢元數(shù)據(jù)的操作不會被記錄在Edits中谐丢,因為查詢操作不會更改元數(shù)據(jù)信息)爽航,如果此時NameNode掛掉,重啟后會從Edits中讀取元數(shù)據(jù)的信息。然后岳掐,NameNode會在內(nèi)存中執(zhí)行元數(shù)據(jù)的增刪改的操作凭疮。

由于Edits中記錄的操作會越來越多,Edits文件會越來越大串述,導(dǎo)致NameNode在啟動加載Edits時會很慢执解,所以需要對Edits和Fsimage進(jìn)行合并(所謂合并,就是將Edits和Fsimage加載到內(nèi)存中纲酗,照著Edits中的操作一步步執(zhí)行衰腌,最終形成新的Fsimage)。SecondaryNameNode的作用就是幫助NameNode進(jìn)行Edits和Fsimage的合并工作觅赊。

SecondaryNameNode首先會詢問NameNode是否需要CheckPoint(觸發(fā)CheckPoint需要滿足兩個條件中的任意一個右蕊,定時時間到和Edits中數(shù)據(jù)寫滿了)。直接帶回NameNode是否檢查結(jié)果吮螺。

SecondaryNameNode執(zhí)行CheckPoint操作饶囚,首先會讓NameNode滾動Edits并生成一個空的edits.inprogress,滾動Edits的目的是給Edits打個標(biāo)記鸠补,以后所有新的操作都寫入edits.inprogress萝风,其他未合并的Edits和Fsimage會拷貝到SecondaryNameNode的本地,然后將拷貝的Edits和Fsimage加載到內(nèi)存中進(jìn)行合并紫岩,生成fsimage.chkpoint规惰,然后將fsimage.chkpoint拷貝給NameNode,重命名為Fsimage后替換掉原來的Fsimage泉蝌。NameNode在啟動時就只需要加載之前未合并的Edits和Fsimage即可歇万,因為合并過的Edits中的元數(shù)據(jù)信息已經(jīng)被記錄在Fsimage中。

image.png
  1. oiv查看Fsimage文件
    (1)查看oiv和oev命令
    [atguigu@hadoop102 current]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 轉(zhuǎn)換后文件輸出路徑 (3)案例實操 [atguigu@hadoop102 current] pwd
    /opt/module/hadoop-2.7.2/data/tmp/dfs/name/current

[atguigu@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/module/hadoop-2.7.2/fsimage.xml

[atguigu@hadoop102 current]$ cat /opt/module/hadoop-2.7.2/fsimage.xml
將顯示的xml文件內(nèi)容拷貝到Eclipse中創(chuàng)建的xml文件中勋陪,并格式化贪磺。部分顯示結(jié)果如下。

<inode>
    <id>16386</id>
    <type>DIRECTORY</type>
    <name>user</name>
    <mtime>1512722284477</mtime>
    <permission>atguigu:supergroup:rwxr-xr-x</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
</inode>
<inode>
    <id>16387</id>
    <type>DIRECTORY</type>
    <name>atguigu</name>
    <mtime>1512790549080</mtime>
    <permission>atguigu:supergroup:rwxr-xr-x</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
</inode>
<inode>
    <id>16389</id>
    <type>FILE</type>
    <name>wc.input</name>
    <replication>3</replication>
    <mtime>1512722322219</mtime>
    <atime>1512722321610</atime>
    <perferredBlockSize>134217728</perferredBlockSize>
    <permission>atguigu:supergroup:rw-r--r--</permission>
    <blocks>
        <block>
            <id>1073741825</id>
            <genstamp>1001</genstamp>
            <numBytes>59</numBytes>
        </block>
    </blocks>
</inode >

思考:可以看出粥鞋,F(xiàn)simage中沒有記錄塊所對應(yīng)DataNode缘挽,為什么瞄崇?

在集群啟動后呻粹,要求DataNode上報數(shù)據(jù)塊信息,并間隔一段時間后再次上報苏研。

CheckPoint時間設(shè)置

通常情況下等浊,SecondaryNameNode每隔一小時執(zhí)行一次。

[hdfs-default.xml]
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
</property>
(2)一分鐘檢查一次操作次數(shù)摹蘑,3當(dāng)操作次數(shù)達(dá)到1百萬時筹燕,SecondaryNameNode執(zhí)行一次。
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
<description>操作動作次數(shù)</description>
</property>

<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
<description> 1分鐘檢查一次操作次數(shù)</description>
</property >

NameNode故障處理

NameNode故障后,可以采用如下兩種方法恢復(fù)數(shù)據(jù)撒踪。
方法一:將SecondaryNameNode中數(shù)據(jù)拷貝到NameNode存儲數(shù)據(jù)的目錄过咬;

  1. kill -9 NameNode進(jìn)程
  2. 刪除NameNode存儲的數(shù)據(jù)(/opt/module/hadoop-2.7.2/data/tmp/dfs/name)
    [atguigu@hadoop102 hadoop-2.7.2]$ rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*
  3. 拷貝SecondaryNameNode中數(shù)據(jù)到原NameNode存儲數(shù)據(jù)目錄
    [atguigu@hadoop102 dfs]$ scp -r atguigu@hadoop104:/opt/module/hadoop-2.7.2/data/tmp/dfs/namesecondary/* ./name/
  4. 重新啟動NameNode
    [atguigu@hadoop102 hadoop-2.7.2]$ sbin/hadoop-daemon.sh start namenode

DataNode

image.png

1)一個數(shù)據(jù)塊在DataNode上以文件形式存儲在磁盤上,包括兩個文件制妄,一個是數(shù)據(jù)本身掸绞,一個是元數(shù)據(jù)包括數(shù)據(jù)塊的長度,塊數(shù)據(jù)的校驗和耕捞,以及時間戳衔掸。
2)DataNode啟動后向NameNode注冊,通過后俺抽,周期性(1小時)的向NameNode上報所有的塊信息敞映。
3)心跳是每3秒一次,心跳返回結(jié)果帶有NameNode給該DataNode的命令如復(fù)制塊數(shù)據(jù)到另一臺機(jī)器磷斧,或刪除某個數(shù)據(jù)塊振愿。如果超過10分鐘沒有收到某個DataNode的心跳,則認(rèn)為該節(jié)點(diǎn)不可用弛饭。
4)集群運(yùn)行中可以安全加入和退出一些機(jī)器埃疫。

DataNode節(jié)點(diǎn)保證數(shù)據(jù)完整性的方法。
1)當(dāng)DataNode讀取Block的時候孩哑,它會計算CheckSum栓霜。
2)如果計算后的CheckSum,與Block創(chuàng)建時值不一樣横蜒,說明Block已經(jīng)損壞胳蛮。
3)Client讀取其他DataNode上的Block。
4)DataNode在其文件創(chuàng)建后周期驗證CheckSum

掉線時限參數(shù)設(shè)置

image.png

HDFS 2.X新特性

集群間數(shù)據(jù)拷貝
1.scp實現(xiàn)兩個遠(yuǎn)程主機(jī)之間的文件復(fù)制
scp -r hello.txt root@hadoop103:/user/atguigu/hello.txt // 推 push
scp -r root@hadoop103:/user/atguigu/hello.txt hello.txt // 拉 pull
scp -r root@hadoop103:/user/atguigu/hello.txt root@hadoop104:/user/atguigu //是通過本地主機(jī)中轉(zhuǎn)實現(xiàn)兩個遠(yuǎn)程主機(jī)的文件復(fù)制丛晌;如果在兩個遠(yuǎn)程主機(jī)之間ssh沒有配置的情況下可以使用該方式仅炊。
2.采用distcp命令實現(xiàn)兩個Hadoop集群之間的遞歸數(shù)據(jù)復(fù)制
[atguigu@hadoop102 hadoop-2.7.2]$ bin/hadoop distcp
hdfs://haoop102:9000/user/atguigu/hello.txt hdfs://hadoop103:9000/user/atguigu/hello.txt

小文件存檔

image.png

案例實操

(1)需要啟動YARN進(jìn)程
[atguigu@hadoop102 hadoop-2.7.2]$ start-yarn.sh
(2)歸檔文件
    把/user/atguigu/input目錄里面的所有文件歸檔成一個叫input.har的歸檔文件,并把歸檔后文件存儲到/user/atguigu/output路徑下澎蛛。
[atguigu@hadoop102 hadoop-2.7.2]$ bin/hadoop archive -archiveName input.har –p  /user/atguigu/input   /user/atguigu/output
(3)查看歸檔
[atguigu@hadoop102 hadoop-2.7.2]$ hadoop fs -lsr /user/atguigu/output/input.har
[atguigu@hadoop102 hadoop-2.7.2]$ hadoop fs -lsr har:///user/atguigu/output/input.har
(4)解歸檔文件
[atguigu@hadoop102 hadoop-2.7.2]$ hadoop fs -cp har:/// user/atguigu/output/input.har/*    /user/atguigu

HDFS HA

HDFS-HA工作要點(diǎn)

  1. 元數(shù)據(jù)管理方式需要改變
    內(nèi)存中各自保存一份元數(shù)據(jù)抚垄;
    Edits日志只有Active狀態(tài)的NameNode節(jié)點(diǎn)可以做寫操作;
    兩個NameNode都可以讀取Edits谋逻;
    共享的Edits放在一個共享存儲中管理(qjournal和NFS兩個主流實現(xiàn))
  2. 需要一個狀態(tài)管理功能模塊
    實現(xiàn)了一個zkfailover呆馁,常駐在每一個namenode所在的節(jié)點(diǎn),每一個zkfailover負(fù)責(zé)監(jiān)控自己所在NameNode節(jié)點(diǎn)毁兆,利用zk進(jìn)行狀態(tài)標(biāo)識浙滤,當(dāng)需要進(jìn)行狀態(tài)切換時,由zkfailover來負(fù)責(zé)切換气堕,切換時需要防止brain split現(xiàn)象的發(fā)生纺腊。
  3. 隔離(Fence)畔咧,即同一時刻僅僅有一個NameNode對外提供服務(wù)

自動故障轉(zhuǎn)移為HDFS部署增加了兩個新組件:ZooKeeper和ZKFailoverController(ZKFC)進(jìn)程,如圖3-20所示揖膜。ZooKeeper是維護(hù)少量協(xié)調(diào)數(shù)據(jù)誓沸,通知客戶端這些數(shù)據(jù)的改變和監(jiān)視客戶端故障的高可用服務(wù)。HA的自動故障轉(zhuǎn)移依賴于ZooKeeper的以下功能:
1)故障檢測:集群中的每個NameNode在ZooKeeper中維護(hù)了一個持久會話壹粟,如果機(jī)器崩潰蔽介,ZooKeeper中的會話將終止,ZooKeeper通知另一個NameNode需要觸發(fā)故障轉(zhuǎn)移煮寡。
2)現(xiàn)役NameNode選擇:ZooKeeper提供了一個簡單的機(jī)制用于唯一的選擇一個節(jié)點(diǎn)為active狀態(tài)虹蓄。如果目前現(xiàn)役NameNode崩潰,另一個節(jié)點(diǎn)可能從ZooKeeper獲得特殊的排外鎖以表明它應(yīng)該成為現(xiàn)役NameNode幸撕。
ZKFC是自動故障轉(zhuǎn)移中的另一個新組件薇组,是ZooKeeper的客戶端,也監(jiān)視和管理NameNode的狀態(tài)坐儿。每個運(yùn)行NameNode的主機(jī)也運(yùn)行了一個ZKFC進(jìn)程律胀,ZKFC負(fù)責(zé)

1)健康監(jiān)測:ZKFC使用一個健康檢查命令定期地ping與之在相同主機(jī)的NameNode,只要該NameNode及時地回復(fù)健康狀態(tài)貌矿,ZKFC認(rèn)為該節(jié)點(diǎn)是健康的炭菌。如果該節(jié)點(diǎn)崩潰,凍結(jié)或進(jìn)入不健康狀態(tài)逛漫,健康監(jiān)測器標(biāo)識該節(jié)點(diǎn)為非健康的黑低。
2)ZooKeeper會話管理:當(dāng)本地NameNode是健康的,ZKFC保持一個在ZooKeeper中打開的會話酌毡。如果本地NameNode處于active狀態(tài)克握,ZKFC也保持一個特殊的znode鎖,該鎖使用了ZooKeeper對短暫節(jié)點(diǎn)的支持枷踏,如果會話終止菩暗,鎖節(jié)點(diǎn)將自動刪除。
3)基于ZooKeeper的選擇:如果本地NameNode是健康的旭蠕,且ZKFC發(fā)現(xiàn)沒有其它的節(jié)點(diǎn)當(dāng)前持有znode鎖停团,它將為自己獲取該鎖。如果成功掏熬,則它已經(jīng)贏得了選舉佑稠,并負(fù)責(zé)運(yùn)行故障轉(zhuǎn)移進(jìn)程以使它的本地NameNode為Active。故障轉(zhuǎn)移進(jìn)程與前面描述的手動故障轉(zhuǎn)移相似孽江,首先如果必要保護(hù)之前的現(xiàn)役NameNode讶坯,然后本地NameNode轉(zhuǎn)換為Active狀態(tài)。

image.png

HDFS Federation架構(gòu)設(shè)計

NameNode架構(gòu)的局限性
(1)Namespace(命名空間)的限制
由于NameNode在內(nèi)存中存儲所有的元數(shù)據(jù)(metadata)岗屏,因此單個NameNode所能存儲的對象(文件+塊)數(shù)目受到NameNode所在JVM的heap size的限制辆琅。50G的heap能夠存儲20億(200million)個對象,這20億個對象支持4000個DataNode这刷,12PB的存儲(假設(shè)文件平均大小為40MB)婉烟。隨著數(shù)據(jù)的飛速增長,存儲的需求也隨之增長暇屋。單個DataNode從4T增長到36T似袁,集群的尺寸增長到8000個DataNode。存儲的需求從12PB增長到大于100PB咐刨。

(2)隔離問題
由于HDFS僅有一個NameNode昙衅,無法隔離各個程序,因此HDFS上的一個實驗程序就很有可能影響整個HDFS上運(yùn)行的程序定鸟。
(3)性能的瓶頸
由于是單個NameNode的HDFS架構(gòu)而涉,因此整個HDFS文件系統(tǒng)的吞吐量受限于單個NameNode的吞吐量

能不能有多個NameNode?

image.png

不同應(yīng)用可以使用不同NameNode進(jìn)行數(shù)據(jù)管理
圖片業(yè)務(wù)联予、爬蟲業(yè)務(wù)啼县、日志審計業(yè)務(wù)
Hadoop生態(tài)系統(tǒng)中,不同的框架使用不同的NameNode進(jìn)行管理NameSpace沸久。(隔離性)
在hadoop1.0的架構(gòu)中季眷,HDFS的所有的元數(shù)據(jù)都放在一個namenode中,只有一個namespace(名字空間)卷胯。這樣隨著HDFS的數(shù)據(jù)越來越多子刮,單個namenode的資源使用必然會達(dá)到上限,而且namenode的負(fù)載也會越來越高窑睁,限制了HDFS的性能话告。

在hadoop2.0架構(gòu)中,namenode federation(聯(lián)合)通過多個namenode/namespace把元數(shù)據(jù)的存儲和管理分散到多個節(jié)點(diǎn)中卵慰,使到namenode/namespace可以通過增加機(jī)器來進(jìn)行水平擴(kuò)展沙郭,并且能把單個namenode的負(fù)載分散到多個節(jié)點(diǎn)中,在HDFS數(shù)據(jù)規(guī)模較大的時候不會也降低HDFS的性能裳朋。還有可以通過多個namespace來隔離不同類型的應(yīng)用病线,把不同類型應(yīng)用的HDFS元數(shù)據(jù)的存儲和管理分派到不同的namenode中。

image.png

如果上圖所示鲤嫡,一個block pool由屬于同一個namespace的數(shù)據(jù)塊組成送挑,每個namenode管理一個namespace,即每個namenode負(fù)責(zé)存儲和管理一個block pool的元數(shù)據(jù)暖眼。而每個datanode是會連接所有的namenode的惕耕,為所有的block pools所共享,即每個datanode都會存儲所有的block pools的數(shù)據(jù)塊诫肠。每個block pool通過namespace隔離開來司澎,對一個block pool的操作不會影響另外一個block pool欺缘。

從配置和使用的角度來看,整個HDFS有一個唯一的clusterid挤安,如“hellokitty”谚殊,它可以配置多個block pool/namespace(也叫name service),如“mycluster”和“yourcluster”蛤铜。為了方便訪問不同名字空間的目錄和文件嫩絮,federation還提供了一個類似linux的Client Side Mount Table的掛載機(jī)制,提供了一個統(tǒng)一的全局的文件系統(tǒng)視圖(viewfs)围肥。用戶可以根據(jù)自己的需要把各個namespace掛載到一個叫做viewFS的文件系統(tǒng)視圖的不同目錄下剿干。例如namespace/name service “mycluster”和“yourcluster”分別掛載到viewfs的“/my”和“/your”目錄下,如下圖所示:

image.png
federation和HA

上面提到的每個namespace/name service配置一個namenode穆刻,這樣這個namespace/name service的單點(diǎn)問題還是存在置尔,因此可以給每個namespace/name service配置成HA。

假設(shè)我們有4臺namenode蛹批,分別是namenode1撰洗,namenode2,namenode3腐芍,namenode4差导。其中namenode1和namenode2是namespace/name service“mycluster”的兩個主備namenode節(jié)點(diǎn),NN_ID分別是“mycluster”的“nn1”和“nn2”猪勇;而namenode3和namenode4是namespace/name service“yourcluster”的兩個主備namenode節(jié)點(diǎn)设褐,NN_ID分別是“yourcluster”的“nn1”和“nn2”。

“mycluster”和“yourcluster”分別掛載在viewfs的“/my”和“/your”目錄下泣刹。

image.png

一般1000臺機(jī)器一下的中小規(guī)模的hadoop集群助析,一個namespace/name service就足夠了,不需要考慮federation椅您,以免增加不必要的復(fù)雜性外冀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市掀泳,隨后出現(xiàn)的幾起案子雪隧,更是在濱河造成了極大的恐慌,老刑警劉巖员舵,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脑沿,死亡現(xiàn)場離奇詭異,居然都是意外死亡马僻,警方通過查閱死者的電腦和手機(jī)庄拇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來韭邓,“玉大人措近,你說我怎么就攤上這事溶弟。” “怎么了熄诡?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵可很,是天一觀的道長诗力。 經(jīng)常有香客問我凰浮,道長,這世上最難降的妖魔是什么苇本? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任袜茧,我火速辦了婚禮,結(jié)果婚禮上瓣窄,老公的妹妹穿的比我還像新娘笛厦。我一直安慰自己,他們只是感情好俺夕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布裳凸。 她就那樣靜靜地躺著,像睡著了一般劝贸。 火紅的嫁衣襯著肌膚如雪姨谷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天映九,我揣著相機(jī)與錄音梦湘,去河邊找鬼。 笑死件甥,一個胖子當(dāng)著我的面吹牛捌议,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播引有,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼瓣颅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了譬正?” 一聲冷哼從身側(cè)響起宫补,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎导帝,沒想到半個月后守谓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡您单,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年斋荞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虐秦。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡平酿,死狀恐怖凤优,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蜈彼,我是刑警寧澤筑辨,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站幸逆,受9級特大地震影響棍辕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜还绘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一楚昭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拍顷,春花似錦抚太、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至踏揣,卻和暖如春庆亡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呼伸。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工彪标, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漏隐,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像远舅,于是被迫代替她去往敵國和親拿撩。 傳聞我的和親對象是個殘疾皇子崭别,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348