這是一篇最通熟易懂的Hadoop HDFS實(shí)踐攻略!
本文主要幫您解決一下幾個(gè)問(wèn)題:
- HDFS是用來(lái)解決什么問(wèn)題?怎么解決的?
- 如何在命令行下操作HDFS?
- 如何使用Java API來(lái)操作HDFS?
- 在了解基本思路和操作方法后,進(jìn)一步深究HDFS具體的讀寫(xiě)數(shù)據(jù)流程
學(xué)習(xí)并實(shí)踐本文教程后,可以對(duì)HDFS有比較清晰的認(rèn)識(shí),并可以進(jìn)行熟練操作,為后續(xù)學(xué)習(xí)Hadoop體系打好基礎(chǔ)。
目錄:
理論部分
- HDFS 基本原理
- 文件讀取、寫(xiě)入機(jī)制
- 元數(shù)據(jù)管理思路
實(shí)踐部分
- 安裝實(shí)踐環(huán)境
- Shell 命令行操作方式
- Java API操作方式
一、HDFS基本原理
HDFS(Hadoop Distribute File System)是一個(gè)分布式文件系統(tǒng),是Hadoop的重要成員。
1、文件系統(tǒng)的問(wèn)題
文件系統(tǒng)是操作系統(tǒng)提供的磁盤(pán)空間管理服務(wù),只需要我們制定把文件放到哪兒,從哪個(gè)路徑讀取文件就可以了,不用關(guān)心文件在磁盤(pán)上是如何存放的。
當(dāng)文件所需空間大于本機(jī)磁盤(pán)空間時(shí),如何處理呢?
一是加磁盤(pán),但是加到一定程度就有限制了;二是加機(jī)器,用遠(yuǎn)程共享目錄的方式提供網(wǎng)絡(luò)化的存儲(chǔ),這種方式可以理解為分布式文件系統(tǒng)的雛形,可以把不同文件放入不同的機(jī)器中,空間不足了可繼續(xù)加機(jī)器,突破了存儲(chǔ)空間的限制。但這個(gè)方式有多個(gè)問(wèn)題:
- 單機(jī)負(fù)載可能極高例如某個(gè)文件是熱門(mén),很多用戶經(jīng)常讀取這個(gè)文件,就使得次文件所在機(jī)器的訪問(wèn)壓力極高。
- 數(shù)據(jù)不安全如果某個(gè)文件所在的機(jī)器出現(xiàn)故障,這個(gè)文件就不能訪問(wèn)了,可靠性很差。
- 文件整理困難例如想把一些文件的存儲(chǔ)位置進(jìn)行調(diào)整,就需要看目標(biāo)機(jī)器的空間是否夠用,并且需要自己維護(hù)文件位置,如果機(jī)器非常多,操作就極為復(fù)雜。
2、HDFS的解決思路
HDFS是個(gè)抽象層,底層依賴(lài)很多獨(dú)立的服務(wù)器,對(duì)外提供統(tǒng)一的文件管理功能,對(duì)于用戶來(lái)講,感覺(jué)就像在操作一臺(tái)機(jī)器,感受不到HDFS下面的多臺(tái)服務(wù)器。
例如用戶訪問(wèn)HDFS中的/a/b/c.mpg這個(gè)文件,HDFS負(fù)責(zé)從底層相應(yīng)服務(wù)器中讀取,然后返回給用戶,這樣用戶只需和HDFS打交道,不關(guān)心這個(gè)文件是怎么存儲(chǔ)的。
例如用戶需要保存一個(gè)文件/a/b/xxx.avi。
HDFS首先會(huì)把這個(gè)文件進(jìn)行分割,例如分為4塊,然后分別放到不同服務(wù)器上。
這樣做有個(gè)好處,不怕文件太大,并且讀文件的壓力不會(huì)全部集中在一臺(tái)服務(wù)器上。但如果某臺(tái)服務(wù)器壞了,文件就讀不全了。
HDFS為保證文件可靠性,會(huì)把每個(gè)文件塊進(jìn)行多個(gè)備份:
塊1:A B C
塊2:A B D
塊3:B C D
塊4:A C D
這樣文件的可靠性就大大增強(qiáng)了,即使某個(gè)服務(wù)器壞了,也可以完整讀取文件。
同時(shí)還帶來(lái)一個(gè)很大的好處,就是增加了文件的并發(fā)訪問(wèn)能力,比如多個(gè)用戶讀取這個(gè)文件時(shí),都要讀塊1,HDFS可以根據(jù)服務(wù)器的繁忙程度,選擇從那臺(tái)服務(wù)器讀塊1。
3、元數(shù)據(jù)的管理
HDFS中存了哪些文件?
文件被分成了哪些塊?
每個(gè)塊被放在哪臺(tái)服務(wù)器上?
……
這些都叫做元數(shù)據(jù),這些元數(shù)據(jù)被抽象為一個(gè)目錄樹(shù),記錄了這些復(fù)雜的對(duì)應(yīng)關(guān)系。這些元數(shù)據(jù)由一個(gè)單獨(dú)的模塊進(jìn)行管理,這個(gè)模塊叫做NameNode。存放文件塊的真實(shí)服務(wù)器叫做DataNode,所以用戶訪問(wèn)HDFS的過(guò)程可以理解為:
用戶-> HDFS -> NameNode -> DataNode
4、HDFS優(yōu)點(diǎn)
容量可以線性擴(kuò)展
有副本機(jī)制,存儲(chǔ)可靠性高,吞吐量增大
有了NameNode后,用戶訪問(wèn)文件只需指定HDFS上的路徑
二、HDFS實(shí)踐
經(jīng)過(guò)上面介紹,可以對(duì)HDFS有個(gè)基本的了解,下面開(kāi)始進(jìn)行實(shí)際操作,在實(shí)踐中更好的認(rèn)識(shí)HDFS。
1、安裝實(shí)踐環(huán)境
您可以選擇自己搭建環(huán)境,也可以使用打包好的Hadoop環(huán)境(版本2.7.3)
這個(gè)Hadoop環(huán)境實(shí)際上是一個(gè)虛機(jī)鏡像,所以需要安裝virtualbox虛擬機(jī)、vagrant鏡像管理工具,和我的Hadoop鏡像,然后用這個(gè)鏡像啟動(dòng)虛機(jī)就可以了,下面是具體操作步驟:
1)安裝virtualbox
下載地址:https://www.virtualbox.org/wiki/Downloads
2)安裝vagrant
因?yàn)楣倬W(wǎng)下載較慢,我上傳到了云盤(pán)
Windows版
鏈接: https://pan.baidu.com/s/1pKKQGHl
密碼: eykr
Mac版
鏈接: https://pan.baidu.com/s/1slts9yt
密碼: aig4
安裝完成后,在命令行終端下就可以使用vagrant命令。
3)下載Hadoop鏡像
鏈接: https://pan.baidu.com/s/1bpaisnd
密碼: pn6c
4)啟動(dòng)
加載Hadoop鏡像
vagrant box add {自定義鏡像名稱(chēng)} {鏡像所在路徑}
例如您想命名為Hadoop,鏡像下載后的路徑為d:\hadoop.box,加載命令就是這樣:
vagrant box add hadoop d:\hadoop.box
創(chuàng)建工作目錄,例如d:\hdfstest。
進(jìn)入此目錄,初始化
- cd d:\hdfstest
- vagrant init hadoop
啟動(dòng)虛機(jī)
- vagrant up
啟動(dòng)完成后,就可以使用SSH客戶端登錄虛機(jī)了
IP 127.0.0.1
端口 2222
用戶名 root
密碼 vagrant
登錄后使用命令ifconfig 查看本虛機(jī)的IP(如192.168.31.239),可以使用此IP和端口22登錄了
IP 192.168.31.239
端口 22
用戶名 root
密碼 vagrant
Hadoop服務(wù)器環(huán)境搭建完成。
2、Shell命令行操作
登錄Hadoop服務(wù)器后,先啟動(dòng)HDFS,執(zhí)行命令:
- start-dfs.sh
查看幫助
- hdfs dfs –help
顯示目錄信息
-ls 后面是要查看的目錄路徑
創(chuàng)建目錄
創(chuàng)建目錄/test
- hdfs dfs -mkdir /test
一次創(chuàng)建多級(jí)目錄/aa/bb
- hdfs dfs -mkdir -p /aa/bb
上傳文件
形式
hdfs dfs -put {本地路徑} {hdfs中的路徑}
實(shí)例(先創(chuàng)建好一個(gè)測(cè)試文件mytest.txt,內(nèi)容隨意,然后上傳到/test)
- hadoop fs -put ~/mytest.txt /test
顯示文件內(nèi)容
- hdfs dfs -cat /test/mytest.txt
下載文件
- hdfs dfs -get /test/mytest.txt ./mytest2.txt
合并下載
先創(chuàng)建2個(gè)測(cè)試文件(log.access, log.error),內(nèi)容隨意,使用-put上傳到/test目錄下
- hdfs dfs -put log.* /test
然后把2個(gè)log文件合并下載到一個(gè)文件中
- hdfs dfs -getmerge /test/log.* ./log
查看本地log文件內(nèi)容,應(yīng)該包含log.access與log.error兩個(gè)文件的內(nèi)容。
復(fù)制
從HDFS的一個(gè)路徑拷貝HDFS的另一個(gè)路徑
- hdfs dfs -cp /test/mytest.txt /aa/mytest.txt.2
驗(yàn)證
- hdfs dfs -ls /aa
移動(dòng)文件
- hdfs dfs -mv /aa/mytest.txt.2 /aa/bb
驗(yàn)證
- hdfs dfs -ls /aa/bb
應(yīng)列出mytest.txt.2。
刪除
- hdfs dfs -rm -r /aa/bb/mytest.txt.2
使用-r參數(shù)可以一次刪除多級(jí)目錄。
驗(yàn)證
- hdfs dfs -ls /aa/bb
應(yīng)為空
修改文件權(quán)限
與Linux文件系統(tǒng)中的用法一樣,修改文件所屬權(quán)限
- -chgrp
- -chmod
- -chown
示例
- hdfs dfs -chmod 666 /test/mytest.txt
- hdfs dfs -chown someuser:somegrp /test/mytest.txt
統(tǒng)計(jì)文件系統(tǒng)的可用空間
- hdfs dfs -df -h /
統(tǒng)計(jì)文件夾的大小
- hdfs dfs -du -s -h /test
3、Java API操作
(1)環(huán)境配置
因?yàn)樾枰诒緳C(jī)鏈接Hadoop虛機(jī)服務(wù)器,所以需要配置Hadoop,使其可以被外部訪問(wèn)。
先登錄Hadoop虛機(jī)服務(wù)器,然后:
1)查看本機(jī)IP
- ip address
例如IP為:192.168.31.239
2)修改文件:
- vi /usr/local/hadoop-2.7.3/etc/hadoop/core-site.xml
- fs.defaultFS
- hdfs://localhost:9000
把其中的localhost:9000修改為本機(jī)IP 192.168.31.239:9000
3)重新啟動(dòng)HDFS
#停止
- stop-dfs.sh
#啟動(dòng)
start-dfs.sh
(2)搭建開(kāi)發(fā)環(huán)境
1)新建項(xiàng)目目錄hdfstest
2)在項(xiàng)目目錄下創(chuàng)建pom.xml
內(nèi)容:
3)創(chuàng)建源碼目錄src/main/java
現(xiàn)在項(xiàng)目目錄結(jié)構(gòu)
- ├── pom.xml
- !"" src
- │ └── main
- │ └── java
(3)示例代碼
查看文件列表ls
1)新建文件src/main/java/Ls.java
列出/下的文件列表,及遞歸獲取所有文件
2)編譯執(zhí)行
- mvn compile
- mvn exec:java -Dexec.mainClass="Ls" -Dexec.cleanupDaemonThreads
- =false
創(chuàng)建目錄mkdir
在HDFS中創(chuàng)建目錄/mkdir/a/b
1)新建文件
- src/main/java/Mkdir.java
2)編譯執(zhí)行
- mvn compile
- mvn exec:java -Dexec.mainClass="Mkdir" -Dexec.cleanupDaemonThre
- ads=false
3)在服務(wù)器中使用HDFS命令驗(yàn)證
- hdfs dfs -ls /mkdir
上傳文件put
在當(dāng)前項(xiàng)目目錄下新建測(cè)試文件,上傳到HDFS中的/mkdir
1)在項(xiàng)目目錄下創(chuàng)建測(cè)試文件testfile.txt,內(nèi)容隨意
2)新建文件src/main/java/Put.java
3)編譯執(zhí)行
- mvn compile
- mvn exec:java -Dexec.mainClass="Put" -Dexec.cleanupDaemonThread
- s=false
4)在服務(wù)器中使用HDFS命令驗(yàn)證
- hdfs dfs -ls /mkdir
- hdfs dfs -cat /mkdir/testfile.txt
下載文件get
1)新建文件src/main/java/Get.java
把HDFS中/mkdir/testfile.txt下載到當(dāng)前項(xiàng)目目錄下
2)編譯執(zhí)行
- mvn compile
- mvn exec:java -Dexec.mainClass="Get" -Dexec.cleanupDaemonThread
- s=false
3)查看項(xiàng)目目錄下是否存在testfile2.txt及其內(nèi)容
刪除文件delete
刪除HDFS上之前上傳的/mkdir/testfile.txt
1)新建文件src/main/java/Del.java
2)編譯執(zhí)行
- mvn compile
- mvn exec:java -Dexec.mainClass="Del" -Dexec.cleanupDaemonThread
- s=false
3)在服務(wù)器中使用HDFS命令驗(yàn)證,檢查testfile.txt是否被刪除
- hdfs dfs -ls /mkdir
重命名rename
把HDFS中的/mkdir/a重命名為/mkdir/a2
1)新建文件src/main/java/Rename.java
2)編譯執(zhí)行
- mvn compile
- mvn exec:java -Dexec.mainClass="Rename" -Dexec.cleanupDaemonThr
- eads=false
3)在服務(wù)器中使用HDFS命令驗(yàn)證
- hdfs dfs -ls /mkdir
流方式讀取文件部分內(nèi)容
上傳一個(gè)文本文件,然后使用流方式讀取部分內(nèi)容保存到當(dāng)前項(xiàng)目目錄。
1)在服務(wù)器中創(chuàng)建一個(gè)測(cè)試文件test.txt,內(nèi)容:
- 123456789abcdefghijklmn
上傳到HDFS
- hdfs dfs -put test.txt /
2)在本地項(xiàng)目中新建文件src/main/java/StreamGet.java
2)編譯執(zhí)行
- mvn compile
- mvn exec:java -Dexec.mainClass="StreamGet" -Dexec.cleanupDaemon
- Threads=false
3)執(zhí)行后查看項(xiàng)目目錄下的test.txt.part2
- 6789abcdefghijklmn
前面的12345已經(jīng)被略過(guò)
三、深入了解
1、寫(xiě)入機(jī)制
向HDFS中寫(xiě)入文件時(shí),是按照塊兒為單位的,client會(huì)根據(jù)配置中設(shè)置的塊兒的大小把目標(biāo)文件切為多塊,例如文件是300M ,配置中塊大小值為128M,那么就分為3塊兒。
具體寫(xiě)入流程:
client向namenode發(fā)請(qǐng)求,說(shuō)想要上傳文件
namenode會(huì)檢查目標(biāo)文件是否存在、父目錄是否存在,檢查沒(méi)有問(wèn)題后返回確認(rèn)信息
client再發(fā)請(qǐng)求,問(wèn)***個(gè)block應(yīng)該傳到哪些datanode上
namenode經(jīng)過(guò)衡量,返回3個(gè)可用的datanode(A,B,C)
client與A建立連接,A與B建立連接,B與C建立連接,形成一個(gè)pipeline
傳輸管道建立完成后,client開(kāi)始向A發(fā)送數(shù)據(jù)包,此數(shù)據(jù)包會(huì)經(jīng)過(guò)管道一次傳遞到B和C
當(dāng)***個(gè)block的數(shù)據(jù)都傳完以后,client再向namenode請(qǐng)求第二個(gè)block上傳到哪些datanode,然后建立傳輸管道發(fā)送數(shù)據(jù)
就這樣,直到client把文件全部上傳完成

