HDFS 2.7.5核心講解

目錄

  1. HDFS概述
  2. HDFS應用場景
  3. HDFS架構
  4. Namenode與Datanode講解
  5. HDFS的副本機制和機架感知
  6. HDFS命令行
  7. HDFS文件數量空間限制
  8. HDFS基準測試
  9. HDFS寫入數據過程
  10. HDFS讀取數據過程
  11. HDFS 的元數據輔助管理
  12. HDFS Java客戶端
  13. HDFS高可用機制
  14. HDFS聯邦機制

HDFS概述

1.1 介紹

在現代的企業環境中,單機容量往往無法存儲大量數據,需要跨機器存儲。統一管理分佈在集羣上的文件系統稱爲分佈式文件系統

​HDFS(Hadoop Distributed File System)是 Apache Hadoop 項目的一個子項目. Hadoop 非常適於存儲大型數據 (比如 TB 和 PB), 其就是使用 HDFS 作爲存儲系統. HDFS 使用多臺計算機存儲文件, 並且提供統一的訪問接口, 像是訪問一個普通文件系統一樣使用分佈式文件系統.
在這裏插入圖片描述

1.2 歷史

  1. Doug Cutting 在做 Lucene 的時候, 需要編寫一個爬蟲服務, 這個爬蟲寫的並不順利, 遇到了一些問題, 諸如: 如何存儲大規模的數據, 如何保證集羣的可伸縮性, 如何動態容錯等
  2. 2013年的時候, Google 發佈了三篇論文, 被稱作爲三駕馬車, 其中有一篇叫做 GFS, 是描述了 Google 內部的一個叫做 GFS 的分佈式大規模文件系統, 具有強大的可伸縮性和容錯性
  3. Doug Cutting 後來根據 GFS 的論文, 創造了一個新的文件系統, 叫做 HDFS

HDFS應用場景

2.1 適合的應用場景

  • 存儲非常大的文件:這裏非常大指的是幾百M、G、或者TB級別,需要高吞吐量,對延時沒有要求
  • 採用流式的數據訪問方式: 即一次寫入、多次讀取,數據集經常從數據源生成或者拷貝一次,然後在其上做很多分析工作 。
  • 運行於商業硬件上: Hadoop不需要特別貴的機器,可運行於普通廉價機器,可以處節約成本
  • 需要高容錯性

2.2 不適合的應用場景

1) 低延時的數據訪問
對延時要求在毫秒級別的應用,不適合採用HDFS。HDFS是爲高吞吐數據傳輸設計的,因此可能犧牲延時

2)大量小文件
文件的元數據保存在NameNode的內存中, 整個文件系統的文件數量會受限於NameNode的內存大小。
經驗而言,一個文件/目錄/文件塊一般佔有150字節的元數據內存空間。如果有100萬個文件,每個文件佔用1個文件塊,則需要大約300M的內存。因此十億級別的文件數量在現有商用機器上難以支持。

3)多方讀寫,需要任意的文件修改
HDFS採用追加(append-only)的方式寫入數據。不支持文件任意offset的修改。不支持多個寫入器(writer)

HDFS架構

HDFS是一個【主/從(Mater/Slave)體系結構】,

HDFS由四部分組成,HDFS ClientNameNodeDataNodeSecondary NameNode
在這裏插入圖片描述
1、Client:就是客戶端。

  • 文件切分。文件上傳 HDFS 的時候,Client 將文件切分成 一個一個的Block,然後進行存儲。
  • 與 NameNode 交互,獲取文件的位置信息。
  • 與 DataNode 交互,讀取或者寫入數據。
  • Client 提供一些命令來管理 和訪問HDFS,比如啓動或者關閉HDFS。

2、NameNode:就是 master,它是一個主管、管理者。

  • 管理 HDFS 的名稱空間
  • 管理數據塊(Block)映射信息
  • 配置副本策略
  • 處理客戶端讀寫請求。

3、DataNode:就是Slave。NameNode 下達命令,DataNode 執行實際的操作。

  • 存儲實際的數據塊。
  • 執行數據塊的讀/寫操作。

4、Secondary NameNode:並非 NameNode 的熱備。當NameNode 掛掉的時候,它並不能馬上替換 NameNode 並提供服務。

  • 輔助 NameNode,分擔其工作量。
  • 定期合併 fsimage和fsedits,並推送給NameNode。
  • 在緊急情況下,可輔助恢復 NameNode。

Namenode與Datanode講解

在這裏插入圖片描述

4.1 NameNode作用

1、NameNode元數據信息
文件名,文件目錄結構,文件屬性(生成時間,副本數,權限)每個文件的塊列表。
以及列表中的塊與塊所在的DataNode之間的地址映射關係
在內存中加載文件系統中每個文件和每個數據塊的引用關係(文件、block、datanode之間的映射信息)
數據會定期保存到本地磁盤(fsImage文件和edits文件)

2、NameNode文件操作
NameNode負責文件元數據的操作
DataNode負責處理文件內容的讀寫請求,數據流不經過NameNode,會詢問它跟那個DataNode聯繫

3、NameNode副本
文件數據塊到底存放到哪些DataNode上,是由NameNode決定的,NN根據全局情況做出放置副本的決定

