您好,登錄后才能下訂單哦!
好程序員大數據學習路線分享分布式文件系統HDFS,設計目標:
1、存儲量大
2、自動快速檢測應對硬件錯誤
3、流式訪問數據
4、移動計算比移動數據本身更劃算
5、簡單一致性模型
6、異構平臺可移植
優點:
高可靠性:Hadoop按位存儲和處理數據的能力強
高擴展性:hadoop是在可用的計算機集簇間分配數據并完成計算任務的,這些集簇可以方便地擴展到數以千計的節點中
高效性:hadoop能夠在節點之間動態地移動數據,并保證各個節點的動態平衡,因此處理速度非常快
高容錯性:hadoop能夠自動保存數據的多個副本,并且能夠自動將失敗的任務重新分配。
缺點:
不適合低延遲數據訪問
無法高效存儲大量小文件(每個文件存儲都有屬于自己的索引,元數據龐大就不高效)
不支持多用戶寫入及任意修改文件(可以刪除以及追加,只是不能修改文件中某處的數據)
重要特性:
文件在物理上是分塊存儲,塊的大小可以通過配置參數(dfs.blocksize)來規定,默認2.x版本之后是128M,老版本是64M
HDFS會給哭護短提供一個統一的抽象目錄樹,客戶端通過路徑來訪問文件,刑辱:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data
目錄結構及文件分塊信息(元數據)的管理由namenode承擔—namenode是HDFS集群主節點,負責維護整個hdfs文件系統的目錄樹,以及每一個路徑(文件)所對應的block塊信息(block的id以及所在datanode服務器)
文件的各個block的存儲管理由datanode承擔—datanode是HDFS集群從節點,每一個block都可以在多個datanode上存儲多個副本(副本參數設置dfs.replication)
HDFS是設計成適應一次寫入,多次讀出的場景,且不支持文件的修改
管理文件系統的命名空間(元數據<metadata>:包含文件名稱、大小、所屬人、地址)
規定客戶端訪問文件規則
a)?文件大小是否已經超載(超過集群的負載)
b)?是否已經存在相同的文件
c)?是否具有創建該文件的權限
對文件執行命令,關閉,打開文件或者打開路徑等操作
所有的數據節點發送心跳給NameNode,他需要確保數據節點DataNode是否在線,一個數據塊報告包含所有這個數據節點上的所有block的狀況
首先將fsimage(鏡像)載入內存,并讀取執行日志editlog的各項操作
一旦在內存中建立文件系統元數據映射,則創建一個新的fsimage文件(這個過程不需要secondaryNamenode)和一個空的editlog
在安全模式下,各個datanode會向namenode發送塊列表的最新情況
此刻namenode運行在安全模式。即NameNode的文件系統對于客戶端來說是只讀
NameNode開始監聽RPC和HTTP請求
RPC:Remote Procedure Call Protocol---遠程過程通過協議
它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議
系統中數據塊的位置并不是由namenode維護的,而是以塊列表形式存儲在datanode中
在系統的正常操作期間,namenode會在內存中保留所有塊信息的映射信息
fsimage:元數據鏡像文件(保存文件系統的目錄樹)
edit.log:元數據操作日志(針對目錄樹的修改操作)
a)?內存中保存一份最新的
b)?內存中鏡像=fsimage+edits
定期合并fsimage與edits
c)?Edits文件過大將導致NamenNode重啟速度緩慢
d)?SecondaryNameNode負責定期合并他們
?
Client通過調用FileSystem的get方法與namenode進程建立通道進行通信,然后調用create方法來請求創建文件。
FileSystem通過對namenode發出遠程請求,在namenode里面創建一個新的文件,但此時并不關聯任何的塊。NameNode進行很多檢查來保證不存在要創建的文件已經存在文件系統中,同時檢查是否有相應的權限來創建文件。如果這些檢查完了,nameNameNode將這個新文件的嘻嘻記錄下來,然后FileSystem返回一個DFSOutputStream給客戶端用來寫入數據。和讀的情形一樣,FSDataOutputStream將包裝一個DFSOutputStream用于和DataNode及NameNode通信。而一旦文件創建失敗,客戶端會受到一個IOException,標識文件創建失敗,停止后續任務。
客戶端開始寫數。FSDataOutputStream把要寫入的數據分成塊打成包的形式,將其寫入到DFSOutputStream對象的中間隊列中。其中的數據由Datastreamer來讀取。DataStreamer的職責是讓NameNode分配新的塊—找出合適的DataNode來存儲作為備份而復制的數據。
FSDataOutputStream維護了一個內部關于packets的隊列,里面存放等待被DataNode確認無誤的packets的信息。這個隊列被稱為等待隊列,一個packet的信息被移出本隊列當且僅當packet被所有節點都確認無誤。
當完成數據寫入之后客戶端調用流的close方法,再通知NameNode完成寫入之前,這個方法將flush殘留的packets,并等待確認信息。NameNode已經知道文件由哪些塊組成,所以在返回成功前只需要等待數據塊進行最小復制。
Configuration?hdfsConf?= new Configuration();//創建一個hdfs的環境變量
String namenodeURI=”hdfs://hadoop001:8020”;//namenode的統一資源定位符
String username=”root”;//訪問指定用戶的hdfs
FileSystem hdfs = FileSystem.get(new URI(namenodeURI),hdfsConf,username);//創建一個hdfs的文件系統對象
FileSystem local = FileSystem.getLocal(new?Configuration());//創建一個本地的文件系統對象
hdfs.copyFromLocalFile(new Path(localPath),new Path(hdfsPath));
FSDateOutputStream out = hdfs.create(new Path(hdfsPath));
out.write(fileContent.getBytes());
out.close();
客戶端或者用戶通過調用FileSystem對象的open方法打開需要讀取的文件,這對HDFS來說是常見一個分布式文件系統的一個讀取實例。
FileSystem通過遠程協議調用NameNode確定文件的前幾個Block的位置。對于每一個Block,Namenode返回含有那個Block?的“元數據”,即文件基本信息;接下來,DataNode按照上文定義的距離來進行排序,如果Client本身就是一個DataNode優先從本地DataNode讀物數據。HDFS實例完成以上工作后,返回一個FSDataInputStream給客戶端,讓其從FSDataInputStream中讀取數據。FSDataInputStream接著包裝一個DFSInputStream用來管理DataNode和NameNode的I/O。
NameNode向客戶端返回一個包含數據信息的地址,客戶端格努詆毀創建一個FSDataInputStream開始對數據進行讀取。
FSDataInputStream根據開始存放的前幾個Blocks的DataNode的地址,連接到最近的DataNode上對數據開始從頭讀取。客戶端反復調用read()方法,以流式方式從DataNode讀取數據
當讀到Block的結尾的時候,FSDataInputStream會關閉當前DataNode的地址,然后查找能夠讀取下一個Block的最好的DataNode。這些操作對客戶端是透明的,客戶端感覺到的是連續的流,也就是說讀取的時候就開始查找下一個塊所在的地址。
讀取完成調用close()方法,關閉FSDataInputStream。
Configuration?hdfsConf?= new Configuration();//創建一個hdfs的環境變量
String namenodeURI=”hdfs://hadoop001:8020”;//namenode的統一資源定位符
String username=”root”;//訪問指定用戶的hdfs
FileSystem hdfs = FileSystem.get(new URI(namenodeURI),hdfsConf,username);//創建一個hdfs的文件系統對象
FileSystem local = FileSystem.getLocal(new?Configuration());//創建一個本地的文件系統對象
hdfs.copyToLocalFile(new Path(hdfsPath),new Path(localPath));
Path path = new Path(hdfsFilePath);//文件路徑
FSDataInputStream in = hdfs.open(path);//獲取文件輸入流
FileStatus status = hdfs.getFileStatus(path);//獲取文件的元數據信息
//獲取文件元數據中的文件大小
byte[] bytes = new byte[Integer.pareInt(String.valueOf(status.getLen()))];
//將輸入流中的全部內容一次性讀取出來
in.readFully(0,bytes);
System.out.println(new String(bytes));//將讀取的文件打印輸出
in.close();
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。