1. 程式人生 > 其它 >hadoop3 HDFS介紹(二)

hadoop3 HDFS介紹(二)

HDFS前言

設計的的思想:主要的是分而治之,將大的檔案分割稱為一個個小的檔案,儲存在各個機器上。

在大資料中的應用:為大資料框架提供儲存資料的服務

重點概念:檔案分塊、副本存放、元資料。

HDFS的概念和特性

首先,它是一個檔案系統,用於儲存檔案,通過統一的名稱空間——目錄樹來定位檔案。

其次,它是分散式的,很多伺服器聯合實現功能。

HDFS組成結構圖

HDFS 寫檔案的基本流程

先來了解幾個概念

block

檔案上傳前需要分塊,這個塊就是block,一般為128MB,當然你可以去改(改成多少跟磁碟效能有關)。block太小的話,會導致block的數量多,定址block的時間就會增加。block太大的話,會導致Map任務數太少,作業執行速度變慢。它是最大的一個單位。

packet

packet是第二大的單位,它是client端向DataNode,或DataNode的PipLine之間傳資料的基本單位,預設64KB。

chunk

chunk是最小的單位,它是client向DataNode,或DataNode的PipLine之間進行資料校驗的基本單位,預設512Byte,因為用作校驗,故每個chunk需要帶有4Byte的校驗位。所以實際每個chunk寫入packet的大小為516Byte。由此可見真實資料與校驗值資料的比值約為128 : 1。(即64*1024 / 512)

例如,在client端向DataNode傳資料的時候,HDFSOutputStream會有一個chunk buff,寫滿一個chunk後,會計算校驗和並寫入當前的chunk。之後再把帶有校驗和的chunk寫入packet,當一個packet寫滿後,packet會進入dataQueue佇列,其他的DataNode就是從這個dataQueue獲取client端上傳的資料並存儲的。同時一個DataNode成功儲存一個packet後之後會返回一個ack packet,放入ack Queue中。

詳細步驟

  • client請求NameNode上傳檔案,NameNode查詢對應許可權,目錄存不存在等 返回是否可以上傳。
  • client對檔案進行block切片,並請求NameNode第一個 Block 上傳到哪幾個 DataNode 伺服器上。
  • NameNode 根據副本數等資訊返回可用的DataNode節點,例如上面的 dn1,dn2,dn3。
  • client 請求3臺節點中的一臺伺服器dn1,進行傳送資料(本質上是一個RPC呼叫,建立管道Pipeline),dn1收到請求會繼續呼叫伺服器dn2,然後伺服器dn3呼叫伺服器dn3。將這個通訊管道建立完成。
  • client 開始往 dn1上傳第一個Block(先從磁碟讀取資料放到一個本地記憶體快取),以 Packet為單位,dn1收到一個 Packet就會傳給 dn2,dn2傳給 dn3;dn1每傳一個 packet會放入一個應答佇列等待應答。
  • 資料被分割成一個個Packet資料包在Pipeline上依次傳輸,而在Pipeline反方向上,將逐個傳送Ack(命令正確應答),最終由Pipeline中第一個DataNode節點dn1將Pipeline的 Ack資訊傳送給客戶端。
  • 當一個 Block傳輸完成之後,客戶端再次請求 NameNode上傳第二個 Block的伺服器。

HDFS 讀檔案的基本流程

  • client 通過 Distributed FileSystem向 NameNode請求下載檔案,NameNode通過查詢元資料,找到檔案塊所在的DataNode地址進行返回。
  • 挑選一臺 DataNode(就近原則,然後隨機)伺服器,請求讀取資料。當第一次讀取完成之後,才進行第二次塊的讀取。
  • DataNode開始傳輸資料給客戶端(從磁盤裡面讀取資料輸入流,以 Packet為單位來做校驗)。
  • 客戶端以 Packet為單位接收,先在本地快取,然後寫入目標檔案。

NameNode+SecondaryNameNode工作原理

  • 叢集啟動,會載入edits日誌和fsimage檔案到記憶體得到元資料。
  • client發起元資料的修改操作時,NameNode先將操作順序追加到edits_inprogress001檔案(效率極高),然後更新到記憶體(保證元資料最新)。
  • SecondaryNameNode會定期(一小時)或者 edits日誌滿了(比如到達了100w條),會請求NameNode進行CheckPoint。
  • NameNode會生成一個新的edits_inprogress002 用於儲存新的請求。然後將原來的edits_inprogress001 修改成edits_001。
  • SecondaryNameNode 會將NameNode的edits_001 和 fsimage拉取過來,進行計算(執行edits裡面的操作)合併成新的映象檔案(fsimage.chkpoint),然後傳送給NameNode。
  • NameNode將fsimage.chkpoint改名覆蓋原來的fsimage 。這樣fsimage 就保持了當前SecondaryNameNode計算合併的最新(加上edits_inprogress002 才是最新的元資料)。

為什麼要有fsimage?

為了伺服器斷電後恢復元資料。fsimage就是元資料的磁碟映象。

為什麼要有edits日誌?

沒有這個日誌,當我們修改元資料,就只能修改fsimage檔案,修改磁碟檔案是效率極低的。edits日誌只能順序追加,記錄的是元資料的操作(類似redis的AOF),這個效率是極高的。後面通過 SecondaryNameNode 的定期合併 生成新的fsimage,這樣保證了元資料高效備份到磁碟。