4、NameNode心跳機制
全權管理數據塊的複製,週期性的接受心跳和塊的狀態報告信息(包含該DataNode上所有數據塊的列表)
若接受到心跳信息,NameNode認爲DataNode工作正常,如果在10分鐘後還接受到不到DN的心跳,那麼NameNode認爲DataNode已經宕機 ,這時候NN準備要把DN上的數據塊進行重新的複製。 塊的狀態報告包含了一個DN上所有數據塊的列表,blocks report 每個1小時發送一次.

4.2 DataNode作用

提供真實文件數據的存儲服務。

1、Data Node以數據塊的形式存儲HDFS文件

2、Data Node 響應HDFS 客戶端讀寫請求

3、Data Node 週期性向NameNode彙報心跳信息

4、Data Node 週期性向NameNode彙報數據塊信息

5、Data Node 週期性向NameNode彙報緩存數據塊信息

HDFS的副本機制和機架感知

5.1 HDFS 文件副本機制

所有的文件都是以 block 塊的方式存放在 HDFS 文件系統當中,作用如下

  1. 一個文件有可能大於集羣中任意一個磁盤,引入塊機制,可以很好的解決這個問題
  2. 使用塊作爲文件存儲的邏輯單位可以簡化存儲子系統
  3. 塊非常適合用於數據備份進而提供數據容錯能力

在 Hadoop1 當中, 文件的 block 塊默認大小是 64M, hadoop2 當中, 文件的 block 塊大小默認是 128M, block 塊的大小可以通過 hdfs-site.xml 當中的配置文件進行指定

<property>
    <name>dfs.block.size</name>
    <value>塊大小 以字節爲單位</value>
</property>

在這裏插入圖片描述

5.2 機架感知

HDFS分佈式文件系統的內部有一個副本存放策略:以默認的副本數=3爲例:

1、第一個副本塊存本機

2、第二個副本塊存跟本機同機架內的其他服務器節點

3、第三個副本塊存不同機架的一個服務器節點上
在這裏插入圖片描述

HDFS命令行

ls

格式 作用
hdfs dfs -ls URI 類似於Linux的ls命令,顯示文件列表
[root@node01 test]# hdfs dfs -ls /
Found 1 items
drwxrwx---   - root supergroup          0 2020-06-26 08:57 /tmp
[root@node01 test]# 

lsr

格式 作用
hdfs dfs -lsr URI 在整個目錄下遞歸執行ls, 與UNIX中的ls-R類似
[root@node01 test]# hdfs dfs -lsr /
lsr: DEPRECATED: Please use 'ls -R' instead.
drwxrwx---   - root supergroup          0 2020-06-26 08:57 /tmp
drwxrwx---   - root supergroup          0 2020-06-26 08:57 /tmp/hadoop-yarn
drwxrwx---   - root supergroup          0 2020-06-26 08:57 /tmp/hadoop-yarn/staging
drwxrwx---   - root supergroup          0 2020-06-26 08:57 /tmp/hadoop-yarn/staging/history
drwxrwx---   - root supergroup          0 2020-06-26 08:57 /tmp/hadoop-yarn/staging/history/done
drwxrwxrwt   - root supergroup          0 2020-06-26 08:57 /tmp/hadoop-yarn/staging/history/done_intermediate
[root@node01 test]# 

mkdir

格式 作用
hdfs dfs [-p] -mkdir 以中的URI作爲參數,創建目錄。使用-p參數可以遞歸創建目錄
[root@node01 test]# hdfs dfs -mkdir -p /aaa/bbb
[root@node01 test]# 

put

格式 作用
hdfs dfs -put … 將單個的源文件src或者多個源文件srcs從本地文件系統拷貝到目標文件系統中(對應的路徑)。也可以從標準輸入中讀取輸入,寫入目標文件系統中
[root@node01 test]# hdfs dfs -put 1.txt /aaa
[root@node01 test]# 

在這裏插入圖片描述

moveFromLocal

格式 作用
hdfs dfs -moveFromLocal 和put命令類似,但是源文件localsrc拷貝之後自身被刪除
[root@node01 test]# ls
1.txt
[root@node01 test]# hdfs dfs -moveFromLocal 1.txt /aaa/bbb
[root@node01 test]# ls
[root@node01 test]#

在這裏插入圖片描述

get

格式 作用
hdfs dfs -get [-ignorecrc ] [-crc] 將文件拷貝到本地文件系統。 CRC 校驗失敗的文件通過-ignorecrc選項拷貝。 文件和CRC校驗和可以通過-CRC選項拷貝
[root@node01 test]# ls
[root@node01 test]# hdfs dfs -get /aaa/bbb/1.txt .
[root@node01 test]# ls
1.txt
[root@node01 test]# 

在這裏插入圖片描述

mv

格式 作用
hdfs dfs -mv URI 將hdfs上的文件從原路徑移動到目標路徑(移動之後文件刪除),該命令不能誇文件系統

在這裏插入圖片描述

[root@node01 test]# hdfs dfs -mv /ccc /aaa/bbb/
[root@node01 test]# 

在這裏插入圖片描述

rm

格式 作用
hdfs dfs -rm [-r] 【-skipTrash】 URI 【URI 。。。】 刪除參數指定的文件,參數可以有多個。 此命令只刪除文件和非空目錄。如果指定-skipTrash選項,那麼在回收站可用的情況下,該選項將跳過回收站而直接刪除文件;否則,在回收站可用時,在HDFS Shell 中執行此命令,會將文件暫時放到回收站中。

移除後自動放入到垃圾桶中

