Hadoop 之 HDFS

1 HDFS 概述

1.1 HDFS 產出背景及定義

隨着數據量越來越大,在一個操作系統存不下所有的數據,那麼就分配到更多的操作系統管理的磁盤中,但是不方便管理和維護,迫切需要一種系統來管理多臺機器上的文件,這就是分佈式文件管理系統。HDFS只是分佈式文件管理系統中的一種。

HDFS(Hadoop Distributed File System),它是一個文件系統,用於存儲文件,通過目錄樹來定位文件;其次,它是分佈式的,由很多服務器聯合起來實現其功能,集羣中的服務器有各自的角色。

HDFS的使用場景:適合一次寫入,多次讀出的場景,且不支持文件的修改。適合用來做數據分析,並不適合用來做網盤應用。

1.2 HDFS優缺點

優點:

  • 高容錯性
    • 數據自動保存多個副本。它通過增加副本的形式,提高容錯性
    • 某一個副本丟失以後,它可以自動恢復
  • 適合處理大數據
  • 可構建在廉價機器上,通過多副本機制,提高可靠性

缺點:

  • 不適合低延時數據訪問,比如毫秒級的存儲數據
  • 無法高效的對大量小文件進行存儲
  • 不支持併發寫入、文件隨機修改

1.3 HDFS組成架構

Hadoop 之 HDFS

Hadoop 之 HDFS

1.4 HDFS文件塊大小

HDFS 中的文件在物理上是分塊存儲(Block),塊的大小可以通過配置參數(dfs.blocksize)來規定,默認大小在Hadoop2.x 版本中是 128M,老版本中是 64M。

如果尋址時間爲 100ms,即查找目標 Block 的時間是 100ms。

尋址時間與傳輸時間的比例爲 100 : 1爲最佳狀態,因此傳輸時間爲 1ms。

目前磁盤的傳輸速率大概在 100MB/s,取個整大概就是 128MB。

2 HDFS 的 Shell 操作

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

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

(3)-mkdir:在 HDFS 上創建目錄

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

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

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

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

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

(9)-copyToLocal:從 HDFS 拷貝到本地

(10)-cp :從 HDFS 的一個路徑拷貝到 HDFS 的另一個路徑

(11)-mv:在 HDFS 目錄中移動文件

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

(13)-getmerge:合併下載多個文件,比如 HDFS 的目錄 /user/djm/test 下有多個文件:log.1, log.2,log.3,...

(14)-put:等同於 copyFromLocal

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

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

(17)-rmdir:刪除空目錄

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

(19)-setrep:設置 HDFS 中文件的副本數量

3 HDFS 客戶端操作

package com.djm.hdfsclient;

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

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

public class HdfsClient {

    FileSystem fileSystem = null;

