這是一篇最通熟易懂的Hadoop HDFS實踐攻略!
作者介紹:杜亦舒,創業中,技術合夥人,喜歡研究分享技術。個人訂閱號:效能與架構。
- HDFS是用來解決什麼問題?怎麼解決的?
- 如何在命令列下操作HDFS?
- 如何使用Java API來操作HDFS?
- 在瞭解基本思路和操作方法後,進一步深究HDFS具體的讀寫資料流程
學習並實踐本文教程後,可以對HDFS有比較清晰的認識,並可以進行熟練操作,為後續學習Hadoop體系打好基礎。
目錄:
理論部分
- HDFS 基本原理
- 檔案讀取、寫入機制
- 元資料管理思路
實踐部分
- 安裝實踐環境
- Shell 命令列操作方式
- Java API操作方式
一、HDFS基本原理
HDFS(Hadoop Distribute File System)是一個分散式檔案系統,是Hadoop的重要成員。
1、檔案系統的問題
檔案系統是作業系統提供的磁碟空間管理服務,只需要我們制定把檔案放到哪兒,從哪個路徑讀取檔案就可以了,不用關心檔案在磁碟上是如何存放的。
當檔案所需空間大於本機磁碟空間時,如何處理呢?
一是加磁碟,但是加到一定程度就有限制了;二是加機器,用遠端共享目錄的方式提供網路化的儲存,這種方式可以理解為分散式檔案系統的雛形,可以把不同檔案放入不同的機器中,空間不足了可繼續加機器,突破了儲存空間的限制。但這個方式有多個問題:
- 單機負載可能極高例如某個檔案是熱門,很多使用者經常讀取這個檔案,就使得次檔案所在機器的訪問壓力極高。
- 資料不安全如果某個檔案所在的機器出現故障,這個檔案就不能訪問了,可靠性很差。
- 檔案整理困難例如想把一些檔案的儲存位置進行調整,就需要看目標機器的空間是否夠用,並且需要自己維護檔案位置,如果機器非常多,操作就極為複雜。
2、HDFS的解決思路
HDFS是個抽象層,底層依賴很多獨立的伺服器,對外提供統一的檔案管理功能,對於使用者來講,感覺就像在操作一臺機器,感受不到HDFS下面的多臺伺服器。
例如使用者訪問HDFS中的/a/b/c.mpg這個檔案,HDFS負責從底層相應伺服器中讀取,然後返回給使用者,這樣使用者只需和HDFS打交道,不關心這個檔案是怎麼儲存的。
例如使用者需要儲存一個檔案/a/b/xxx.avi。
HDFS首先會把這個檔案進行分割,例如分為4塊,然後分別放到不同伺服器上。
這樣做有個好處,不怕檔案太大,並且讀檔案的壓力不會全部集中在一臺伺服器上。但如果某臺伺服器壞了,檔案就讀不全了。
HDFS為保證檔案可靠性,會把每個檔案塊進行多個備份:
- 塊1:A B C
- 塊2:A B D
- 塊3:B C D
- 塊4:A C D
這樣檔案的可靠性就大大增強了,即使某個伺服器壞了,也可以完整讀取檔案。
同時還帶來一個很大的好處,就是增加了檔案的併發訪問能力,比如多個使用者讀取這個檔案時,都要讀塊1,HDFS可以根據伺服器的繁忙程度,選擇從那臺伺服器讀塊1。
3、元資料的管理
HDFS中存了哪些檔案?
檔案被分成了哪些塊?
每個塊被放在哪臺伺服器上?
……
這些都叫做元資料,這些元資料被抽象為一個目錄樹,記錄了這些複雜的對應關係。這些元資料由一個單獨的模組進行管理,這個模組叫做NameNode。存放檔案塊的真實伺服器叫做DataNode,所以使用者訪問HDFS的過程可以理解為:
使用者-> HDFS -> NameNode -> DataNode
4、HDFS優點
- 容量可以線性擴充套件
- 有副本機制,儲存可靠性高,吞吐量增大
- 有了NameNode後,使用者訪問檔案只需指定HDFS上的路徑
二、HDFS實踐
經過上面介紹,可以對HDFS有個基本的瞭解,下面開始進行實際操作,在實踐中更好的認識HDFS。
1、安裝實踐環境
您可以選擇自己搭建環境,也可以使用打包好的Hadoop環境(版本2.7.3)
這個Hadoop環境實際上是一個虛機映象,所以需要安裝virtualbox虛擬機器、vagrant映象管理工具,和我的Hadoop映象,然後用這個映象啟動虛機就可以了,下面是具體操作步驟:
1)安裝virtualbox
下載地址:https://www.virtualbox.org/wiki/Downloads
2)安裝vagrant
因為官網下載較慢,我上傳到了雲盤
Windows版
連結: https://pan.baidu.com/s/1pKKQGHl
密碼: eykr
Mac版
連結: https://pan.baidu.com/s/1slts9yt
密碼: aig4
安裝完成後,在命令列終端下就可以使用vagrant命令。
3)下載Hadoop映象
4)啟動
載入Hadoop映象
vagrant box add {自定義映象名稱} {映象所在路徑}
例如您想命名為Hadoop,映象下載後的路徑為d:\hadoop.box,載入命令就是這樣:
vagrant box add hadoop d:\hadoop.box
建立工作目錄,例如d:\hdfstest。
進入此目錄,初始化
cd d:\hdfstest
vagrant init hadoop
啟動虛機
vagrant up
啟動完成後,就可以使用SSH客戶端登入虛機了
IP 127.0.0.1
埠 2222
使用者名稱 root
密碼 vagrant
登入後使用命令ifconfig 檢視本虛機的IP(如192.168.31.239),可以使用此IP和埠22登入了
IP 192.168.31.239
埠 22
使用者名稱 root
密碼 vagrant
Hadoop伺服器環境搭建完成。
2、Shell命令列操作
登入Hadoop伺服器後,先啟動HDFS,執行命令:
start-dfs.sh
- 檢視幫助
hdfs dfs –help
顯示目錄資訊
-ls 後面是要檢視的目錄路徑
建立目錄
建立目錄/test
hdfs dfs -mkdir /test
一次建立多級目錄/aa/bb
hdfs dfs -mkdir -p /aa/bb
- 上傳檔案
形式
hdfs dfs -put {本地路徑} {hdfs中的路徑}
例項(先建立好一個測試檔案mytest.txt,內容隨意,然後上傳到/test)
hadoop fs -put ~/mytest.txt /test
- 顯示檔案內容
hdfs dfs -cat /test/mytest.txt
- 合併下載
先建立2個測試檔案(log.access, log.error),內容隨意,使用-put上傳到/test目錄下
hdfs dfs -put log.* /test
然後把2個log檔案合併下載到一個檔案中
hdfs dfs -getmerge /test/log.* ./log
檢視本地log檔案內容,應該包含log.access與log.error兩個檔案的內容。
- 複製
從HDFS的一個路徑拷貝HDFS的另一個路徑
hdfs dfs -cp /test/mytest.txt /aa/mytest.txt.2
驗證
hdfs dfs -ls /aa
- 移動檔案
hdfs dfs -mv /aa/mytest.txt.2 /aa/bb
驗證
hdfs dfs -ls /aa/bb
應列出mytest.txt.2。
- 刪除
hdfs dfs -rm -r /aa/bb/mytest.txt.2
使用-r引數可以一次刪除多級目錄。
驗證
hdfs dfs -ls /aa/bb
應為空
- 修改檔案許可權
與Linux檔案系統中的用法一樣,修改檔案所屬許可權
-chgrp
-chmod
-chown
示例
hdfs dfs -chmod 666 /test/mytest.txt
hdfs dfs -chown someuser:somegrp /test/mytest.txt
- 統計檔案系統的可用空間
hdfs dfs -df -h /
- 統計資料夾的大小
hdfs dfs -du -s -h /test
3、Java API操作
(1)環境配置
因為需要在本機連結Hadoop虛機伺服器,所以需要配置Hadoop,使其可以被外部訪問。
先登入Hadoop虛機伺服器,然後:
1)檢視本機IP
ip address
例如IP為:192.168.31.239
2)修改檔案:
vi /usr/local/hadoop-2.7.3/etc/hadoop/core-site.xml
<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
</property>
把其中的localhost:9000修改為本機IP 192.168.31.239:9000
3)重新啟動HDFS
#停止
stop-dfs.sh
#啟動
start-dfs.sh
(2)搭建開發環境
)新建專案目錄hdfstest
2)在專案目錄下建立pom.xml
內容:
3)建立原始碼目錄src/main/java
現在專案目錄結構
├── pom.xml
!”” src
│ └── main
│ └── java
(3)示例程式碼
檢視檔案列表ls
1)新建檔案src/main/java/Ls.java
列出/下的檔案列表,及遞迴獲取所有檔案
2)編譯執行
mvn compile
mvn exec:java -Dexec.mainClass=”Ls” -Dexec.cleanupDaemonThreads
=false
建立目錄mkdir
在HDFS中建立目錄/mkdir/a/b
1)新建檔案
src/main/java/Mkdir.java
2)編譯執行
mvn compile
mvn exec:java -Dexec.mainClass=”Mkdir” -Dexec.cleanupDaemonThre
ads=false
3)在伺服器中使用HDFS命令驗證
hdfs dfs -ls /mkdir
上傳檔案put
在當前專案目錄下新建測試檔案,上傳到HDFS中的/mkdir
1)在專案目錄下建立測試檔案testfile.txt,內容隨意
2)新建檔案src/main/java/Put.java
3)編譯執行
mvn compile
mvn exec:java -Dexec.mainClass=”Put” -Dexec.cleanupDaemonThread
s=false
4)在伺服器中使用HDFS命令驗證
hdfs dfs -ls /mkdir
hdfs dfs -cat /mkdir/testfile.txt
下載檔案get
1)新建檔案src/main/java/Get.java
把HDFS中/mkdir/testfile.txt下載到當前專案目錄下
2)編譯執行
mvn compile
mvn exec:java -Dexec.mainClass=”Get” -Dexec.cleanupDaemonThread
s=false
3)檢視專案目錄下是否存在testfile2.txt及其內容
刪除檔案delete
刪除HDFS上之前上傳的/mkdir/testfile.txt
1)新建檔案src/main/java/Del.java
2)編譯執行
mvn compile
mvn exec:java -Dexec.mainClass=”Del” -Dexec.cleanupDaemonThread
s=false
3)在伺服器中使用HDFS命令驗證,檢查testfile.txt是否被刪除
hdfs dfs -ls /mkdir
重新命名rename
把HDFS中的/mkdir/a重新命名為/mkdir/a2
1)新建檔案src/main/java/Rename.java
2)編譯執行
mvn compile
mvn exec:java -Dexec.mainClass=”Rename” -Dexec.cleanupDaemonThr
eads=false
3)在伺服器中使用HDFS命令驗證
hdfs dfs -ls /mkdir
流方式讀取檔案部分內容
上傳一個文字檔案,然後使用流方式讀取部分內容儲存到當前專案目錄。
1)在伺服器中建立一個測試檔案test.txt,內容:
123456789abcdefghijklmn
上傳到HDFS
hdfs dfs -put test.txt /
2)在本地專案中新建檔案src/main/java/StreamGet.java
2)編譯執行
mvn compile
mvn exec:java -Dexec.mainClass=”StreamGet” -Dexec.cleanupDaemon
Threads=false
3)執行後檢視專案目錄下的test.txt.part2
6789abcdefghijklmn
前面的12345已經被略過
三、深入瞭解
1、寫入機制
向HDFS中寫入檔案時,是按照塊兒為單位的,client會根據配置中設定的塊兒的大小把目標檔案切為多塊,例如檔案是300M ,配置中塊大小值為128M,那麼就分為3塊兒。
具體寫入流程:
- client向namenode發請求,說想要上傳檔案
- namenode會檢查目標檔案是否存在、父目錄是否存在,檢查沒有問題後返回確認資訊
- client再發請求,問第一個block應該傳到哪些datanode上
- namenode經過衡量,返回3個可用的datanode(A,B,C)
- client與A建立連線,A與B建立連線,B與C建立連線,形成一個pipeline
- 傳輸管道建立完成後,client開始向A傳送資料包,此資料包會經過管道一次傳遞到B和C
- 當第一個block的資料都傳完以後,client再向namenode請求第二個block上傳到哪些datanode,然後建立傳輸管道傳送資料
- 就這樣,直到client把檔案全部上傳完成
2、讀取機制
- Client把要讀取的檔案路徑發給namenode,查詢元資料,找到檔案塊所在的datanode伺服器
- Client直到了檔案包含哪幾塊兒、每一塊兒在哪些datanode上,就選擇那些離自己進的datanode(在同一機房,如果有多個離著近的,就隨機選擇),請求簡歷socket流
- 從datanode獲取資料
- Client接收資料包,先本地快取,然後寫入目標檔案
- 直到檔案讀取完成
3、NameNode機制
通過對HDFS讀寫流程的瞭解,可以發現namenode是一個很重要的部分,它記錄著整個HDFS系統的元資料,這些元資料是需要持久化的,要儲存到檔案中。
Namenode還要承受巨大的訪問量,client讀寫檔案時都需要請求namenode,寫檔案時要修改元資料,讀檔案時要查詢元資料。
為了提高效率,namenode便將元資料載入到記憶體中,每次修改時,直接修改記憶體,而不是直接修改檔案,同時會記錄下操作日誌,供後期修改檔案時使用。
這樣,namenode對資料的管理就涉及到了3種儲存形式:
- 記憶體資料
- 元資料檔案
- 操作日誌檔案
namenode需要定期對元資料檔案和日誌檔案進行整合,以保證檔案中資料是新的,但這個過程很消耗效能,namenode需要快速地響應client的大量請求,很難去完成檔案整合操作,這時就引入了一個小助手secondnamenode。
secondnamenode會定期從namenode中下載元資料檔案和操作日誌,進行整合,形成新的資料檔案,然後傳回namenode,並替換掉之前的舊檔案。
secondnamenode是namenode的好幫手,替namenode完成了這個重體力活兒,並且還可以作為namenode的一個防災備份,當namenode資料丟失時,secondnamenode上有最近一次整理好的資料檔案,可以傳給namenode進行載入,這樣可以保證最少的資料丟失。
小結
HDFS的基礎內容介紹完了,希望可以幫助您快速熟悉HDFS的思路和使用方式。如有批評與建議(例如內容有誤、不足的地方、改進建議等),歡迎留言討論。
文章來自微信公眾號:DBAplus社群