[root@node01 test]# hdfs dfs -rm -r /aaa
20/06/26 17:07:40 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 10080 minutes, Emptier interval = 0 minutes.
20/06/26 17:07:40 INFO fs.TrashPolicyDefault: Moved: 'hdfs://node01:8020/aaa' to trash at: hdfs://node01:8020/user/root/.Trash/Current/aaa
Moved: 'hdfs://node01:8020/aaa' to trash at: hdfs://node01:8020/user/root/.Trash/Current
[root@node01 test]# 

cp

格式 作用
hdfs dfs -cp URI [URI …] 將文件拷貝到目標路徑中。如果 爲目錄的話,可以將多個文件拷貝到該目錄下。-f 選項將覆蓋目標,如果它已經存在。-p 選項將保留文件屬性(時間戳、所有權、許可、ACL、XAttr)。
[root@node01 test]# hdfs dfs -cp /aaa /bbb
[root@node01 test]# 

在這裏插入圖片描述

cat

格式 作用
hdfs dfs -cat URI [uri …] 將參數所指示的文件內容輸出到stdout
[root@node01 test]# hdfs dfs -cat /aaa/1.txt
hello gcx!
[root@node01 test]# 

chmod

格式 作用
hdfs dfs -chmod [-R] URI[URI …] 改變文件權限。如果使用 -R 選項,則對整個目錄有效遞歸執行。使用這一命令的用戶必須是文件的所屬用戶,或者超級用戶。
[root@node01 test]# hdfs dfs -chmod 777 /aaa/1.txt
[root@node01 test]# 

在這裏插入圖片描述

chown

格式 作用
hdfs dfs -chmod [-R] URI[URI …] 改變文件的所屬用戶和用戶組。如果使用 -R 選項,則對整個目錄有效遞歸執行。使用這一命令的用戶必須是文件的所屬用戶,或者超級用戶
[root@node01 test]# hdfs dfs -chown -R root:root /aaa/
[root@node01 test]# 

在這裏插入圖片描述

appendToFile

格式 作用
hdfs dfs -appendToFile … 追加一個或者多個文件到hdfs指定文件中.也可以從命令行讀取輸入.
[root@node01 test]# cat 1.xml 
<gcx>hello</gcx>
[root@node01 test]# cat 2.xml 
<gcxzflgl>world</gcxzflgl>
[root@node01 test]# hdfs dfs -appendToFile 1.xml 2.xml /merge.xml
[root@node01 test]# hdfs dfs -cat /merge.xml
<gcx>hello</gcx>
<gcxzflgl>world</gcxzflgl>
[root@node01 test]# 

HDFS文件數量空間限制

7. 1、HDFS文件限額配置

​在多人共用HDFS的環境下,配置設置非常重要。特別是在Hadoop處理大量資料的環境,如果沒有配額管理,很容易把所有的空間用完造成別人無法存取。Hdfs的配額設定是針對目錄而不是針對賬號,可以 讓每個賬號僅操作某一個目錄,然後對目錄設置配置。

​ HDFS文件的限額配置允許我們以文件個數,或者文件大小來限制我們在某個目錄下上傳的文件數量或者文件內容總量,以便達到我們類似百度網盤網盤等限制每個用戶允許上傳的最大的文件的量。

7.1.1 文件數量限額

對文件夾bbb下查看文件數量限額查看,結果顯示無上限

[root@node01 test]# hdfs dfs -count -q -h /bbb
        none             inf            none             inf            1            0                  0 /bbb
[root@node01 test]# 

給bbb文件夾設置存放兩個文件的數量限額

[root@node01 test]# hdfs dfsadmin -setQuota 2 /bbb

#結果第二項顯示只剩下1個文件的數量(hdfs認爲文件夾bbb也是其中一項,所以只剩下一個存儲文件數量限額)
[root@node01 test]# hdfs dfs -count -q -h /bbb
           2               1            none             inf            1            0                  0 /bbb
[root@node01 test]# 

給bbb文件夾放入兩個文件

[root@node01 test]# ll
總用量 8
-rw-r--r--. 1 root root 17 626 17:17 1.xml
-rw-r--r--. 1 root root 27 626 17:17 2.xml

#放入一個文件
[root@node01 test]# hdfs dfs -put 1.xml /bbb

#文件數量限額爲空
[root@node01 test]# hdfs dfs -count -q -h /bbb
           2               0            none             inf            1            1                 17 /bbb

#再次放入一個文件,提示已經超出限額,不能再放入文件
[root@node01 test]# hdfs dfs -put 2.xml /bbb
put: The NameSpace quota (directories and files) of directory /bbb is exceeded: quota=2 file count=3
[root@node01 test]# 

#清除限額
[root@node01 test]# hdfs dfsadmin -clrQuota /bbb

#放入因限額存儲失敗的文件,發現成功存入
[root@node01 test]# hdfs dfs -put 2.xml /bbb
[root@node01 test]# 

7.1.2 文件空間限額

#給ccc文件夾放入5k空間的限額
[root@node01 test]# hdfs dfsadmin -setSpaceQuota 5k /ccc

#查看文件的大小
[root@node01 test]# clear
[root@node01 test]# du -sh 1.xml 
4.0K	1.xml
[root@node01 test]# 

#存入小於5k限額的文件
[root@node01 test]# hdfs dfs -put 1.xml /ccc

