1 HDFS 組成架構(gòu)
- NameNode(NN)
- 管理HDFS的名稱空間
- 配置副本策略
- 管理數(shù)據(jù)塊(Block)映射信息
- 處理客戶端讀寫請求
- DataNode(DN)
- 存儲實際的數(shù)據(jù)塊
- 執(zhí)行數(shù)據(jù)塊的讀寫操作
- Client(客戶端)
- 文件切分,文件上傳HDFS時秩仆,Client將文件切分成一個個Block瘦穆,然后進行上傳
- 與NameNode交互,獲取文件的位置信息
- 與DataNode交互珊蟀,讀取或者寫入數(shù)據(jù)
- Client提供一些命令管理HDFS,比如NameNode格式化
- Client可以通過一些命令訪問HDFS,比如對HDFS增刪改查操作
- Secondary NameNode(2NN)
- 輔助NameNode难捌,分擔工作量拴还,定期合并Fsimage 和 Edits 文件跨晴,并推送給NameNode
- 緊急情況下,可以輔助恢復 NameNode
2 HDFS 文件塊大小
HDFS中的文件在物理上時分塊存儲(Block)片林,塊的大小可通過參數(shù)(dfs.blocksize)配置端盆,默認Hadoop3.x版本中為128MB怀骤。
-
計算由來:
- 如果尋址時間為10ms,即查找到目標block的時間為10ms焕妙。
- 尋址時間為傳輸時間的1%時蒋伦,為最佳狀態(tài)。因此焚鹊,傳輸時間約為 10ms/0.01 = 1000ms = 1s
- 目前磁盤的傳輸速率為100MB/s
- 所以痕届,Block的大小 = 1s * 100MB/s = 100MB 約等于 128MB
-
塊不能太大也不能太小的原因
- HDFS塊設(shè)置太小,會增加尋址時間末患,程序的運行耽誤在尋找塊開始位置
- HDFS塊設(shè)置太大研叫,從磁盤傳輸數(shù)據(jù)的時間會明顯大于定位塊開始位置所需時間,導致程序處理塊數(shù)據(jù)時璧针,非常慢
結(jié)論
HDFS塊的大小設(shè)置主要取決于磁盤傳輸速率嚷炉。
3 HDFS Shell操作
hadoop fs 具體命令
or
hdfs dfs 具體命令
Usage: hadoop fs [generic options]
# 追加一個文件到已經(jīng)存在的文件末尾
[-appendToFile <localsrc> ... <dst>]
# 顯示文件內(nèi)容
[-cat [-ignoreCrc] <src> ...]
[-checksum <src> ...]
# Linux文件系統(tǒng)中的用法一樣,修改文件所屬權(quán)限
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
# 從本地文件系統(tǒng)中拷貝文件到HDFS路徑去
[-copyFromLocal [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
# 從HDFS拷貝到本地
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] [-e] <path> ...]
# 從HDFS的一個路徑拷貝到HDFS的另一個路徑
[-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
# 統(tǒng)計文件夾的大小信息
[-du [-s] [-h] [-v] [-x] <path> ...]
[-expunge [-immediate]]
[-find <path> ... <expression> ...]
# 等同于copyToLocal探橱,生產(chǎn)環(huán)境更習慣用get
[-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> ...]]
# 創(chuàng)建路徑
[-mkdir [-p] <path> ...]
# 從本地剪切粘貼到HDFS
[-moveFromLocal <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
# 在HDFS目錄中移動文件
[-mv <src> ... <dst>]
# 等同于copyFromLocal申屹,生產(chǎn)環(huán)境更習慣用put
[-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>]
# 設(shè)置HDFS中文件的副本數(shù)量
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
# 顯示一個文件的末尾1kb的數(shù)據(jù)
[-tail [-f] [-s <sleep interval>] <file>]
[-test -[defsz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touch [-a] [-m] [-t TIMESTAMP ] [-c] <path> ...]
[-touchz <path> ...]
[-truncate [-w] <length> <path> ...]
[-usage [cmd ...]]
4 HDFS API 操作
- Pom.xml
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
- log4j.properties
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
- 測試類
public class TestHDFS {
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
FileSystem fs = FileSystem.get(new URI("hdfs://47.93.223.3:9000"), new Configuration(), "root");
fs.mkdirs(new Path("/user/admin"));
fs.close();
}
}
5 HDFS 的流程機制
5.1 HDFS 的寫流程
- 客戶端通過Distributed FileSystem模塊向NameNode請求上傳文件,NameNode檢查目標文件是否已存在隧膏,父目錄是否存在哗讥。
- NameNode返回是否可以上傳。
- 客戶端請求第一個 Block上傳到哪幾個DataNode服務(wù)器上私植。
- NameNode返回3個DataNode節(jié)點忌栅,分別為dn1、dn2曲稼、dn3索绪。
- 客戶端通過FSDataOutputStream模塊請求dn1上傳數(shù)據(jù),dn1收到請求會繼續(xù)調(diào)用dn2贫悄,然后dn2調(diào)用dn3瑞驱,將這個通信管道建立完成。
- dn1窄坦、dn2唤反、dn3逐級應(yīng)答客戶端。
- 客戶端開始往dn1上傳第一個Block(先從磁盤讀取數(shù)據(jù)放到一個本地內(nèi)存緩存)鸭津,以Packet為單位彤侍,dn1收到一個Packet就會傳給dn2,dn2傳給dn3逆趋;dn1每傳一個packet會放入一個應(yīng)答隊列等待應(yīng)答盏阶。
- 當一個Block傳輸完成之后,客戶端再次請求NameNode上傳第二個Block的服務(wù)器闻书。(重復執(zhí)行3-7步)名斟。
5.2 HDFS 的讀流程
客戶端通過DistributedFileSystem向NameNode請求下載文件脑慧,NameNode通過查詢元數(shù)據(jù),找到文件塊所在的DataNode地址砰盐。
挑選一臺DataNode(就近原則闷袒,然后隨機)服務(wù)器,請求讀取數(shù)據(jù)岩梳。
DataNode開始傳輸數(shù)據(jù)給客戶端(從磁盤里面讀取數(shù)據(jù)輸入流囊骤,以Packet為單位來做校驗)。
客戶端以Packet為單位接收冀值,先在本地緩存淘捡,然后寫入目標文件。
5.3 NN 與 2NN 工作機制
1)第一階段:NameNode啟動
第一次啟動NameNode格式化后池摧,創(chuàng)建Fsimage和Edits文件姜性。如果不是第一次啟動篮灼,直接加載編輯日志和鏡像文件到內(nèi)存哺哼。
客戶端對元數(shù)據(jù)進行增刪改的請求晾蜘。
NameNode記錄操作日志芯咧,更新滾動日志玛荞。
NameNode在內(nèi)存中對元數(shù)據(jù)進行增刪改支子。
2)第二階段:Secondary NameNode工作
Secondary NameNode詢問NameNode是否需要CheckPoint蛮浑。直接帶回NameNode是否檢查結(jié)果浙踢。
Secondary NameNode請求執(zhí)行CheckPoint绢慢。
NameNode滾動正在寫的Edits日志。
將滾動前的編輯日志和鏡像文件拷貝到Secondary NameNode洛波。
Secondary NameNode加載編輯日志和鏡像文件到內(nèi)存胰舆,并合并。
生成新的鏡像文件fsimage.chkpoint蹬挤。
拷貝fsimage.chkpoint到NameNode缚窿。
NameNode將fsimage.chkpoint重新命名成fsimage。
5.4 DataNode 工作機制
一個數(shù)據(jù)塊在DataNode上以文件形式存儲在磁盤上焰扳,包括兩個文件倦零,一個是數(shù)據(jù)本身,一個是元數(shù)據(jù)包括數(shù)據(jù)塊的長度吨悍,塊數(shù)據(jù)的校驗和扫茅,以及時間戳。
DataNode啟動后向NameNode注冊育瓜,通過后葫隙,周期性(6小時)的向NameNode上報所有的塊信息。
- DN向NN匯報當前解讀信息的時間間隔爆雹,默認6小時停蕉;
<property>
<name>dfs.blockreport.intervalMsec</name>
<value>21600000</value>
<description>Determines block reporting interval in milliseconds.</description>
</property>
- DN掃描自己節(jié)點塊信息列表的時間愕鼓,默認6小時
<property>
<name>dfs.datanode.directoryscan.interval</name>
<value>21600s</value>
<description>Interval in seconds for Datanode to scan data directories and reconcile the difference between blocks in memory and on the disk.
Support multiple time unit suffix(case insensitive), as described in dfs.heartbeat.interval.
</description>
</property>
心跳是每3秒一次,心跳返回結(jié)果帶有NameNode給該DataNode的命令如復制塊數(shù)據(jù)到另一臺機器慧起,或刪除某個數(shù)據(jù)塊菇晃。如果超過10分鐘沒有收到某個DataNode的心跳,則認為該節(jié)點不可用蚓挤。
集群運行中可以安全加入和退出一些機器磺送。