hdfs读写流程_深度探索Hadoop分布式文件系统(HDFS)数据读取流程
一、開篇
Hadoop分布式文件系統(HDFS)是Hadoop大數據生態最底層的數據存儲設施。因其具備了海量數據分布式存儲能力,針對不同批處理業務的大吞吐數據計算承載力,使其綜合復雜度要遠遠高于其他數據存儲系統。
因此對Hadoop分布式文件系統(HDFS)的深入研究,了解其架構特征、讀寫流程、分區模式、高可用思想、數據存儲規劃等知識,對學習大數據技術大有裨益,尤其是面臨開發生產環境時,能做到胸中有數。
本文重點從客戶端讀取HDFS數據的角度切入,通過Hadoop源代碼跟蹤手段,層層撥開,漸漸深入Hadoop機制內部,使其讀取流程逐漸明朗化。
二、HDFS數據讀取整體架構流程如上圖所示:描繪了客戶端訪問HDFS數據的簡化后整體架構流程。客戶端向hdfs namenode節點發送Path文件路徑的數據訪問的請求
Namenode會根據文件路徑收集所有數據塊(block)的位置信息,并根據數據塊在文件中的先后順序,按次序組成數據塊定位集合(located blocks),回應給客戶端
客戶端拿到數據塊定位集合后,創建HDFS輸入流,定位第一個數據塊所在的位置,并讀取datanode的數據流。之后根據讀取偏移量定位下一個datanode并創建新的數據塊讀取數據流,以此類推,完成對HDFS文件的整個讀取。
1. 首先我們先從一個hdfs-site.xml配置看起
????dfs.client.failover.proxy.provider.fszx
????org.apache.hadoop.hdfs.server.namenode.ha.
????ConfiguredFailoverProxyProvider
配置中定義了namenode代理的提供者為ConfiguredFailoverProxyProvider。什么叫namenode代理?其實本質上就是連接namenode服務的客戶端網絡通訊對象,用于客戶端和namenode服務端的交流。2. 分析ConfiguredFailoverProxyProvider
上圖是ConfiguredFailoverProxyProvider的繼承關系,頂端接口是FailoverProxyProvider,它包含了一段代碼:??/**
???*?Get?the?proxy?object?which?should?be?used?until?the?next?failover?event
???*?occurs.
???*?@return?the?proxy?object?to?invoke?methods?upon
???*/
??public?ProxyInfo?getProxy();
這個方法返回的ProxyInfo就是namenode代理對象,當然客戶端獲取的ProxyInfo整個過程非常復雜,甚至還用到了動態代理,但本質上就是通過此接口拿到了namenode代理。3. 此時類關系演化成如下圖所示:
上圖ProxyInfo就是namenode的代理類,繼承的子類NNProxyInfo就是具體指定是高可用代理類。4. 那么費了這么大勁搞清楚的namenode代理,它的作用在哪里呢?
這就需要關注一個極為重要的對象DFSClient了,它是所有客戶端向HDFS發起輸入輸出流的起點,如下圖所示:上圖實線代表了真實的調用過程,虛線代表了對象之間的間接關系。我們可以看到DFSClient是一個關鍵角色,它由分布式文件系統對象(DistributeFileSystem)初始化,并在初始化中調用NameNodeProxiesClient等一系列操作,實現了高可用NNproxyInfo對象創建,也就是namenode代理,并最終作為DFSClient對象的一個成員,在創建數據流等過程中使用。(二) ?讀取文件流的深入源代碼探索1. 首先方法一樣,先找一個切入口。建立從HDFS下載文件到本地的一個簡單場景,以下是代碼片段
……
//打開HDFS文件輸入流
input?=?fileSystem.open(new?Path(hdfs_file_path));
//創建本地文件輸出流
output?=?new?FileOutputStream(local_file_path);
//通過IOUtils工具實現數據流字節循環復制
IOUtils.copyBytes(input,?output,?4096,?true);
……
咱們再看看IOUtils的一段文件流讀寫的方法代碼。/**
???*?Copies?from?one?stream?to?another.
???*?
???*?@param?in?InputStrem?to?read?from
???*?@param?out?OutputStream?to?write?to
???*?@param?buffSize?the?size?of?the?buffer?
???*/
??public?static?void?copyBytes(InputStream?in,?OutputStream?out,?int?buffSize)?
????throws?IOException?{
??????PrintStream?ps?=?out?instanceof?PrintStream??
???????(PrintStream)out?:?null;
??????byte?buf[]?=?new?byte[buffSize];
??????int?bytesRead?=?in.read(buf);
??????while?(bytesRead?>=?0)?{
??????out.write(buf,?0,?bytesRead);
??????if?((ps?!=?null)?&&?ps.checkError())?{
??????????throw?new?IOException("
??????????Unable?to?write?to?output?stream.");
??????}
??????bytesRead?=?in.read(buf);
????}
??}
這段代碼是個標準的循環讀取HDFS InputStream數據流,然后向本地文件OutputStream輸出流寫數據的過程。我們的目標是深入到HDFS InputStream數據流的創建和使用過程。
2. 接下來我們開始分析InputStream的產生過程,如下圖所示:
上圖實線代表了真實的調用過程,虛線代表了對象之間的間接關系。其代碼內部結構極為復雜,我用此圖用最簡化的方式讓我們能快速的理解清楚他的原理。我來簡單講解一下這個過程:第一步?
第二步?
第三步
3. 最后我們再深入到數據塊讀取機制的源代碼上看看,如下圖所示:
上圖實線代表了真實的調用過程,虛線代表了對象之間的間接關系。實際的代碼邏輯比較復雜,此圖也是盡量簡化展現,方便我們理解。一樣的,我來簡單講解一下這個過程:第一步?
第二步?
第三步?
總結
以上是生活随笔為你收集整理的hdfs读写流程_深度探索Hadoop分布式文件系统(HDFS)数据读取流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 红黑树中nil结点_什么是红黑树?程序员
- 下一篇: windows server 驱动精灵_