#錯誤摘要
Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.protocol.DSQuotaExceededException): The DiskSpace quota of /ccc is exceeded: quota = 5120 B = 5 KB but diskspace consumed = 402653184 B =
 384 MB

我們對ccc文件夾設置了5k的空間限額,上傳4k的文件夾提示報錯,因爲HDFS是分佈式文件存儲系統,默認進行分片存儲,每片大小是128M,所以說至少需要384M才能存入成功

我們先清除對ccc文件夾5k的空間的限額,從新設定限額爲384M


#清除空間限額
[root@node01 test]# hdfs dfsadmin -clrSpaceQuota /ccc

#設置空間大小限額384M
[root@node01 test]# hdfs dfsadmin -setSpaceQuota 384M /ccc

#上傳4K的文件,經過分片處理需要384M大小空間,剛好存入ccc文件夾
[root@node01 test]# hdfs dfs -put 1.xml /ccc
[root@node01 test]# 

附:生成任意大小的文件命令

dd if=/dev/zero of=1.txt  bs=3M count=5     #生成15M的文件

7.2、hdfs的安全模式

安全模式是hadoop的一種保護機制,用於保證集羣中的數據塊的安全性。當集羣啓動的時候,會首先進入安全模式。當系統處於安全模式時會檢查數據塊的完整性。

假設我們設置的副本數(即參數dfs.replication)是3,那麼在datanode上就應該有3個副本存在,假設只存在2個副本,那麼比例就是2/3=0.666。hdfs默認的副本率0.999。我們的副本率0.666明顯小於0.999,因此係統會自動的複製副本到其他dataNode,使得副本率不小於0.999。如果系統中有5個副本,超過我們設定的3個副本,那麼系統也會刪除多於的2個副本。

在安全模式狀態下,文件系統只接受讀數據請求,而不接受刪除、修改等變更請求。在,當整個系統達到安全標準時,HDFS自動離開安全模式。

hdfs  dfsadmin  -safemode  get #查看安全模式狀態
hdfs  dfsadmin  -safemode  enter #進入安全模式
hdfs  dfsadmin  -safemode  leave #離開安全模式

我們模擬下,服務異常處於安全模式狀態情況下,對文件的讀寫

#開啓安全模式
[root@node01 test]# hdfs  dfsadmin  -safemode  enter
Safe mode is ON

#安全模式下刪除文件。報錯信息提示安全模式下,禁止操作,需要非安全模式下在操作
[root@node01 test]# hdfs dfs -rm -r /ccc
20/06/26 17:45:07 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 10080 minutes, Emptier interval = 0 minutes.
20/06/26 17:45:07 WARN fs.TrashPolicyDefault: Can't create trash directory: hdfs://node01:8020/user/root/.Trash/Current
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.server.namenode.SafeModeException): Cannot create directory /user/root/.Trash/Current. Name node is in safe mode.
It was turned on manually. Use "hdfs dfsadmin -safemode leave" to turn safe mode off.
	at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkNameNodeSafeMode(FSNamesystem.java:1335)
	at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.mkdirs(FSNamesystem.java:3866)
	at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.mkdirs(NameNodeRpcServer.java:984)
	at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.mkdirs(ClientNamenodeProtocolServerSideTranslatorPB.java:634)
	at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
	at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616)
	at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:982)
	at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2217)
	at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2213)
	at java.security.AccessController.doPrivileged(Native Method)
	at javax.security.auth.Subject.doAs(Subject.java:422)
	at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1754)
	at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2211)

	at org.apache.hadoop.ipc.Client.call(Client.java:1476)
	at org.apache.hadoop.ipc.Client.call(Client.java:1413)
	at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:229)
	at com.sun.proxy.$Proxy10.mkdirs(Unknown Source)
	at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.mkdirs(ClientNamenodeProtocolTranslatorPB.java:563)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:191)
	at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:102)
	at com.sun.proxy.$Proxy11.mkdirs(Unknown Source)
	at org.apache.hadoop.hdfs.DFSClient.primitiveMkdir(DFSClient.java:3014)
	at org.apache.hadoop.hdfs.DFSClient.mkdirs(DFSClient.java:2984)
	at org.apache.hadoop.hdfs.DistributedFileSystem$21.doCall(DistributedFileSystem.java:1047)
	at org.apache.hadoop.hdfs.DistributedFileSystem$21.doCall(DistributedFileSystem.java:1043)
	at org.apache.hadoop.fs.FileSystemLinkResolver.resolve(FileSystemLinkResolver.java:81)
	at org.apache.hadoop.hdfs.DistributedFileSystem.mkdirsInternal(DistributedFileSystem.java:1043)
	at org.apache.hadoop.hdfs.DistributedFileSystem.mkdirs(DistributedFileSystem.java:1036)
	at org.apache.hadoop.fs.TrashPolicyDefault.moveToTrash(TrashPolicyDefault.java:137)
	at org.apache.hadoop.fs.Trash.moveToTrash(Trash.java:114)
	at org.apache.hadoop.fs.Trash.moveToAppropriateTrash(Trash.java:95)
	at org.apache.hadoop.fs.shell.Delete$Rm.moveToTrash(Delete.java:117)
	at org.apache.hadoop.fs.shell.Delete$Rm.processPath(Delete.java:104)
	at org.apache.hadoop.fs.shell.Command.processPaths(Command.java:317)
	at org.apache.hadoop.fs.shell.Command.processPathArgument(Command.java:289)
	at org.apache.hadoop.fs.shell.Command.processArgument(Command.java:271)
	at org.apache.hadoop.fs.shell.Command.processArguments(Command.java:255)
	at org.apache.hadoop.fs.shell.Command.processRawArguments(Command.java:201)
	at org.apache.hadoop.fs.shell.Command.run(Command.java:165)
	at org.apache.hadoop.fs.FsShell.run(FsShell.java:287)
	at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
	at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:84)
	at org.apache.hadoop.fs.FsShell.main(FsShell.java:340)