DataNode 工作原理

DataNode用於儲存檔案的表現形式block,還儲存了block的長度,校驗和,以及時間戳。

DataNode啟動後向NameNode註冊 當前可用的block資訊,以後每隔(N小時)向NameNode上報所有的block資訊 。

DataNode同時每隔3秒向NameNode傳送心跳,如果超過10分鐘沒有收到某個datanode的心跳,則認為該節點不可用。

HDFS Shell基本命令

1.檢視有哪些命令

[root@hadoop1 ~]# hadoop fs
Usage: hadoop fs [generic options]
    [-appendToFile <localsrc> ... <dst>]
    [-cat [-ignoreCrc] <src> ...]
    [-checksum <src> ...]
    [-chgrp [-R] GROUP PATH...]
    [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
    [-chown [-R] [OWNER][:[GROUP]] PATH...]
    [-copyFromLocal [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
    [-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
    [-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] [-e] <path> ...]
    [-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
    [-createSnapshot <snapshotDir> [<snapshotName>]]
    [-deleteSnapshot <snapshotDir> <snapshotName>]
    [-df [-h] [<path> ...]]
    [-du [-s] [-h] [-v] [-x] <path> ...]
    [-expunge]
    [-find <path> ... <expression> ...]
    [-get [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
    [-getfacl [-R] <path>]
    [-getfattr [-R] {-n name | -d} [-e en] <path>]
    [-getmerge [-nl] [-skip-empty-file] <src> <localdst>]
    [-head <file>]
    [-help [cmd ...]]
    [-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [<path> ...]]
    [-mkdir [-p] <path> ...]
    [-moveFromLocal <localsrc> ... <dst>]
    [-moveToLocal <src> <localdst>]
    [-mv <src> ... <dst>]
    [-put [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
    [-renameSnapshot <snapshotDir> <oldName> <newName>]
    [-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ...]
    [-rmdir [--ignore-fail-on-non-empty] <dir> ...]
    [-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
    [-setfattr {-n name [-v value] | -x name} <path>]
    [-setrep [-R] [-w] <rep> <path> ...]
    [-stat [format] <path> ...]
    [-tail [-f] [-s <sleep interval>] <file>]

2.建立資料夾

# 建立資料夾
[root@hadoop1 ~]# hadoop fs -mkdir /hadluo
# 列出檔案
[root@hadoop1 ~]# hadoop fs -ls /hadluo
#檢視檔案
[root@hadoop1 ~]# hadoop fs -cat /hadluo/b.txt
# 跟linux一樣 ,還有 rm -r,tail ,cp,mv,du

3.上傳

#從本地剪下上傳到hdfs
[root@hadoop1 local]# hadoop fs -moveFromLocal /usr/local/b.txt /hadluo
#從本地複製上傳到hdfs
[root@hadoop1 local]# hadoop fs -put /usr/local/b.txt /hadluo
#追加一個檔案到已經存在的檔案末尾
[root@hadoop1 local]# hadoop fs -appendToFile /usr/local/a.txt /hadluo/b.txt

4.下載

# 拷貝到本地
[root@hadoop1 local]# hadoop fs -get /hadluo/b.txt ./

HDFS Java Api

引入 maven:

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>3.1.3</version>
</dependency> 

java程式碼:

public class HDFS {
    public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException {
        Configuration configuration = new Configuration();
        // 設定副本數
        configuration.set("dfs.replication", "2");
        // 建立客戶端
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop1:8020"), configuration, "root");
        // 建立資料夾
        fs.mkdirs(new Path("/abc"));
        // 上傳
        fs.copyFromLocalFile(new Path("C:\\Users\\youh\\Desktop\\斗店爬蟲v0.0.1\\geckodriver.exe"), new Path("/abc"));
        // 下載
        fs.copyToLocalFile(new Path("/abc/geckodriver.exe"), new Path("C:\\Users\\youh\\Desktop\\斗店爬蟲v0.0.1"));
        // 刪除 引數2:是否遞迴刪除
        fs.delete(new Path("/abc"), false);
        // 檔案移動 並且 改名
        fs.rename(new Path("/abc/geckodriver.exe"), new Path("/klk/geckodriver22.exe"));
        // 遞迴遍歷資料夾
        RemoteIterator<LocatedFileStatus> it = fs.listFiles(new Path("/abc"), false);
        while (it.hasNext()) {
            LocatedFileStatus file = it.next();
            System.out.println("檔名:" + file.getPath().getName());
            System.out.println("塊儲存資訊:" + file.getBlockLocations());
            System.out.println("副本數:" + file.getReplication());
        }
        // 判斷是否是檔案
        for (FileStatus status : fs.listStatus(new Path("/abc"))) {
            System.out.println("是否是檔案: " + status.isFile());
        }
        // 關閉客戶端
        fs.close();
    }
}

學好大資料,必須學好java,推薦一個java架構師部落格:

https://githubs.xyz/

總結

HDFS是儲存基石 , MapReduce負責計算(後面會介紹), 今天我們詳細講解了hdfs的儲存系統, 就是一個核心思想: 分而治之。