開源組件系列(6):分佈式文件系統(HDFS)

目錄

(一)概述

(二)文件系統的應用

(三)HDFS基本架構

(四)HDFS關鍵技術

(五)HDFS訪問方式

(六)HDFS Java API


(一)概述

 

在海量數據的業務場景中,我們每天採集的數據通常是GB級別的,系統所存儲的數據通常是TB級別的,甚至是PB級別。爲了應爲數據存儲的管理和擴展問題,大數據集羣通常採用橫向擴展的方式來滿足數據增長的需求,即以網絡互連的節點爲單位擴大存儲容量。爲了構建橫向擴展的分佈式文件系統,通常需要解決如下幾個問題:

1.數據能備份:由於橫向擴展的集羣節點通常採用廉價的服務器,因而出現故障的機率較大,需要分佈式文件系統能夠很好的應對各種問題,也就是有良好的容錯性;

2.存儲大文件:在分佈式文件系統中,存儲GB級別的文件很常見,也可能存儲大量的KB級小文件,這與傳統文件系統的場景很不同,要求大數據集羣在IO方面有良好的性能;

3.一次寫入多次讀取:大多數場景下,文件是追加寫入的,且寫入完成後不會隨機修改,只會讀取。因此,文件的追加操作需要重點保障讀寫性能和原子操作。

在2003年,Google發佈了分佈式文件系統GFS的相關論文,在此基礎上,Apache開源了頂級項目:Hadoop,而HDFS正是Hadoop中的分佈式文件系統,也是GFS的開源實現。

 

(二)文件系統的應用

 

構建分佈式文件系統,通常有兩種方式:文件級別和塊級別。

這裏首先介紹文件級別,通常採用的方案是基於現有文件系統的主從架構:Master/Slave,也就是給定N個網絡節點,每個節點都裝有Linux操作系統,選出一個節點作爲Master,記錄文件的元信息,其他節點作爲Slave,存儲實際文件。

該方案是初級的分佈式文件系統實現,但存在如下兩個難以解決的問題:

1.難以負載均衡:文件級別的分佈式文件系統,以文件爲單位進行存儲,由於用戶的文件大小不統一,因此難以保證每個節點的數據都是均衡的;

2.難以並行處理:如果以文件爲單位進行存儲,當多個分佈在不同節點上的並行任務讀取同一文件時,存儲該文件的節點網絡帶寬便會成爲瓶頸,從而制約上層框架的並行處理效率。

文件級別的分佈式文件系統結構圖如下:

 

爲了解決文件級別的分佈式文件系統存在的問題,我們提出了塊級別的分佈式文件系統,其核心思想是將文件分成等大的數據塊,例如HDFS默認是128MB,並以數據塊爲單位存儲到不同的節點上,進而解決負載均衡和並行處理的問題。如下圖所示:

 

(三)HDFS基本架構

 

HDFS是典型的塊級別分佈式文件系統,主節點被稱爲Namenode,負責管理元信息和子節點,子節點被稱爲Datanode,負責存儲實際的數據塊,如下圖所示:

 

Namenode是HDFS的管理者,主要包括如下功能:

1.管理元信息:Namenode以目錄樹的形式維護整個文件系統目錄、文件的數據塊等信息;

2.管理Datanode:Datanode需要週期性的向Namenode彙報心跳信息,一旦Namenode發現Datanode出現了問題,會在其他存活的Datanode節點上重構丟失的數據塊;

3.HA高可用性:爲了防止Namenode出現問題之後集羣不可用,通常會啓動一個備用的Namenode,實現HA的高可用性;

4.狀態同步:主從Namenode並不是通過強一致的協議保證狀態一致的,而是通過第三方的文件共享存儲系統,主Namenode將EditLog日誌寫入共享存儲系統,從Namenode讀取這些日誌並執行修改操作。

 

Datanode主要是用來對文件數據塊的讀寫。存儲數據塊和塊的校驗,因爲數據在網絡的傳輸中可能存在數據丟失的問題,所以需要校驗。同時,DataNode要保持與NameNode的通信,一般每3秒發送一次心跳包。一般來說,數據是以block存儲在DataNode節點上,在DataNode節點上提交文件,那麼第一個塊就是存儲在這個節點上(選擇最近的一個),如果不是在DataNode節點上提交的,就隨即挑選一個磁盤合適CPU負荷的節點。第二個block存儲在不同機架上的一個節點,假設副本數爲3,那麼第三個block存儲在與第二個block相同機架上的不同節點。

 

 