rm: Failed to move to trash: hdfs://node01:8020/ccc: Cannot create directory /user/root/.Trash/Current. Name node is in safe mode.


#退出安全模式
[root@node01 test]# hdfs  dfsadmin  -safemode  leave
Safe mode is OFF

#刪除文件成功
[root@node01 test]# hdfs dfs -rm -r /ccc
20/06/26 17:45:26 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 10080 minutes, Emptier interval = 0 minutes.
20/06/26 17:45:26 INFO fs.TrashPolicyDefault: Moved: 'hdfs://node01:8020/ccc' to trash at: hdfs://node01:8020/user/root/.Trash/Current/ccc
Moved: 'hdfs://node01:8020/ccc' to trash at: hdfs://node01:8020/user/root/.Trash/Current
[root@node01 test]# 

HDFS基準測試

實際生產環境當中,hadoop的環境搭建完成之後,第一件事情就是進行壓力測試,測試我們的集羣的讀取和寫入速度,測試我們的網絡帶寬是否足夠等一些基準測試

8.1 測試寫入速度

向HDFS文件系統中寫入數據,10個文件,每個文件10MB,文件存放到/benchmarks/TestDFSIO中

hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar  TestDFSIO -write -nrFiles 10  -fileSize 10MB

完成之後查看寫入速度結果

hdfs dfs -text  /benchmarks/TestDFSIO/io_write/part-00000


#也可以查看本地運行結果(機器硬件性能有關)
[root@node01 test]# cat TestDFSIO_results.log 
----- TestDFSIO ----- : write
            Date & time: Fri Jun 26 17:49:52 CST 2020
        Number of files: 10
 Total MBytes processed: 100
      Throughput mb/sec: 1.56
 Average IO rate mb/sec: 1.57
  IO rate std deviation: 0.11
     Test exec time sec: 126.33
[root@node01 test]# 

8.2 測試讀取速度

測試hdfs的讀取文件性能

在HDFS文件系統中讀入10個文件,每個文件10M

hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar  TestDFSIO -read -nrFiles 10 -fileSize 10MB

查看讀取果

hdfs dfs -text /benchmarks/TestDFSIO/io_read/part-00000


#本地查看測試結果(機器硬件性能有關)
[root@node01 test]# cat TestDFSIO_results.log 
----- TestDFSIO ----- : write
            Date & time: Fri Jun 26 17:49:52 CST 2020
        Number of files: 10
 Total MBytes processed: 100
      Throughput mb/sec: 1.56
 Average IO rate mb/sec: 1.57  # 平均寫入速度1.57M每秒
  IO rate std deviation: 0.11
     Test exec time sec: 126.33 # 總共執行時間

----- TestDFSIO ----- : read
            Date & time: Fri Jun 26 17:54:02 CST 2020
        Number of files: 10
 Total MBytes processed: 100
      Throughput mb/sec: 28.7
 Average IO rate mb/sec: 50.3  # 平均讀取速度50.3M每秒
  IO rate std deviation: 71.05
     Test exec time sec: 89.49 # 總共執行時間

[root@node01 test]# 

8.3 清除測試數據

hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar   TestDFSIO -clean

HDFS寫入數據過程

在這裏插入圖片描述
文字敘述:
1.client請求上傳文件a.txt
2.namenode校驗上傳權限(上傳的文件在指定目錄下是否存在)
3.校驗通過返回client告知可以上傳
4.將待上傳的文件進行切片(默認128切分成3塊),請求上傳block1
5.namenodeg根據集羣中datanode中的block信息和機架感知,選擇可以上傳的三個主機
6.返回給client可以上傳的datanode主機列表
7.client與datanode進行pipeline 建立
8.client向datanode傳遞數據(packet單位64k)同時也傳遞給其他datanode
9.datanode將傳遞進來的文件進行緩存。存儲在本地文件中
10.datanode每次接受一個packet的數據進行進行應答
11.block2重複進行4-10過程

HDFS讀取數據過程

在這裏插入圖片描述
文字敘述:
1.client請求namenode下載a.txt
2.namenode進行權限檢查(文件切分block後分布在的主機列表)
3.優先本機尋找是否存在block,沒有按照一定的策略讀取datanode主機
4.和選出的datanode進行並行的pipeline連接
5.並行讀取數據(packet:64k)
6.將讀取的數據進行合併成一個大文件,返回給client

HDFS 的元數據輔助管理

當 Hadoop 的集羣當中, NameNode的所有元數據信息都保存在了 FsImage 與 Eidts 文件當中, 這兩個文件就記錄了所有的數據的元數據信息, 元數據信息的保存目錄配置在了 hdfs-site.xml 當中

<property>
    <name>dfs.namenode.name.dir</name>    
    <value>
        file:///export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas,          	        		file:///export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas2
    </value>
</property>
<property>
     <name>dfs.namenode.edits.dir</name>
     <value>file:///export/servers/hadoop-2.7.5/hadoopDatas/nn/edits</value