    @Before
    public void init() {

        try {
            fileSystem = FileSystem.get(URI.create("hdfs://hadoop102:9000"), new Configuration(), "djm");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 上傳文件
     */
    @Test
    public void put() {
        try {
            fileSystem.copyFromLocalFile(new Path("C:\\Users\\Administrator\\Desktop\\Hadoop 入門.md"), new Path("/"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 下載文件
     */
    @Test
    public void download() {
        try {
            // useRawLocalFileSystem表示是否開啓文件校驗
            fileSystem.copyToLocalFile(false, new Path("/Hadoop 入門.md"), new Path("C:\\Users\\Administrator\\Desktop\\Hadoop 入門1.md"), true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 刪除文件
     */
    @Test
    public void delete() {
        try {
            // recursive表示是否遞歸刪除
            fileSystem.delete(new Path("/Hadoop 入門.md"), true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件重命名
     */
    @Test
    public void rename() {
        try {
            fileSystem.rename(new Path("/tmp"), new Path("/temp"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 查看文件信息
     */
    @Test
    public void ls() {
        try {
            RemoteIterator<locatedfilestatus> listFiles = fileSystem.listFiles(new Path("/etc"), true);
            while (listFiles.hasNext()) {
                LocatedFileStatus fileStatus = listFiles.next();
                if (fileStatus.isFile()) {
                    // 僅輸出文件信息
                    System.out.print(fileStatus.getPath().getName() + "   " + fileStatus.getLen() + "   " + fileStatus.getPermission() + "   "  + fileStatus.getGroup() + "   ");
                    // 獲取文件塊信息
                    BlockLocation[] blockLocations = fileStatus.getBlockLocations();
                    for (BlockLocation blockLocation : blockLocations) {
                        // 獲取節點信息
                        String[] hosts = blockLocation.getHosts();
                        for (String host : hosts) {
                            System.out.print(host + "   ");
                        }
                    }
                    System.out.println();
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @After
    public void exit() {
        try {
            fileSystem.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4 HDFS 的數據流

4.1 HDFS寫數據流程

4.1.1 剖析文件寫入

Hadoop 之 HDFS

1、客戶端通過 Distributed FileSystem 模塊向 NameNode 請求上傳文件,NameNode 檢查目標文件是否已存在,父目錄是否存在。

2、NameNode 返回是否可以上傳。

3、客戶端請求第一個 Block 上傳到哪幾個 DataNode。

4、NameNode 返回三個節點,分別是 dn1、dn2、dn3。

5、客戶端通過 FSDataOutputStream 模塊請求 dn1 上傳數據,dn1 收到請求會繼續調用 dn2,然後 dn2 調用 dn3,將這個通信管道建立完成。

6、按倒序逐級響應客戶端。

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

8、當一個Block傳輸完成之後,客戶端再次請求NameNode上傳第二個Block的服務器。

4.1.2 網絡拓撲-節點距離計算

在HDFS寫數據的過程中,NameNode會選擇距離待上傳數據最近距離的DataNode接收數據。那麼這個最近距離怎麼計算呢?

Hadoop 之 HDFS

4.1.3 機架感知

Hadoop 之 HDFS

4.2 HDFS讀數據流程

Hadoop 之 HDFS

1、客戶端通過 Distributed FileSystem 向 NameNode 請求下載文件,NameNode通過查詢元數據,找到文件塊所在的DataNode地址。

2、根據就近原則挑選一臺 DataNode,請求讀取數據。

3、DataNode 開始傳輸數據給客戶端。

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

5 NameNode 和 SecondaryNameNode

5.1 NN 和 2NN 工作機制

如果存儲在 NameNode 節點的磁盤中,因爲經常需要進行隨機訪問,還有響應客戶請求,必然是效率過低,因此,元數據必須存放在內存中,周所周知,內存的特點是速度快,斷電後丟失數據,一旦斷電,元數據丟失,整個集羣就無法工作了,因此產生了用於備份元數據的 FsImage。

但是這樣又會引發一個問題,當內存中的元數據更新時,FsImage 是否要同時更新,如果要同步更新,就會導致效率低,如果不同步更新,就會導致數據一致性問題,一旦突然斷電,就會丟失一部分數據,因此,引入了 Edits(只進行追加操作,效率很高),每當元數據進行增加或者修改時,先追加到 Edits,在修改內存,這樣的話,一旦斷電,可以通過 FsImage 和 Edits 合成元數據。

但是,如果長時間添加數據到 Edits,導致 Edits 過大,還是會影響效率,而且一旦斷電,恢復元數據的時間也會相應增加,因此,需要定期的對 FsImage 和 Edits 進行合併,如果這個操作由 NameNode 去完成,又會效率低(因爲在合併後不能處理寫請求),所以引入了 SecondaryNameNode,專門用來做合併操作。

Hadoop 之 HDFS

NameNode 工作:

1、第一次啓動 NameNode格式化後,創建 Fsimage 和 Edits 文件,如果不是第一次啓動,直接加載編輯日誌和鏡像文件到內存。

2、客戶端對元數據進行增刪改操作。

3、NameNode 記錄操作日誌,更新滾動日誌。

4、NameNode 在內存中對元數據進行增刪改操作。

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。

5.2 Fsimage 和 Edits 解析

Hadoop 之 HDFS

oiv 查看Fsimage 文件

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

oev 查看 Edits 文件

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

5.3 CheckPoint 時間設置

滿足以下兩個條件都會觸發合併操作:

通常情況下,SecondaryNameNode 每隔一小時執行一次。

  • [hdfs-default.xml]

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

一分鐘檢查一次操作次數,當次數到達 100 萬次就會觸發操作。

  • [hdfs-default.xml]

    <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.4 NameNode 故障處理

NameNode 故障後,可以採用如下兩種方法恢復數據:

將 2NN 中的數據拷貝到 NN 存儲數據的目錄。

使用 -importCheckpoint 選項啓動 NN 守護進程,從而將 2NN 中數據拷貝到 NN 目錄中。

  • hdfs namenode -importCheckpoint

5.5 集羣安全模式

Hadoop 之 HDFS

基本命令:

hdfs dfsadmin -safemode get:查看安全模式狀態

hdfs dfsadmin -safemode enter:進入安全模式狀態

hdfs dfsadmin -safemode leave:離開安全模式狀態

hdfs dfsadmin -safemode wait:等待安全模式狀態

6 DataNode

6.1 DataNode工作機制

Hadoop 之 HDFS

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

2、DataNode 啓動後向 NameNode 註冊,通過後,週期性(1小時)的向 NameNode 上報所有的塊信息。

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

4、集羣運行中可以安全加入和退出一些機器。

6.2 數據完整性

Hadoop 之 HDFS

1、當 DataNode 讀取 Block 的時候,它會計算 CheckSum。

2、如果計算後的 CheckSum,與 Block 創建時值不一樣,說明 Block 已經損壞。

3、Client 讀取其他 DataNode 上的 Block。

4、在其文件創建後周期驗證。

6.3 掉線時限參數設置

Hadoop 之 HDFS

[hdfs-site.xml]

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

6.4 服役新數據節點

將 hadoop102 上的 java、hadoop、profile 發送到新主機,source 一下 profile,直接啓動即可加入集羣。

6.5 退役舊數據節點

6.5.1 黑名單設置

創建黑名單

[djm@hadoop101 hadoop]$ touch blacklist 

配置加入黑名單的主機

hadoop102

配置 hdfs-site.xml

<property>
    <name>dfs.hosts.exclude</name>
    <value>/opt/module/hadoop-2.7.2/etc/hadoop/blacklist</value>
</property>

刷新 namenodes

[djm@hadoop102 hadoop-2.7.2]$ hdfs dfsadmin -refreshNodes

更新 ResourceManager 節點

[djm@hadoop102 hadoop-2.7.2]$ yarn rmadmin -refreshNodes

如果數據不均衡,可以用命令實現集羣的再平衡

[djm@hadoop102 hadoop-2.7.2]$ start-balancer.sh

6.5.2 白名單設置

創建白名單

[djm@hadoop101 hadoop]$ touch whitelist 

配置加入黑名單的主機

hadoop102
hadoop103
hadoop104

配置 hdfs-site.xml

<property>
    <name>dfs.hosts</name>
    <value>/opt/module/hadoop-2.7.2/etc/hadoop/whitelist</value>
</property>

刷新 namenodes

[djm@hadoop102 hadoop-2.7.2]$ hdfs dfsadmin -refreshNodes

更新 ResourceManager 節點

[djm@hadoop102 hadoop-2.7.2]$ yarn rmadmin -refreshNodes

如果數據不均衡,可以用命令實現集羣的再平衡

[djm@hadoop102 hadoop-2.7.2]$ start-balancer.sh

黑白名單的區別:

白名單比較嚴格,黑名單比較平緩,處於黑名單中的主機會同步數據結束後繼續處於集羣,只是不在處理請求而已,而不處於白名單中的主機會直接被幹掉。

6.6 Datanode多目錄配置

DataNode也可以配置成多個目錄,每個目錄存儲的數據不一樣,即:數據不是副本。

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>

7 HDFS 2.X新特性

7.1 集羣間數據拷貝

採用 distcp 命令實現兩個 Hadoop 集羣之間的遞歸數據複製

[djm@hadoop102 hadoop-2.7.2]$  hadoop distcp hdfs://haoop102:9000/user/djm/hello.txt hdfs://hadoop103:9000/user/djm/hello.txt

7.2 小文件存檔

Hadoop 之 HDFS

歸檔文件

[djm@hadoop102 hadoop-2.7.2]$ hadoop archive -archiveName input.har –p  /user/djm/input   /user/djm/output

查看歸檔

[djm@hadoop102 hadoop-2.7.2]$ hadoop fs -lsr har:///user/djm/output/input.har

解歸檔文件

[atguigu@djm hadoop-2.7.2]$ hadoop fs -cp har:/// user/djm/output/input.har/*    /user/djm

</locatedfilestatus>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章