(四)HDFS關鍵技術

 

HDFS在實現時採用了大量分佈式技術,典型的有如下幾種:

 

1.容錯性設計

HDFS有良好的容錯性設計,以降低節點故障情況下數據丟失的可能性。當Namenode故障時,會導致整個文件系統數據不可用,因此HDFS會爲每個Active Namenode分配一個Standby Namenode,用於故障時備用;當Datanode故障時,由於數據塊的多副本策略,Namenode可以在其他節點上重構故障Datanode上的數據塊;當數據塊損壞時,也就是校驗碼不一致時,Namenode會通過其他節點上的正常副本來重構首受損的數據塊。

 

2.副本放置策略

數據塊副本放置策略決定了每個數據塊多個副本存放節點的選擇,在保證讀寫性能的前提下,儘可能的提高數據的可靠性。副本放置策略與集羣物理拓撲結構直接相關,通常情況下,一個集羣由多個機架構成,每個機架由16~64個物理節點組成,機架內部的節點時通過內部交換機通信的,機架之間的節點時通過外部節點通信的。由於機架間的節點通信需要多層交換機,相比於機架內節點通信,讀寫延遲要高一些。相同機架內部的節點通常是綁定在一起的,多種資源可能是共享的,例如插座、交換機等,因此同時不可用的概率要比不同機架節點高很多。

考慮到集羣物理拓撲結構特點,HDFS默認採用三副本放置策略。當客戶端與Datanode同節點時,上層計算框架處理HDFS數據時,每個任務實際上就是一個客戶端,運行在與Datanode相同的計算節點上,三副本放置策略爲:第一個副本寫到同Datanode上,另外兩個副本寫到相同機架的不同Datanode上。當客戶端與Datanode不同節點時,也就是HDFS之外的應用程序會向HDFS寫數據,例如Flink Sink,HDFS會隨機選擇一個Datanode作爲第一個副本放置節點,其他兩個副本寫到另一個相同機架不同的Datanode上。

 

 

3.異構存儲介質

隨着HDFS的不斷完善,已經從最初的單存儲介質(磁盤)的單一文件系統,演化爲支持異構存儲介質的綜合性分佈式文件系統,使得HDFS能夠很好的利用新型存儲介質,使得HDFS變成了一個提供混合存儲方式的存儲系統,用戶能夠根據自己的業務特點,選擇不同的存儲介質。HDFS目前支持的存儲介質主要包括:

Disk:默認的磁盤介質;

Archive:高存儲密度但耗電較少,通常用來存儲冷數據;

SSD:固態硬盤,新型存儲介質,速度較快;

Ram Disk:數據首先被寫道內存中,同時向該存儲介質中再異步寫一份。

 

4.集中式緩存管理

HDFS允許用戶將一部分目錄或文件緩存在off-heap內存中,以加速對這些數據的訪問效率,該機制被稱爲集中式緩存管理,包括如下幾方面的有點:

提高集羣的內存利用效率:當使用操作系統的緩存時,對一個數據塊的重讀讀會導致所有的副本都會被放到緩衝區中,造成內存浪費,使用集中式緩存,用戶可以指定n個副本的m個被緩存,節約n-m的內存;

防止被頻繁使用的數據從內存中清除:當使用操作系統緩存時,操作系統使用自帶的內存置換算法管理內存,此時容易讓熱數據不斷寫入內存,之後從內存中清除,導致數據訪問速度的不穩定;

提高讀取效率:Datanode緩存統一由Namenode來管理,上層計算框架的調度器查詢數據塊的緩存列表,並通過一定的調度策略將任務儘可能調度到緩存塊所在節點上,以提高數據讀性能;當數據塊被Datanode緩存後,HDFS會使用一個高效的、支持zero-copy的新API加快讀速度,客戶端的開銷基本是0。

 

(五)HDFS訪問方式

 

HDFS提供了兩類shell命令:用戶命令和管理員命令,具體如下:

 

1.用戶命令

HDFS提供了大量用戶命令,常用的有文件操作命令dfs,文件一致性檢查命令fsck和分佈式文件複製命令distcp,具體如下:

 

(1)文件操作命令dfs

文件操作命令是文件系統交互的命令,可以是HDFS,也可以是Hadoop支持的文件系統,語法如下:

