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架構師部落格:
總結
HDFS是儲存基石 , MapReduce負責計算(後面會介紹), 今天我們詳細講解了hdfs的儲存系統, 就是一個核心思想: 分而治之。