第三章-分布式文件系统HDFS
第三章-分布式文件系統HDFS
文章目錄
- 第三章-分布式文件系統HDFS
- HDFS簡介
- HDFS相關概念
- HDFS塊與組件
- 名稱節點
- 第二名稱節點
- 數據節點
- HDFS體系結構
- HDFS存儲原理
- 冗余數據保存
- 數據存取策略
- 數據錯誤與恢復
- HDFS數據讀寫過程
- 讀過程
- 寫過程
HDFS簡介
分布式文件系統把文件分布存儲到多個計算機節點上,成千上萬的計算機節點構成計算機集群。
分布式文件系統在物理結構上是由計算機集群中的多個節點構成的,這些節點分為兩類,一類叫“主節點”(Master Node)或者也被稱為“名稱結點”(NameNode);另一類叫“從節點”(Slave Node)或者也被稱為“數據節點”(DataNode)
總體而言,HDFS要實現以下目標:
- 兼容廉價的硬件設備
- 流數據讀寫
- 大數據集
- 簡單的文件模型
- 強大的跨平臺兼容性
HDFS特殊的設計,在實現上述優良特性的同時, 也使得自身具有一些應用局限性,主要包括以下幾個方面:
- 不適合低延遲數據訪問
- 無法高效存儲大量小文件
- 不支持多用戶寫入及任意修改文件
HDFS相關概念
HDFS塊與組件
HDFS默認一個數據塊 Data Block 64MB/128M,一個文件被分成多個塊,以塊作為存儲單位。塊的大小遠遠大于普通文件系統,以降低分布式尋址開銷,但也不宜過大。
HDFS采用抽象的塊概念可以帶來的明顯的好處:
- 支持大規模文件存儲:一個大規模文件可以被分拆成若干個文件塊,不同的文件塊可以被分發到不同的節點上,不會受到單個節點的存儲容量的限制
- 簡化系統設計:文件塊大小是固定的,很容易計算出一個節點可以存儲的文件塊數以及一個文件的存儲需求,方便元數據管理
- 適合數據備份:每個文件塊都可以冗余存儲到多個節點上, 大大提高了系統的容錯性和可用性
HDFS主要組件的功能:
| 存儲元數據 | 存儲文本內容 |
| 元數據保存在內存中 | 文件內容保存在磁盤 |
| 保存文件,block,datanode之間的映射關系 | 維護了block id到datanode本地文件的映射關系 |
名稱節點
在HDFS中,名稱節點(NameNode)保存了兩個核心的數據結構,即 FsImage 和 EditLog
- FsImage維護文件樹以及文件樹中所有的文件和文件夾的元數據
- EditLog中記錄了所有針對文件的創建、刪除、重命名等操作
FsImage文件:包含文件系統中所有目錄和文件的元數據信息,如修改和訪問時間、訪問權限、分塊情況等。FsImage文件沒有記錄文件包含的每個塊存儲在哪個數據節點,文件塊位置信息只存儲在內存中。
當數據節點加入HDFS集群時,數據節點會把自己所包含的塊列表告知給名稱節點,此后會定期執行這種告知操作,以確保名稱節點的塊映射是最新的。
在名稱節點啟動的時候,它會將FsImage文件中的內容加載到內存中,之后再執行EditLog文件中的各項操作,使得內存中的元數據和實際的同步。一旦在內存中成功建立文件系統元數據的映射,則創建一個新的FsImage文件和一個空的EditLog 文件。
名稱節點在啟動的過程中處于“安全模式”,只提供讀操作,不提供寫操作。啟動過程結束后,系統就會退出安全模式,進入正常運行狀態,對外提供讀寫操作。
名稱節點啟動成功并進入到正常運行狀態以后,HDFS中的更新操作會重新寫到EditLog文件中, 而不是FsImage。
- 因為FsImage文件一般都很大(GB級別的很常見),如果所有的更新操作都往FsImage文件中添加,這樣會導致系統運行的十分緩慢,相對而言,EditLog 要小很多,寫入EditLog是更加高效的
- 每次執行寫操作之后,且在向客戶端發送成功代碼之前, EditLog文件都需要同步更新
在名稱節點運行期間,HDFS的所有更新操作都是直接寫到EditLog中,久而久之, EditLog文件將會變得很大。
在名稱節點重啟的時候,名稱節點需要先將 FsImage 里面的所有內容映像到內存中,然后再一條一條地執行 EditLog中的記錄,當EditLog文件非常大的時候,會導致名稱節點啟動操作非常慢,而在這段時間內HDFS系統處于安全模式,一直無法對外提供寫操作,影響了用戶的使用。因此,Hadoop官方提出了第二名稱節點(SecondaryNameNode)的概念。
第二名稱節點
第二名稱節點用途主要是防止日志文件 EditLog過大,導致名稱節點失敗恢復時消耗過多時間 。第二名稱節點不是熱備份,只是附帶起到冷備份的功能。
SecondaryNameNode的工作情況:
數據節點
數據節點是分布式文件系統HDFS的工作節點,負責數據的存儲和讀取,會根據客戶端或者是名稱節點的調度來進行數據的存儲和檢索,并且向名稱節點定期發送自己所存儲的塊的列表。
每個數據節點中的數據會被保存在各自節點的本地 Linux文件系統中。
HDFS體系結構
HDFS采用了主從(Master/Slave)結構模型,一個 HDFS集群包括一個名稱節點(NameNode)和若干個數據節點(DataNode)。
名稱節點作為中心服務器,負責管理文件系統的命名空間及客戶端對文件的訪問。
集群中的數據節點一般是一個節點運行一個數據節點進程,負責處理文件系統客戶端的讀/寫請求,在名稱節點的統一調度下進行數據塊的創建、刪除和復制等操作。每個數據節點會周期性的向名稱節點報告自己的狀態,沒有按時報告的數據節點會被標記為“宕機”,不再給它分配I/O請求。
HDFS使用的是傳統的分級文件體系,因此,用戶可以像使用普通文件系統一樣,創建、刪除目錄和文件,在目錄間轉移文件,重命名文件等。
HDFS存儲原理
機架感知(Rack Awareness)
- 機架內的機器之間的網絡速度通常都會高于跨機架機 器之間的網絡速度,并且機架之間機器的網絡通信通 常受到上層交換機間網絡帶寬的限制
- 希望不同節點之間的通信能夠盡量發生在同一個機架之內,而不是跨機架
- 為了提高容錯能力,名稱節點會盡可能把數據塊的副本放到多個機架上
冗余數據保存
作為一個分布式文件系統,為了保證系統的容錯性和可用性,HDFS采用了多副本方式對數據進行冗余存儲,通常一個數據塊的多個副本會被分布到不同的數據節點上
- 加快數據傳輸速度
- 容易檢查數據錯誤
- 保證數據可靠性
數據存取策略
數據存放:
- 第一個副本:如果是集群內發起寫操作請求,放置在發起請求的數據節點上;如果來自集群外,隨機挑選一臺磁盤不太滿、CPU不太忙的節點
- 第二個副本:放置在與第一個副本不同的機架的節點上
- 第三個副本:與第二個副本相同機架的其他節點上
- 更多副本:隨機節點
數據讀取:就近原則
- 當客戶端讀取數據時,從名稱節點獲得數據塊不同副本的存放位置列表,列表中包含了副本所在的數據節點,開啟機架感知后可以確定客戶端和這些數據節點所屬的機架ID
- 當發現某個數據塊副本對應的機架ID和客戶端對應的機架ID相同時,就優先選擇該副本讀取數據,如果沒有發現,就隨機選擇一個副本讀取數據
數據錯誤與恢復
HDFS部署在大規模的集群上,并且可以兼容廉價的硬件,它把硬件出錯看作一種常態,而不是異常,并設計了相應的機制檢測數據錯誤和進行自動恢復,主要包括以下幾種情形:名稱節點出錯、數據節點出錯和數據出錯。
- 名稱節點出錯
- 名稱節點保存了所有的元數據信息,其中,最核心的兩大數據結構是 FsImage和 Editlog,如果這 兩個文件發生損壞,那么整個HDFS實例將失效。
- HDFS設置了備份機制,把這些核心文件備份到第二名稱節點 SecondaryNameNode上。當名稱節點出錯時,就可以根據備份服務器中的 FsImage和 Editlog數據進行恢復,但需要暫停服務一段時間
- 數據節點出錯
- 每個數據節點會定期向名稱節點發送“心跳”信息,向名稱節點報告自己的狀態
- 當數據節點發生故障,或者網絡發生斷網時,名稱節點就無法收到來自一些數據節點的心跳信息,這時,這些數據節點就會被標記為“宕機”,節點上面的所有數據都會被標記為“不可讀”,名稱節點不會再給它們發送任何I/O請求
- 這時,有可能出現一種情形,即由于一些數據節點的不可用,會導致一些數據塊的副本數量小于冗余因子。名稱節點會定期檢查這種情況,一旦發現某個數據塊的副本數量小于冗余因子,就會啟動數據冗余復制,為它生成新的副本
- HDFS和其它分布式文件系統的最大區別就是可以調整冗余數據的位置(負載嚴重不均衡時也可做調整)
- 數據出錯
- 網絡傳輸和磁盤錯誤等因素,都會造成數據錯誤
- 客戶端在讀取到數據后,會對數據塊進行校驗,以確定讀取到正確的數據
- 在文件被創建時,客戶端就會對每一個文件塊進行信息摘錄,并把這些信息寫入到同一個路徑的隱藏文件里面
- 當客戶端讀取文件的時候,會先讀取該信息文件。然后,利用該信息文件對每個讀取的數據塊進行校驗,如果校驗出錯,客戶端就會請求到另外一個數據節點讀取該文件塊,并且向名稱節點報告這個文件塊有錯誤,名稱節點會定期檢查并且重新復制這個文件塊
HDFS數據讀寫過程
FileSystem是一個通用文件系統的抽象基類,可以被分布式文件系統繼承,所有可能使用 Hadoop文件系統的代碼,都要使用這個類。Hadoop為 FileSystem這個抽象類提供了多種具體實現,DistributedFileSystem就是 FileSystem在 HDFS文件系統中的具體實現。
FileSystem的 open( )方法返回的是一個輸入流 FSDataInputStream對象,在HDFS文件系統中,具體的輸入流就是DFSInputStream。FileSystem中的 create( )方法返回的是一個輸出流 FSDataOutputStream對象,在 HDFS文件系統中,具體的輸出流就是 DFSOutputStream。
事實上,這些具體的輸入輸出流都已經被封裝在了 FSDataInputStream/FSDataOutputStream對象中了,直接使用這兩個對象即可。
讀過程
讀數據的流程:
- 1.打開文件
- Configuration conf = new Configuration( );
- FileSystem fs = FileSystem.get(conf);
- FSDataInputStream in = fs.open(new Path(uri));
- 2.獲取數據塊信息
- 通過ClientProtocal.getBlockLocations( ) 遠程調用名稱節點,獲得文件開始部分數據塊的位置。對于該數據塊,名稱節點返回保存該數據塊的所有數據節點的地址,并根據距離客戶端遠近進行排序
- 3.讀取請求
- 客戶端獲得輸入流 FSDataInputStream以后,調用read( )函數開始讀取數據。輸入流根據前面的排序結果,選擇距離客戶端最近的數據節點,建立連接并讀取數據
- 4.讀取數據
- 數據從數據節點讀到客戶端,當該數據塊讀取完畢時,FSDataInputStream關閉和該數據節點的連接。
- 如果系統中還有數據需要讀取,則轉至第3步繼續查找下一個數據塊,接著讀入數據,直到所有數據塊都讀取完畢。
- 5.關閉文件
讀數據實例:
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path;import java.io.BufferedReader; import java.io.InputStreamReader;public class HDFSReadFile { public static void main(String[] args) { try{ Configuration conf = new Configuration();conf.set("fs.defaultFS", "hdfs://localhost:9000");FileSystem fs = FileSystem.get(conf);Path filename = new Path("input/localfile.txt");//Path filename = new Path("hdfs://localhost:9000/user/bigdata/input/localfile.txt");FSDataInputStream is = fs.open(filename);BufferedReader d = new BufferedReader(new InputStreamReader(is));String content = d.readLine();System.out.println(content);d.close();s.close(); }catch (Exception e){e.printStackTrace(); } } }寫過程
寫數據的流程:
- 1.創建文件請求
- Configuration conf = new Configuration( );
- FileSystem fs = FileSystem.get(conf);
- FSDataOutputStream out = fs.create(new Path(uri));
- 2.創建文件元數據
- RPC遠程調用名稱節點,在文件系統的命名空間中新建一個文件,名稱節點會執行一些檢查(文件是否存在,客戶端權限)
- 3.寫入數據
- 數據被分成一個個分包,分包被放入 DFSOutputStream對象的內部隊列。DFSOutputStream向名稱節點申請保存數據塊的若干數據節點
- 4.寫入數據包
- 這些數據節點形成一個數據流管道,隊列中的分包最后被打包成數據包,發往數據流管道中的第一個數據節點。第一個數據節點將數據包發送到第二個節點,依此類推,形成“流水線復制”
- 5.接受確認包
- 為了保證節點數據準確,接收到數據的數據節點要向發送者發送“確認包”。確認包沿著數據流管道逆流而上,經過各個節點最終到達客戶端。客戶端收到應答時,它將對應的分包從內部隊列移除
- 不斷執行步驟3-5,直到數據全部寫完
- 6.關閉文件
- DFSOutputStream調用 ClientProtocal.Complete( )方法通知名稱節點關閉文件
寫數據實例:
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path;public class HDFSWriteFile { public static void main(String[] args) { try{ Configuration conf = new Configuration();conf.set("fs.defaultFS", "hdfs://localhost:9000");FileSystem fs = FileSystem.get(conf); String filename = "newfile.txt"; FSDataOutputStream os = fs.create(new Path(filename));os.writeChars("This is a new file."); System.out.println("Create File:" + filename);os.close(); fs.close(); } catch (Exception e){e.printStackTrace(); } } }總結
以上是生活随笔為你收集整理的第三章-分布式文件系统HDFS的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第二章-大数据处理框Hadoop
- 下一篇: 第四章-分布式数据库HBase