天天看點

《Hadoop技術詳解》一2.4 讀寫資料

本節書摘來異步社群《hadoop技術詳解》一書中的第2章,第2.4節,作者: 【美】eric sammer 譯者: 劉敏 , 麥耀鋒 , 李冀蕾 , 等,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

用戶端可以通過多種不同的工具和應用程式接口(參見2.8節“通路與內建”)對hdfs進行讀寫操作,這些操作都遵循着同樣的流程。在某些層面,用戶端可能要使用到hadoop庫函數,因為隻有hadoop庫函數才清楚知道hdfs的具體細節和相關文法。函數庫封裝了大部分與namenode 和datanode通信相關的細節,同時也考慮了分布式檔案系統在諸多場景中的錯誤處理機制。

首先,我們來看一下hdfs資料讀取操作的處理邏輯。假設,hdfs中已經存儲了一個檔案/user/esammer/foo.txt,要讀取檔案,hadoop用戶端程式庫(通常是java的jar檔案)是必不可少的。同時,用戶端還必須有叢集配置資料的副本,因為它包含了namenode的位置資訊(參見第5章)。如圖2-2所示,用戶端首先要通路namenode,并告訴它所要讀取的檔案,當然,這之前必須對客戶的身份進行确認。客戶身份确認有兩種方式:一種是通過信任的用戶端,由其指定使用者名;第二種方式是通過諸如kerberos(參見第6章)等強認證機制來完成。接下來還必須檢查檔案的所有者及其設定的通路權限。如果檔案确實存在,而且使用者對這個檔案有通路權限,這時namenode就會告訴用戶端這個檔案的第一個資料塊的标号以及儲存有該資料塊的datanode清單。這個清單是根據datanode與用戶端間的距離進行了排序的。用戶端與datanode之間的距離是根據hadoop叢集的機架拓撲結構計算得到的。機架拓撲結構記錄了主機機架位置的配置資訊(有關機架拓撲配置的更多詳情,請參見第5.9節“機架拓撲”)。

在namenode因為自身原因或網絡故障無法通路時,用戶端會收到逾時或異常出錯消息,資料讀取操作也就無法繼續。

有了資料塊标号和datanode的主機名,用戶端便可以直接通路最合适的datanode,讀取所需要的資料塊。這個過程會一直重複直到該檔案的所有資料塊讀取完成或用戶端主動關閉了檔案流。

《Hadoop技術詳解》一2.4 讀寫資料

從datanode讀取資料時,可能會發生程序或主機異常結束的情況。這時,資料讀操作不會停止,hdfs 程式庫會自動嘗試從其他有資料副本的datanode中讀取資料。如果所有資料副本都無法通路,則讀取操作失敗,用戶端收到異常出錯消息。還有一種情況,當用戶端試圖從datanode中讀取資料時,namenode傳回的資料塊位置資訊已經過期。這時如果還有其他datanode儲存有該資料塊副本,用戶端會嘗試從那些datanode中讀取資料,否則至此讀取操作就會失敗。這些情況很少發生,但對hadoop這樣的大規模分布式系統而言,一旦發生,調查分析過程就會異常複雜。第9章将介紹什麼情況可能導緻出錯以及如何診斷這類問題。

hdfs寫資料操作比讀取資料操作要相對複雜些。我們先來看個最簡單的例子:用戶端要在叢集中建立一個新檔案,當然用戶端并不一定要真正實作這裡介紹的邏輯,在這裡隻是作為一個例子來介紹hadoop庫函數是如何将資料寫入到叢集中的。其實應用程式開發人員可以像操作傳統的本地檔案一樣,用他們熟悉的應用程式接口(api)打開檔案、寫入流,然後關閉流即可。

首先,用戶端通過hadoop檔案系統相關api發送請求打開一個要寫入的檔案,如果該使用者有足夠的通路權限,這一請求就會被送到namenode,并在namenode上建立該檔案的中繼資料。剛建立的新檔案中繼資料并未将該檔案和任何資料塊關聯,這時用戶端會收到“打開檔案成功”的響應,然後就可以開始寫入資料了。當然在api層面會傳回一個标準的java流對象,這一實作隻是針對hdfs的。當用戶端将資料寫入流時,資料會被自動拆分成資料包(這裡,不要和tcp資料包或hdfs資料塊混淆),并将資料包儲存在記憶體隊列中。用戶端有一個獨立的線程,它從隊列中讀取資料包,并同時向namenode請求一組datanode清單,以便寫入下一個資料塊的多個副本。接着,用戶端直接連接配接到清單中的第一個datanode,而該datanode又連接配接到第二個datanode,第二個又連接配接到第三個上……這樣就建立了資料塊的複制管道,如圖2-3所示。資料包以流的方式寫入第一個datanode的磁盤,同時傳入管道中的下一個datanode并寫入其磁盤,依此類推。複制管道中的每一個datanode都會确認所收資料包已經成功寫入磁盤。用戶端應用程式維護着一個清單,記錄哪些資料包尚未收到确認消息。每收到一個響應,用戶端便知道資料已經成功地寫入到管道中的一個datanode。當資料塊被寫滿時,用戶端将重新向namenode申請下一組datanodes。最終,用戶端将剩餘資料包全部寫入磁盤,關閉資料流并通知namenode檔案寫操作已經完成。

《Hadoop技術詳解》一2.4 讀寫資料

然而,凡事絕非如此簡單,出現問題在所難免。最常見的情況是,複制管道中的某一datanode無法将資料寫入磁盤(磁盤翹了辮子或datanode當機)。發生這種錯誤時,管道會立即關閉,已發送的但尚未收到确認的資料包會被退回到隊列中,以確定管道中錯誤節點的下遊節點可以獲得資料包。而在剩下的健康資料節點中,正在寫入的資料塊會被配置設定新的id。這樣,當發生故障的資料節點恢複後,備援的資料塊就好像不屬于任何檔案而被自動丢棄,由剩餘資料節點組成的新複制管道會重新開放,寫入操作得以繼續。此時,雨過天晴,寫操作将繼續直至檔案關閉。namenode如果發現檔案的某個資料塊正在複制,就會異步地建立一個新的複制塊,這樣,即便叢集的多個資料節點發生錯誤,用戶端仍然可以從資料塊的副本中恢複資料,前提是滿足要求的最少數目的資料副本已經被正确寫入(預設的最少資料副本是1)。