Hadoop 概述
????????Hadoop 是一個由Apache 軟件基金會開發的分布式基礎架構。用戶可以在不了解分布式底層細節的情況下,開發分布式程序,充分利用集群的威力進行高速運算和存儲。
????????Hadoop 實現一個分布式文件系統(Hadoop Distributed File System, HDFS)。HDFS具有高容錯性的特點,并設計它用來部署在廉價的硬件上,而且它提供高吞吐量來訪問應用程序的數據,適合那些有著超大數據集的應用程序。Hadoop 框架的核心設計是HDFS和MapReduce。HDFS為海量數據提供了存儲,而MapReduce則為海量的數據提供了計算。
Hadoop 核心三大組件
- HDFS?
- MapReduce
- Yarn
基于Linux 安裝Hadoop 3 偽分布式版本/單機版本
請參考文章:Centos7 安裝Hadoop3 單機版本(偽分布式版本)
HDFS 原理?
HDFS采用Master/Slave架構。
- 一個HDFS集群包含一個單獨的NameNode和多個DataNode。
- NameNode作為Master服務,它負責管理文件系統的命名空間和客戶端對文件的訪問。NameNode會保存文件系統的具體信息,包括文件信息、文件被分割成具體block塊的信息、以及每一個block塊歸屬的DataNode的信息。對于整個集群來說,HDFS通過NameNode對用戶提供了一個單一的命名空間。
- DataNode作為Slave服務,在集群中可以存在多個。通常每一個DataNode都對應于一個物理節點。DataNode負責管理節點上它們擁有的存儲,它將存儲劃分為多個block塊,管理block塊信息,同時周期性的將其所有的block塊信息發送給NameNode。
HDFS系統架構圖,主要有三個角色,Client、NameNode、DataNode。
HDFS的一些關鍵元素
- Block:將文件分塊,通常為64M。
- NameNode:是Master節點,是大領導。管理數據塊映射;處理客戶端的讀寫請求;配置副本策略;管理HDFS的名稱空間。保存整個文件系統的目錄信息、文件信息及分塊信息,由唯一一臺主機專門保存。
- SecondaryNameNode:是一個小弟,分擔大哥NameNode的工作量;是NameNode的冷備份;合并fsimage和fsedits然后再發給NameNode。(熱備份:b是a的熱備份,如果a壞掉。那么b馬上運行代替a的工作。冷備份:b是a的冷備份,如果a壞掉。那么b不能馬上代替a工作。但是b上存儲a的一些信息,減少a壞掉之后的損失。)
- DataNode:是Slave節點,奴隸,干活的。負責存儲Client發來的數據塊block;執行數據塊的讀寫操作。
- fsimage:元數據鏡像文件(文件系統的目錄樹)
- edits:元數據的操作日志(針對文件系統做的修改操作記錄)
HDFS設計重點
- HDFS 數據備份HDFS被設計成一個可以在大集群中、跨機器、可靠的存儲海量數據的框架。它將所有文件存儲成block塊組成的序列,除了最后一個block塊,所有的block塊大小都是一樣的。
- HDFS中的文件默認規則是write one(一次寫、多次讀)的,并且嚴格要求在任何時候只有一個writer。
- NameNode全權管理數據塊的復制,它周期性地從集群中的每個DataNode接受心跳信號和塊狀態報告(BlockReport)。接收到心跳信號以為該DataNode工作正常,塊狀態報告包含了一個該DataNode上所有數據塊的列表。
- NameNode內存中存儲的是=fsimage+edits。SecondaryNameNode負責定時(默認1小時)從NameNode上,獲取fsimage和edits來進行合并,然后再發送給NameNode。減少NameNode的工作量。
HDFS 文件寫入?
Client向NameNode發起文件寫入的請求。
- NameNode根據文件大小和文件塊配置情況,返回給Client它所管理部分DataNode的信息。
- Client將文件劃分為多個block塊,并根據DataNode的地址信息,按順序寫入到每一個DataNode塊中。
實例講解:有一個文件FileA,100M大小。Client將FileA寫入到HDFS上。
Hadoop 環境配置說明:
- HDFS分布在三個機架上Rack1,Rack2,Rack3。
文件寫入過程如下:
- Client將FileA按64M分塊。分成兩塊,block1和Block2;
- Client向NameNode發送寫數據請求,如圖藍色虛線①------>。
- NameNode節點,記錄block信息。并返回可用的DataNode,如粉色虛線②--------->。
- Block1: host2,host1,host3
- Block2: host7,host8,host4
- 原理:
- NameNode具有RackAware機架感知功能,這個可以配置。
- 若Client為DataNode節點,那存儲block時,規則為:副本1,同Client的節點上;副本2,不同機架節點上;副本3,同第二個副本機架的另一個節點上;其他副本隨機挑選。
- 若Client不為DataNode節點,那存儲block時,規則為:副本1,隨機選擇一個節點上;副本2,不同副本1,機架上;副本3,同副本2相同的另一個節點上;其他副本隨機挑選。
- Client向DataNode發送block1;發送過程是以流式寫入。流式寫入過程如下:
- 將64M的block1按64k的package劃分;
- 然后將第一個package發送給host2;
- host2接收完后,將第一個package發送給host1,同時Client想host2發送第二個package;
- host1接收完第一個package后,發送給host3,同時接收host2發來的第二個package。
- 以此類推,如圖紅線實線所示,直到將block1發送完畢。
- host2,host1,host3向NameNode,host2向Client發送通知,說“消息發送完了”。如圖粉紅顏色實線所示。
- Client收到host2發來的消息后,向NameNode發送消息,說我寫完了。這樣就真完成了。如圖黃色粗實線
- 發送完block1后,再向host7、host8、host4發送block2,如圖藍色實線所示。
- 發送完block2后,host7、host8、host4向NameNode,host7向Client發送通知,如圖淺綠色實線所示。
- Client向NameNode發送消息,說我寫完了,如圖黃色粗實線。。。這樣就完畢了。
- 分析:通過寫過程,我們可以了解到
- 寫1T文件,我們需要3T的存儲,3T的網絡流量貸款。
- 在執行讀或寫的過程中,NameNode和DataNode通過HeartBeat進行保存通信,確定DataNode活著。如果發現DataNode死掉了,就將死掉的DataNode上的數據,放到其他節點去。讀取時,要讀其他節點去。
- 掛掉一個節點,沒關系,還有其他節點可以備份;甚至,掛掉某一個機架,也沒關系;其他機架上,也有備份。
HDFS 文件讀取
Client向NameNode發起文件讀取的請求。
- Client向NameNode發起文件讀取的請求。
- NameNode返回文件存儲的block塊信息、及其block塊所在DataNode的信息。
- Client讀取文件信息。
如圖所示,Client要從DataNode上,讀取FileA。而FileA由block1和block2組成。讀操作流程如下:
- Client向NameNode發送讀請求。
- NameNode查看Metadata信息,返回FileA的block的位置。
- block1:host2,host1,host3
- block2:host7,host8,host4
- block的位置是有先后順序的,先讀block1,再讀block2。而且block1去host2上讀取;然后block2,去host7上讀取。
上面例子中,Client位于機架外,那么如果Client位于機架內某個DataNode上,例如,Client是host6。那么讀取的時候,遵循的規律是:優選讀取本機架上的數據。
HDFS 數據備份
備份數據的存放是HDFS可靠性和性能的關鍵。HDFS采用一種稱為rack-aware的策略來決定備份數據的存放。
通過一個稱為Rack Awareness的過程,NameNode決定每個DataNode所屬rack id。
缺省情況下,一個block塊會有三個備份:
- 一個在NameNode指定的DataNode上
- 一個在指定DataNode非同一rack的DataNode上
- 一個在指定DataNode同一rack的DataNode上。
這種策略綜合考慮了同一rack失效、以及不同rack之間數據復制性能問題。
副本的選擇:為了降低整體的帶寬消耗和讀取延時,HDFS會盡量讀取最近的副本。如果在同一個rack上有一個副本,那么就讀該副本。如果一個HDFS集群跨越多個數據中心,那么將首先嘗試讀本地數據中心的副本。
HDFS Shell 命令
HDFS Shell 簡介
????????調用文件系統(HDFS)Shell命令應使用?bin/hadoop fs <args>的形式。 所有的的FS shell命令使用URI路徑作為參數。URI格式是scheme://authority/path。對HDFS文件系統,scheme是hdfs,對本地文件系統,scheme是file。其中scheme和authority參數都是可選的,如果未加指定,就會使用配置中指定的默認scheme。
HDFS Shell 命令詳解
cat
使用方法:hadoop fs -cat URI [URI …]
將路徑指定文件的內容輸出到stdout。
示例:
- hadoop fs -cat hdfs://host1:port1/file1 hdfs://host2:port2/file2
- hadoop fs -cat file:///file3 /user/hadoop/file4
返回值:
成功返回0,失敗返回-1。
chgrp
使用方法:hadoop fs -chgrp [-R] GROUP URI [URI …]?Change group association of files. With?-R, make the change recursively through the directory structure. The user must be the owner of files, or else a super-user. Additional information is in the?Permissions User Guide. -->
改變文件所屬的組。使用-R將使改變在目錄結構下遞歸進行。命令的使用者必須是文件的所有者或者超級用戶。更多的信息請參見HDFS權限用戶指南。
chmod
使用方法:hadoop fs -chmod [-R] <MODE[,MODE]... | OCTALMODE> URI [URI …]
改變文件的權限。使用-R將使改變在目錄結構下遞歸進行。命令的使用者必須是文件的所有者或者超級用戶。更多的信息請參見HDFS權限用戶指南。
chown
使用方法:hadoop fs -chown [-R] [OWNER][:[GROUP]] URI [URI ]
改變文件的擁有者。使用-R將使改變在目錄結構下遞歸進行。命令的使用者必須是超級用戶。更多的信息請參見HDFS權限用戶指南。
copyFromLocal
使用方法:hadoop fs -copyFromLocal <localsrc> URI
除了限定源路徑是一個本地文件外,和put命令相似。
copyToLocal
使用方法:hadoop fs -copyToLocal [-ignorecrc] [-crc] URI <localdst>
除了限定目標路徑是一個本地文件外,和get命令類似。
cp
使用方法:hadoop fs -cp URI [URI …] <dest>
將文件從源路徑復制到目標路徑。這個命令允許有多個源路徑,此時目標路徑必須是一個目錄。
示例:
- hadoop fs -cp /user/hadoop/file1 /user/hadoop/file2
- hadoop fs -cp /user/hadoop/file1 /user/hadoop/file2 /user/hadoop/dir
返回值:
成功返回0,失敗返回-1。
du
使用方法:hadoop fs -du URI [URI …]
顯示目錄中所有文件的大小,或者當只指定一個文件時,顯示此文件的大小。
示例:
hadoop fs -du /user/hadoop/dir1 /user/hadoop/file1 hdfs://host:port/user/hadoop/dir1
返回值:
成功返回0,失敗返回-1。
dus
使用方法:hadoop fs -dus <args>
顯示文件的大小。
expunge
使用方法:hadoop fs -expunge
清空回收站。請參考HDFS設計文檔以獲取更多關于回收站特性的信息。
get
使用方法:hadoop fs -get [-ignorecrc] [-crc] <src> <localdst>
復制文件到本地文件系統。可用-ignorecrc選項復制CRC校驗失敗的文件。使用-crc選項復制文件以及CRC信息。
示例:
- hadoop fs -get /user/hadoop/file localfile
- hadoop fs -get hdfs://host:port/user/hadoop/file localfile
返回值:
成功返回0,失敗返回-1。
getmerge
使用方法:hadoop fs -getmerge <src> <localdst> [addnl]
接受一個源目錄和一個目標文件作為輸入,并且將源目錄中所有的文件連接成本地目標文件。addnl是可選的,用于指定在每個文件結尾添加一個換行符。
ls
使用方法:hadoop fs -ls <args>
如果是文件,則按照如下格式返回文件信息:
文件名 <副本數> 文件大小 修改日期 修改時間 權限 用戶ID 組ID
如果是目錄,則返回它直接子文件的一個列表,就像在Unix中一樣。目錄返回列表的信息如下:
目錄名 <dir> 修改日期 修改時間 權限 用戶ID 組ID
示例:
hadoop fs -ls /user/hadoop/file1 /user/hadoop/file2 hdfs://host:port/user/hadoop/dir1 /nonexistentfile
返回值:
成功返回0,失敗返回-1。
lsr
使用方法:hadoop fs -lsr <args>
ls命令的遞歸版本。類似于Unix中的ls -R。
mkdir
使用方法:hadoop fs -mkdir <paths>
接受路徑指定的uri作為參數,創建這些目錄。其行為類似于Unix的mkdir -p,它會創建路徑中的各級父目錄。
示例:
- hadoop fs -mkdir /user/hadoop/dir1 /user/hadoop/dir2
- hadoop fs -mkdir hdfs://host1:port1/user/hadoop/dir hdfs://host2:port2/user/hadoop/dir
返回值:
成功返回0,失敗返回-1。
movefromLocal
使用方法:dfs -moveFromLocal <src> <dst>
輸出一個”not implemented“信息。
mv
使用方法:hadoop fs -mv URI [URI …] <dest>
將文件從源路徑移動到目標路徑。這個命令允許有多個源路徑,此時目標路徑必須是一個目錄。不允許在不同的文件系統間移動文件。
示例:
- hadoop fs -mv /user/hadoop/file1 /user/hadoop/file2
- hadoop fs -mv hdfs://host:port/file1 hdfs://host:port/file2 hdfs://host:port/file3 hdfs://host:port/dir1
返回值:
成功返回0,失敗返回-1。
put
使用方法:hadoop fs -put <localsrc> ... <dst>
從本地文件系統中復制單個或多個源路徑到目標文件系統。也支持從標準輸入中讀取輸入寫入目標文件系統。
- hadoop fs -put localfile /user/hadoop/hadoopfile
- hadoop fs -put localfile1 localfile2 /user/hadoop/hadoopdir
- hadoop fs -put localfile hdfs://host:port/hadoop/hadoopfile
- hadoop fs -put - hdfs://host:port/hadoop/hadoopfile
從標準輸入中讀取輸入。
返回值:
成功返回0,失敗返回-1。
rm
使用方法:hadoop fs -rm URI [URI …]
刪除指定的文件。只刪除非空目錄和文件。請參考rmr命令了解遞歸刪除。
示例:
- hadoop fs -rm hdfs://host:port/file /user/hadoop/emptydir
返回值:
成功返回0,失敗返回-1。
rmr
使用方法:hadoop fs -rmr URI [URI …]
delete的遞歸版本。
示例:
- hadoop fs -rmr /user/hadoop/dir
- hadoop fs -rmr hdfs://host:port/user/hadoop/dir
返回值:
成功返回0,失敗返回-1。
setrep
使用方法:hadoop fs -setrep [-R] <path>
改變一個文件的副本系數。-R選項用于遞歸改變目錄下所有文件的副本系數。
示例:
- hadoop fs -setrep -w 3 -R /user/hadoop/dir1
返回值:
成功返回0,失敗返回-1。
stat
使用方法:hadoop fs -stat URI [URI …]
返回指定路徑的統計信息。
示例:
- hadoop fs -stat path
返回值:
成功返回0,失敗返回-1。
tail
使用方法:hadoop fs -tail [-f] URI
將文件尾部1K字節的內容輸出到stdout。支持-f選項,行為和Unix中一致。
示例:
- hadoop fs -tail pathname
返回值:
成功返回0,失敗返回-1。
test
使用方法:hadoop fs -test -[ezd] URI
選項:
-e 檢查文件是否存在。如果存在則返回0。
-z 檢查文件是否是0字節。如果是則返回0。
-d 如果路徑是個目錄,則返回1,否則返回0。
示例:
- hadoop fs -test -e filename
text
使用方法:hadoop fs -text <src>
將源文件輸出為文本格式。允許的格式是zip和TextRecordInputStream。
touchz
使用方法:hadoop fs -touchz URI [URI …]
創建一個0字節的空文件。
示例:
- hadoop -touchz pathname
返回值:
成功返回0,失敗返回-1。
HDFS Python API
HDFS 除了通過HDFS Shell 命令的方式進行操作,還可以通過Java API、Python API、C++ API等方式進行編程操作。在使用Python API 編程前,需要安裝HDFS 依賴的第三方庫:PyHDFS
pyhdfs?
官方文檔地址:https://pyhdfs.readthedocs.io/en/latest/pyhdfs.html
原文簡介:
WebHDFS client with support for NN HA and automatic error checkingFor details on the WebHDFS endpoints, see the Hadoop documentation:https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/WebHDFS.html
https://hadoop.apache.org/docs/current/api/org/apache/hadoop/fs/FileSystem.html
https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/filesystem/filesystem.html
大致意思是:pyhdfs 模塊/庫使用WebHDFS 客戶端連接HDFS,支持NN HA? 和自動錯誤檢測,詳細使用參考官方文檔地址。
pyhdfs 核心類
Python 3 使用 pyhdfs(重點是HdfsClient 類)
安裝pyhdfs 模塊/庫
pip install pyhdfs
pyhdfs 使用實例
# _*_ coding : UTF-8_*_
# 開發者 : zhuozhiwengang
# 開發時間 : 2023/8/11 22:35
# 文件名稱 : pythonHdfs_1
# 開發工具 : PyCharmimport pyhdfs# 基于pyHDFS 模塊, 連接Hadoop 主機:9870 端口
fs = pyhdfs.HdfsClient(hosts="192.168.43.11:9870", user_name="root")# 返回用戶根目錄
print(fs.get_home_directory())# 返回可用namenode節點
print(fs.get_active_namenode())# 返回指定目錄下所有文件
print(fs.listdir("/"))# hadoop 創建指定目錄
fs.mkdirs('/uploads')# 再次執行返貨指定目錄下所有文件
print(fs.listdir("/"))# 執行本地文件上傳Hadoop 指定目錄
# fs.copy_from_local("D:\one.txt", '/uploads/one.txt')# 執行Hadoop 文件下載
# fs.copy_to_local("/uploads/one.txt", r'D:\two.txt')# 判斷目錄是否存在
print(fs.exists("/uploads"))
# 返回目錄下的所有目錄,路徑,文件名
print(list(fs.walk('/uploads')))# 刪除目錄/文件
fs.delete("/uploads", recursive=True) # 刪除目錄 recursive=True
fs.delete("/uploads/one.txt") # 刪除文件
Python 3 通用封裝?pyhdfs
# _*_ coding : UTF-8_*_
# 開發者 : zhuozhiwengang
# 開發時間 : 2023/8/11 22:35
# 文件名稱 : pythonHdfs
# 開發工具 : PyCharmimport sys
import pyhdfsclass HDFS:def __init__(self, host='192.168.43.11',user_name='root'):self.host = hostself.user_name=user_namedef get_con(self):try:hdfs = pyhdfs.HdfsClient(hosts = self.host,user_name = self.user_name)return hdfsexcept pyhdfs.HdfsException,e:print "Error:%s" % e# 返回指定目錄下的所有文件def listdir(self,oper):try:client = self.get_con()dirs = client.listdir(oper)for row in dirs:print rowexcept pyhdfs.HdfsException, e:print "Error:%s" % e# 返回用戶的根目錄def get_home_directory(self):try:client = self.get_con()print client.get_home_directory()except pyhdfs.HdfsException, e:print "Error:%s" % e# 返回可用的namenode節點def get_active_namenode(self):try:client = self.get_con()print client.get_active_namenode()except pyhdfs.HdfsException, e:print "Error:%s" % e# 創建新目錄def mkdirs(self,oper):try:client = self.get_con()print client.mkdirs(oper)except pyhdfs.HdfsException, e:print "Error:%s" % e# 從集群上copy到本地def copy_to_local(self, dest,localsrc):try:client = self.get_con()print client.copy_to_local(dest,localsrc)except pyhdfs.HdfsException, e:print "Error:%s" % e# 從本地上傳文件至集群def copy_from_local(self, localsrc, dest):try:client = self.get_con()print client.copy_from_local(localsrc, dest)except pyhdfs.HdfsException, e:print "Error:%s" % e# 查看文件內容def read_files(self,oper):try:client = self.get_con()response = client.open(oper)print response.read()except pyhdfs.HdfsException, e:print "Error:%s" % e# 向一個已經存在的文件追加內容def append_files(self, file,content):try:client = self.get_con()print client.append(file,content)except pyhdfs.HdfsException, e:print "Error:%s" % e# 查看是否存在文件def check_files(self,oper):try:client = self.get_con()print client.exists(oper)except pyhdfs.HdfsException, e:print "Error:%s" % e# 查看文件的校驗和def get_file_checksum(self,oper):try:client = self.get_con()print client.get_file_checksum(oper)except pyhdfs.HdfsException, e:print "Error:%s" % e# 查看路徑總覽信息def get_content_summary(self,oper):try:client = self.get_con()print client.get_content_summary(oper)except pyhdfs.HdfsException, e:print "Error:%s" % e# 查看當前路徑的狀態def list_status(self,oper):try:client = self.get_con()print client.list_status(oper)except pyhdfs.HdfsException, e:print "Error:%s" % e# 刪除文件def delete_files(self,path):try:client = self.get_con()print client.delete(path)except pyhdfs.HdfsException, e:print "Error:%s" % eif __name__ == '__main__':db = HDFS('Hadoop3-master','root')# db.listdir('/user')# db.get_home_directory()# db.get_active_namenode()# db.mkdirs('/dave')# db.copy_from_local("D:/one.txt","/uploads/two.txt")# db.listdir('/uploads')# db.read_files('/uploads/two.txt')# db.check_files('/uploads/two.txt')# db.get_file_checksum('/uploads/two.txt')# db.get_content_summary('/')# db.list_status('/')# db.list_status('/uploads/two.txt')# db.copy_to_local("/uploads/two.txt","D:/one.txt")# db.append_files('/uploads/two.txt',"88, CSDN 博客")# db.read_files('/uploads/two.txt')# db.copy_from_local("D:/three.txt", "/uploads/two.txt")db.listdir('/uploads')# db.delete_files('/uploads/two.txt')