</property>>

11.1 FsImage 和 Edits 詳解

  • edits
    • edits 存放了客戶端最近一段時間的操作日誌
    • 客戶端對 HDFS 進行寫文件時會首先被記錄在 edits 文件中
    • edits 修改時元數據也會更新
  • fsimage
    • NameNode 中關於元數據的鏡像, 一般稱爲檢查點, fsimage 存放了一份比較完整的元數據信息
    • 因爲 fsimage 是 NameNode 的完整的鏡像, 如果每次都加載到內存生成樹狀拓撲結構,這是非常耗內存和CPU, 所以一般開始時對 NameNode 的操作都放在 edits 中
    • fsimage 內容包含了 NameNode 管理下的所有 DataNode 文件及文件 block 及 block 所在的 DataNode 的元數據信息.
    • 隨着 edits 內容增大, 就需要在一定時間點和 fsimage 合併

11.2 fsimage 中的文件信息查看

使用命令 hdfs oiv

cd /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas/current
hdfs oiv -i fsimage_0000000000000000864 -p XML -o hello.xml

11.3. edits 中的文件信息查看

使用命令 hdfs oev

cd /export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas/current
hdfs oev -i  edits_0000000000000000865-0000000000000000866 -p XML -o myedit.xml 

11.4 SecondaryNameNode 如何輔助管理 fsimage 與 edits 文件?

  • SecondaryNameNode 定期合併 fsimage 和 edits, 把 edits 控制在一個範圍內

  • 配置 SecondaryNameNode

    • SecondaryNameNode 在 conf/masters 中指定

    • 在 masters 指定的機器上, 修改 hdfs-site.xml

      <property>
        <name>dfs.http.address</name>
        <value>host:50070</value>
      </property>
      
    • 修改 core-site.xml, 這一步不做配置保持默認也可以

      <!-- 多久記錄一次 HDFS 鏡像, 默認 1小時 -->
      <property>
        <name>fs.checkpoint.period</name>
        <value>3600</value>
      </property>
      <!-- 一次記錄多大, 默認 64M -->
      <property>
        <name>fs.checkpoint.size</name>
        <value>67108864</value>
      </property>
      

在這裏插入圖片描述

  1. SecondaryNameNode 通知 NameNode 切換 editlog
  2. SecondaryNameNode 從 NameNode 中獲得 fsimage 和 editlog(通過http方式)
  3. SecondaryNameNode 將 fsimage 載入內存, 然後開始合併 editlog, 合併之後成爲新的 fsimage
  4. SecondaryNameNode 將新的 fsimage 發回給 NameNode
  5. NameNode 用新的 fsimage 替換舊的 fsimage
特點
  • 完成合並的是 SecondaryNameNode, 會請求 NameNode 停止使用 edits, 暫時將新寫操作放入一個新的文件中 edits.new
  • SecondaryNameNode 從 NameNode 中通過 Http GET 獲得 edits, 因爲要和 fsimage 合併, 所以也是通過 Http Get 的方式把 fsimage 加載到內存, 然後逐一執行具體對文件系統的操作, 與 fsimage 合併, 生成新的 fsimage, 然後通過 Http POST 的方式把 fsimage 發送給 NameNode. NameNode 從 SecondaryNameNode 獲得了 fsimage 後會把原有的 fsimage 替換爲新的 fsimage, 把 edits.new 變成 edits. 同時會更新 fstime
  • Hadoop 進入安全模式時需要管理員使用 dfsadmin 的 save namespace 來創建新的檢查點
  • SecondaryNameNode 在合併 edits 和 fsimage 時需要消耗的內存和 NameNode 差不多, 所以一般把 NameNode 和 SecondaryNameNode 放在不同的機器上

HDFS Java客戶端

12.HDFS 的 API 操作

12.1 配置Windows下Hadoop環境

Hadoop linux編譯後windows運行版本下載鏈接:鏈接:https://pan.baidu.com/s/1qMtCSBQYeDB-lpor4fadCQ
提取碼:4epc

在windows系統需要配置hadoop運行環境,否則直接運行代碼會出現以下問題:

缺少winutils.exe

Could not locate executable null \bin\winutils.exe in the hadoop binaries 

缺少hadoop.dll

Unable to load native-hadoop library for your platform… using builtin-Java classes where applicable  

步驟:

第一步:將hadoop2.7.5文件夾拷貝到一個沒有中文沒有空格的路徑下面

第二步:在windows上面配置hadoop的環境變量: HADOOP_HOME,並將%HADOOP_HOME%\bin添加到path中

第三步:把hadoop2.7.5文件夾中bin目錄下的hadoop.dll文件放到系統盤: C:\Windows\System32 目錄

第四步:關閉windows重啓

12.2 導入 Maven 依賴

<dependencies>
      	<dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.5</version>
	    </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.7.5</version>
		</dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.7.5</version>
		</dependency>
		<dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-core</artifactId>
            <version>2.7.5</version>
		</dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                    <!--    <verbal>true</verbal>-->
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <minimizeJar>true</minimizeJar>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

12.3 使用文件系統方式訪問數據

12.3.1 涉及的主要類