2、讀取機(jī)制
Client把要讀取的文件路徑發(fā)給namenode,查詢(xún)?cè)獢?shù)據(jù),找到文件塊所在的datanode服務(wù)器
Client直到了文件包含哪幾塊兒、每一塊兒在哪些datanode上,就選擇那些離自己進(jìn)的datanode(在同一機(jī)房,如果有多個(gè)離著近的,就隨機(jī)選擇),請(qǐng)求簡(jiǎn)歷socket流
從datanode獲取數(shù)據(jù)
Client接收數(shù)據(jù)包,先本地緩存,然后寫(xiě)入目標(biāo)文件
直到文件讀取完成
3、NameNode機(jī)制
通過(guò)對(duì)HDFS讀寫(xiě)流程的了解,可以發(fā)現(xiàn)namenode是一個(gè)很重要的部分,它記錄著整個(gè)HDFS系統(tǒng)的元數(shù)據(jù),這些元數(shù)據(jù)是需要持久化的,要保存到文件中。
Namenode還要承受巨大的訪問(wèn)量,client讀寫(xiě)文件時(shí)都需要請(qǐng)求namenode,寫(xiě)文件時(shí)要修改元數(shù)據(jù),讀文件時(shí)要查詢(xún)?cè)獢?shù)據(jù)。
為了提高效率,namenode便將元數(shù)據(jù)加載到內(nèi)存中,每次修改時(shí),直接修改內(nèi)存,而不是直接修改文件,同時(shí)會(huì)記錄下操作日志,供后期修改文件時(shí)使用。
這樣,namenode對(duì)數(shù)據(jù)的管理就涉及到了3種存儲(chǔ)形式:
- 內(nèi)存數(shù)據(jù)
- 元數(shù)據(jù)文件
- 操作日志文件
namenode需要定期對(duì)元數(shù)據(jù)文件和日志文件進(jìn)行整合,以保證文件中數(shù)據(jù)是新的,但這個(gè)過(guò)程很消耗性能,namenode需要快速地響應(yīng)client的大量請(qǐng)求,很難去完成文件整合操作,這時(shí)就引入了一個(gè)小助手secondnamenode。
secondnamenode會(huì)定期從namenode中下載元數(shù)據(jù)文件和操作日志,進(jìn)行整合,形成新的數(shù)據(jù)文件,然后傳回namenode,并替換掉之前的舊文件。
secondnamenode是namenode的好幫手,替namenode完成了這個(gè)重體力活兒,并且還可以作為namenode的一個(gè)防災(zāi)備份,當(dāng)namenode數(shù)據(jù)丟失時(shí),secondnamenode上有最近一次整理好的數(shù)據(jù)文件,可以傳給namenode進(jìn)行加載,這樣可以保證最少的數(shù)據(jù)丟失。
小結(jié)
HDFS的基礎(chǔ)內(nèi)容介紹完了,希望可以幫助您快速熟悉HDFS的思路和使用方式。