$HADOOP_HOME/bin/hadoop fs <args>

所有命令均會接收文件uri作爲參數,如果直接操作HDFS上的文件,也可以使用如下命令:

$HADOOP_HOME/bin/hdfs dfs <args>

除了執行命令的前綴不同,HDFS大部分文件操作命令與Linux自帶命令類似,例如mkdir、rm、mv等。

 

(2)文件一致性檢查命令fsck

fsck命令的用法和參數如下:

 

(3)分佈式文件複製命令distcp

分佈式文件複製命令distcp主要功能包括集羣內文件並行複製和集羣間文件並行複製,例如將/user/gai/從集羣nm1複製到集羣nm2上,加入兩個集羣的版本相同,那麼命令如下:

bin/hadoop/ distcp hdfs://nm1:8020/user/gai hdfs://nm2:8020/user/gai

 

2.管理員命令

管理員命令主要是針對服務生命週期管理的,比如啓動/關閉Namenode/Datanode,HDFS份額管理等,例如啓動和關閉Namenode:

sbin/hadoop-daemon.sh start namenode

sbin/hadoop-daemon.sh stop namenode

 

(六)HDFS Java API

 

例子如下:

/**
 * hdfs入門程序:
 * 面向對象:一切皆對象
 * 文件系統也可以看做是一類事物、FileSystem
 * 
 * 一定有共同的行爲和屬性:
 * 1.屬性--就是--URL
 * 本地文件系統的URL:	file:///c:myProgram
 * HDFS文件系統的URL:	fs.defaultFS=hdfs://hadoop02:9000
 * 2.行爲/方法--就是--上傳和下載
 * 
 * FileSystem類的相關方法:
 * .get()----->靜態方法,用來獲取FileSystem類的這個實例對象的,而不是 做下載的,此方法最少傳一個參數否則要傳三個參數
 */
public class HelloHDFS {
	/**
	 * 從windows上傳和下載到HDFS
	 */
	public static void main(String[] args) throws Exception {
		/**
		 * 插曲:創建對象的方式有五種:
		 * 1.構造方法(一般用這種)
		 * 2.靜態方法(一般用這種)
		 * 3.反射
		 * 4.克隆
		 * 5.反序列化
		 */
		//Configuration是配置對象,conf可以理解爲包含了所有配置信息的一個集合,可以認爲是Map
		//在執行這行代碼的時候底層會加載一堆配置文件 core-default.xml;hdfs-default.xml;mapred-default.xml;yarn-default.xml
		Configuration conf = new Configuration();
		//相當於通過配置文件的key獲取到value的值
		conf.set("fs.defaultFS","hdfs://hadoop02:9000");
		/**
		 * 更改操作用戶有兩種方式:(系統會自動識別我們的操作用戶,如果我們設置,將會報錯會拒絕Administrator用戶(windows用戶))
		 * 1.直接設置運行環境中的用戶名爲hadoop,此方法不方便因爲打成jar包執行還是需要改用戶,右鍵Run As--Run Configurations--Arguments--VM arguments--輸入-DHADOOP_USER_NAME=hadoop
		 * 2.直接在代碼中進行聲明
		 */
		//更改操作用戶爲hadoop 
		System.setProperty("HADOOP_USER_NAME","hadoop");
		//獲取文件系統對象(目的是獲取HDFS文件系統)
		FileSystem fs=FileSystem.get(conf);
		//直接輸出fs對象是org.apache.hadoop.fs.LocalFileSystem@70e8f8e
		//這說明是本地文件系統對象。代碼在eclipse所嵌入的jvm中執行的,jvm是安裝在Windows下的,所以是windows文件系統對象
		//所以要返回來指定HDFS
		System.out.println(fs);
		//上傳的API
		fs.copyFromLocalFile(new Path("c:/ss.txt"), new Path("/a"));
		//下載的API										不改名就不用寫文件名字也行
		fs.copyToLocalFile(new Path("/a/qqq.txt"), new Path("c:/qqq.txt"));
		fs.close();
		/**
		 * .crc 是校驗文件
		 * 每個塊的元數據信息都只會記錄合法的數據起始偏移量。
		 * 如果進行了非法的數據追加,最終是能夠下載正確的數據的。
		 * 如果在數據的中間更改了數據,造成了採用CRC算法計算出來的校驗值和最初存入HDFS的校驗值不一致。HDFS就認爲當前這個文件被損壞了。
		 */
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章