在 Java 中操作 HDFS, 主要涉及以下 Class:

  • Configuration

    • 該類的對象封轉了客戶端或者服務器的配置
  • FileSystem

    • 該類的對象是一個文件系統對象, 可以用該對象的一些方法來對文件進行操作, 通過 FileSystem 的靜態方法 get 獲得該對象

      FileSystem fs = FileSystem.get(conf)
      
      • get 方法從 conf 中的一個參數 fs.defaultFS 的配置值判斷具體是什麼類型的文件系統
      • 如果我們的代碼中沒有指定 fs.defaultFS, 並且工程 ClassPath 下也沒有給定相應的配置, conf 中的默認值就來自於 Hadoop 的 Jar 包中的 core-default.xml
      • 默認值爲 file:/// , 則獲取的不是一個 DistributedFileSystem 的實例, 而是一個本地文件系統的客戶端對象

12.3.2 獲取 FileSystem 的幾種方式

  • 第一種方式
@Test
public void getFileSystem1() throws IOException {
    Configuration configuration = new Configuration();
    //指定我們使用的文件系統類型:
    configuration.set("fs.defaultFS", "hdfs://node01:8020/");

    //獲取指定的文件系統
    FileSystem fileSystem = FileSystem.get(configuration);
    System.out.println(fileSystem.toString());

}
  • 第二種方式
@Test
public void getFileSystem2() throws  Exception{
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new       Configuration());
    System.out.println("fileSystem:"+fileSystem);
}
  • 第三種方式
@Test
public void getFileSystem3() throws  Exception{
    Configuration configuration = new Configuration();
    configuration.set("fs.defaultFS", "hdfs://node01:8020");
    FileSystem fileSystem = FileSystem.newInstance(configuration);
    System.out.println(fileSystem.toString());
}
  • 第四種方式
//@Test
public void getFileSystem4() throws  Exception{
    FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://node01:8020") ,new Configuration());
    System.out.println(fileSystem.toString());
}

12.3.3 遍歷 HDFS 中所有文件

  • 使用 API 遍歷
@Test
public void listMyFiles()throws Exception{
    //獲取fileSystem類
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
    //獲取RemoteIterator 得到所有的文件或者文件夾,第一個參數指定遍歷的路徑,第二個參數表示是否要遞歸遍歷
    RemoteIterator<LocatedFileStatus> locatedFileStatusRemoteIterator = fileSystem.listFiles(new Path("/"), true);
    while (locatedFileStatusRemoteIterator.hasNext()){
        LocatedFileStatus next = locatedFileStatusRemoteIterator.next();
        System.out.println(next.getPath().toString());
    }
    fileSystem.close();
}

12.3.4 HDFS 上創建文件夾

@Test
public void mkdirs() throws  Exception{
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
    boolean mkdirs = fileSystem.mkdirs(new Path("/hello/mydir/test"));
    fileSystem.close();
}

12.3.5 下載文件

@Test
public void getFileToLocal()throws  Exception{
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
    FSDataInputStream inputStream = fileSystem.open(new Path("/timer.txt"));
    FileOutputStream  outputStream = new FileOutputStream(new File("e:\\timer.txt"));
    IOUtils.copy(inputStream,outputStream );
    IOUtils.closeQuietly(inputStream);
    IOUtils.closeQuietly(outputStream);
    fileSystem.close();
}

12.3.6 HDFS 文件上傳

@Test
public void putData() throws  Exception{
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
    fileSystem.copyFromLocalFile(new Path("file:///c:\\install.log"),new Path("/hello/mydir/test"));
    fileSystem.close();
}

12.3.7 小文件合併

由於 Hadoop 擅長存儲大文件,因爲大文件的元數據信息比較少,如果 Hadoop 集羣當中有大量的小文件,那麼每個小文件都需要維護一份元數據信息,會大大的增加集羣管理元數據的內存壓力,所以在實際工作當中,如果有必要一定要將小文件合併成大文件進行一起處理

在我們的 HDFS 的 Shell 命令模式下,可以通過命令行將很多的 hdfs 文件合併成一個大文件下載到本地

cd /export/servers
hdfs dfs -getmerge /*.txt ./hello.txt

既然可以在下載的時候將這些小文件合併成一個大文件一起下載,那麼肯定就可以在上傳的時候將小文件合併到一個大文件裏面去
在這裏插入圖片描述

@Test
public void mergeFile() throws  Exception{
    //獲取分佈式文件系統
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration(),"root");
    FSDataOutputStream outputStream = fileSystem.create(new Path("/bigfile.txt"));
    //獲取本地文件系統
    LocalFileSystem local = FileSystem.getLocal(new Configuration());
    //通過本地文件系統獲取文件列表,爲一個集合
    FileStatus[] fileStatuses = local.listStatus(new Path("file:///E:\\input"));
    for (FileStatus fileStatus : fileStatuses) {
        FSDataInputStream inputStream = local.open(fileStatus.getPath());
       IOUtils.copy(inputStream,outputStream);
        IOUtils.closeQuietly(inputStream);
    }
    IOUtils.closeQuietly(outputStream);
    local.close();
    fileSystem.close();
}

HDFS高可用機制

13.1 HDFS高可用介紹

在Hadoop 中,NameNode 所處的位置是非常重要的,整個HDFS文件系統的元數據信息都由NameNode 來管理,NameNode的可用性直接決定了Hadoop 的可用性,一旦NameNode進程不能工作了,就會影響整個集羣的正常使用。

在典型的HA集羣中,兩臺獨立的機器被配置爲NameNode。在工作集羣中,NameNode機器中的一個處於Active狀態,另一個處於Standby狀態。Active NameNode負責羣集中的所有客戶端操作,而Standby充當從服務器。Standby機器保持足夠的狀態以提供快速故障切換。
在這裏插入圖片描述

13.2 組件介紹

ZKFailoverController

是基於Zookeeper的故障轉移控制器,它負責控制NameNode的主備切換,ZKFailoverController會監測NameNode的健康狀態,當發現Active NameNode出現異常時會通過Zookeeper進行一次新的選舉,完成Active和Standby狀態的切換

HealthMonitor

週期性調用NameNode的HAServiceProtocol RPC接口(monitorHealth 和 getServiceStatus),監控NameNode的健康狀態並向ZKFailoverController反饋

ActiveStandbyElector

接收ZKFC的選舉請求,通過Zookeeper自動完成主備選舉,選舉完成後回調ZKFailoverController的主備切換方法對NameNode進行Active和Standby狀態的切換.

DataNode

NameNode包含了HDFS的元數據信息和數據塊信息(blockmap),其中數據塊信息通過DataNode主動向Active NameNode和Standby NameNode上報

共享存儲系統

共享存儲系統負責存儲HDFS的元數據(EditsLog),Active NameNode(寫入)和 Standby NameNode(讀取)通過共享存儲系統實現元數據同步,在主備切換過程中,新的Active NameNode必須確保元數據同步完成才能對外提供服務

高可用架構圖:
在這裏插入圖片描述
HA namenode切換簡易文字敘述:
通過zk監聽namenode的狀態,一旦掉線通過HealthMonitor上報ZKFailoverController,ActiveStandbyElector上報給zookeeper,zookeeper進行投票選舉,選舉出新的namenode,同時也告知崩潰的namenode狀態切換成standby。

高可用集羣搭建文檔:
鏈接:https://pan.baidu.com/s/1pcMYSu-yMWjVGPhacF4PnA
提取碼:ivqr

HDFS聯邦機制

##3: Hadoop的聯邦機制(Federation)

14.1背景概述

單NameNode的架構使得HDFS在集羣擴展性和性能上都有潛在的問題,當集羣大到一定程度後,NameNode進程使用的內存可能會達到上百G,NameNode成爲了性能的瓶頸。因而提出了namenode水平擴展方案-- Federation。

Federation中文意思爲聯邦,聯盟,是NameNode的Federation,也就是會有多個NameNode。多個NameNode的情況意味着有多個namespace(命名空間),區別於HA模式下的多NameNode,它們是擁有着同一個namespace。既然說到了NameNode的命名空間的概念,這裏就看一下現有的HDFS數據管理架構,如下圖所示:
在這裏插入圖片描述
從上圖中,我們可以很明顯地看出現有的HDFS數據管理,數據存儲2層分層的結構.也就是說,所有關於存儲數據的信息和管理是放在NameNode這邊,而真實數據的存儲則是在各個DataNode下.而這些隸屬於同一個NameNode所管理的數據都是在同一個命名空間下的.而一個namespace對應一個block pool。Block Pool是同一個namespace下的block的集合.當然這是我們最常見的單個namespace的情況,也就是一個NameNode管理集羣中所有元數據信息的時候.如果我們遇到了之前提到的NameNode內存使用過高的問題,這時候怎麼辦?元數據空間依然還是在不斷增大,一味調高NameNode的jvm大小絕對不是一個持久的辦法.這時候就誕生了HDFS Federation的機制.

14.2 Federation架構設計

HDFS Federation是解決namenode內存瓶頸問題的水平橫向擴展方案。

Federation意味着在集羣中將會有多個namenode/namespace。這些namenode之間是聯合的,也就是說,他們之間相互獨立且不需要互相協調,各自分工,管理自己的區域。分佈式的datanode被用作通用的數據塊存儲存儲設備。每個datanode要向集羣中所有的namenode註冊,且週期性地向所有namenode發送心跳和塊報告,並執行來自所有namenode的命令。

在這裏插入圖片描述

Federation一個典型的例子就是上面提到的NameNode內存過高問題,我們完全可以將上面部分大的文件目錄移到另外一個NameNode上做管理.更重要的一點在於,這些NameNode是共享集羣中所有的DataNode的,它們還是在同一個集羣內的**。**

這時候在DataNode上就不僅僅存儲一個Block Pool下的數據了,而是多個(在DataNode的datadir所在目錄裏面查看BP-xx.xx.xx.xx打頭的目錄)。

概括起來:

多個NN共用一個集羣裏的存儲資源,每個NN都可以單獨對外提供服務。

每個NN都會定義一個存儲池,有單獨的id,每個DN都爲所有存儲池提供存儲。

DN會按照存儲池id向其對應的NN彙報塊信息,同時,DN會向所有NN彙報本地存儲可用資源情況。

HDFS Federation不足

HDFS Federation並沒有完全解決單點故障問題。雖然namenode/namespace存在多個,但是從單個namenode/namespace看,仍然存在單點故障:如果某個namenode掛掉了,其管理的相應的文件便不可以訪問。Federation中每個namenode仍然像之前HDFS上實現一樣,配有一個secondary namenode,以便主namenode掛掉一下,用於還原元數據信息。

所以一般集羣規模真的很大的時候,會採用HA+Federation的部署方案。也就是每個聯合的namenodes都是ha的。

至此,HDFS核心內容講解完畢!

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