1. 程式人生 > >HDFS檔案元資料資訊管理模組

HDFS檔案元資料資訊管理模組

設計思想

HDFS中對資料儲存的最小單位為block,HDFS會將其儲存的大檔案打散成很多64M大小的block,並將這些block分別儲存在叢集中datanode機器上。伺服器namenode主要儲存檔案元資料資訊(檔案目錄結構,具體檔案由那些block組成),該部分主要涉及的關鍵物件為:INode,INodeFile,INodeDirectory,Block,BlockInfo,FSDirectory

NameNode主要負責儲存檔案目錄結構以及具體檔案由那些block組成這些元資料基本資訊,以上物件存在於namenode上。上述物件的主要關係如下。

INode

INode是抽象基類,從字面上能夠了解到它表示一個檔案屬性目錄結構中的一個節點,它包含的主要屬性為:

  //節點名稱

protectedbyte[] name;

  //父節點

protected INodeDirectory parent;

//最後修改時間

protectedlongmodificationTime;

//訪問時間

protectedlongaccessTime;

//訪問許可權(同linux 0777,0666 之類)

privatelongpermission;

INodeFile

INodeFile繼承自INode,表示檔案節點。 包含的主要屬性如下:

 //該檔案中包含的所有Block,這些物件並不包含實際的檔案block內容,主要的屬性為blocks,後續通過blockID和時間戳資訊可以找到這些Block存在哪臺datanode機器上,客戶端直接與該datanode建立連結,請求這個BockID對應的Block中具體檔案內容資料(後續再講,該欄位為關鍵欄位)

protected BlockInfo blocks[] = null;

 //block的複製個數

protectedshortblockReplication;

 //預設block大小

protectedlongpreferredBlockSize;

 INodeDirectory

INodeDirectory同樣繼承自INode,表示檔案目錄節點,主要包含的屬性如下:

 //該檔案目錄下所有的子節點資訊

private List<INode> children;

Block

publicclassBlockimplements Writable, Comparable<Block

>

 Block本身是一個抽象概念,就表示HDFS中一個最小儲存單元,其主要包含的屬性如下:

 //BlockID標識

privatelongblockId;

//這個Block包含多少位元組資料

privatelongnumBytes;

 //一個時間戳,表示Block的版本

privatelonggenerationStamp;

 注:這個Block物件只是一個抽象的概念(你可以理解為一個數據塊的標識,一個儲存單元的標識),這個物件並不包含實際Block資料。

Block資訊的讀取就是client通過網路傳遞一個序列化的block物件到DataNode,DataNode在本機中的讀取這個Block對應的儲存檔案,返回給客戶端。

Block是一個實現了Writable, Comparable<Block>的物件。說明Block物件可以進行序列化並通過網路進行傳輸,DataNode也可以通過HashMap的方式將Block與實際的儲存檔案進行對應關聯。

 BlockInfo

 BlockInfo繼承自Block,其包含的主要屬性如下:

 //該Block所屬的檔案

private INodeFile          inode;

/**

*Thisarraycontainstripletsofreferences.

*Foreachi-thdata-nodetheblockbelongsto

*triplets[3*i]isthereferencetotheDatanodeDescriptor

*andtriplets[3*i+1]andtriplets[3*i+2]arereferences

*tothepreviousandthenextblocks,respectively,inthe

*listofblocksbelongingtothisdata-node.

*/

private Object[] triplets

triplets是一個關鍵欄位。

通過triplets[3*i+1] 和 triplets[3*i+2]可以得到某臺datanode機器上所有的block列表,triplets[3*i+1] triplets[3*i+2]為BlockInfo型別物件

該項功能主要應用在DatanodeDescriptor例項的

private volatile BlockInfo blockList = null 這個欄位中

通過triplets[3*i]可以得到這個Block其他副本的所屬datanode的位置,triplets[3*i]DatanodeDescriptor型別物件

抓住BlockInfo就抓住了整個HDFS按Block進行檔案分散式儲存的關鍵。

BlockInfo資訊中不僅包括了一個Block都儲存在哪些DataNode上,還包含了某個具體datanode上儲存的所有Block資訊,以及該block屬於哪一個INodeFile。使用者需要讀取檔案時首先通過INodeFile得到這個檔案所有的Block---INodeFile中BlockInfo[] getBlocks() 方法。通過BlockInfo又可以得到Block儲存的DataNodeInfo列表。 使用者就可以向得到的DataNode列表的機器傳送讀取Block具體資料的請求(這部分具體實現後面再講)。

在系統執行過程中,上述關鍵物件主要儲存在記憶體中,也就是說HDFS的Namenode有一個記憶體映象,其中的內容就是以上物件組成的樹形結構,也許有人會問,如果Namenode當機會出現什麼問題呢?這個問題問得好:)(具體的解決辦法後續會詳細講解,目前先提一下)

HDFS為了能夠保證資料安全性,完整性,採用和資料庫一樣的容災機制,記錄資料操作行為日誌:對應的功能物件為FSEditLog 。 

系統定時將記憶體中的檔案系統結構映象序列化到磁碟(FsImage),並刪除當前的EditLog 。 如果系統機器重啟,Namenode會從映象檔案中讀取目錄結構資訊,同時執行EditLog中記錄的操作,用以恢復最新的記憶體映象。 

FSDirectory

FSdirectory的一個主要作用是就是上述所說的從映象檔案中讀取目錄結構資訊,同時執行EditLog中記錄的操作,用以恢復最新的記憶體映象。

FSdirectory另一個主要作用就是操作INodeDirectory,INodeFile物件,對檔案系統的目錄,檔案以及檔案包含的Block進行操作。FSdirectory有一個關鍵屬性:rootDir這個物件是整個檔案系統的根目錄。

該物件涉及的主要方法如下:

voidloadFSImage(Collection<File> dataDirs, Collection<File> editsDirs,StartupOption startOpt) throws IOException

boolean mkdirs(String src, PermissionStatus permissions,

boolean inheritPermission, long now)

Block addBlock(String path, INode[] inodes, Block block) throws IOException

private <T extends INode> T addChild(INode[] pathComponents, int pos,T child, long childDiskspace, boolean inheritPermission)

throws QuotaExceededException

INodeFileUnderConstruction

這個類繼承自INodeFile,它的例項代表一個正在處於寫入狀態的檔案,新檔案的建立和檔案的追加(檔案追加目前HDFS支援不是很好)時都會使用到這個物件,INode有一個方法booleanisUnderConstruction(),如果這個方法返回true,表示這個物件目前處於寫入狀態,可以將這個物件引用轉化為INodeFileUnderConstruction

當檔案處於isUnderConstruction狀態時,往往就和檔案租約產生關聯,因為檔案的寫入操作都會首先實現申請一個租約(租約有專門一章進行講解),從FSNameSystem的startFileInternal()方法中的部分邏輯程式碼可以看出端倪

//首先判斷檔案是否存在,並且處於檔案寫入狀態

if (myFile != null && myFile.isUnderConstruction())

{

//轉換檔案為INodeFileUnderConstruction型別

INodeFileUnderConstruction pendingFile = 

(INodeFileUnderConstruction) myFile;

// If the file is under construction , then it must be in our

// leases. Find the appropriate lease record.

//如果檔案處於寫入狀態一定有租約與之對應

Lease lease = 

leaseManager.getLease(new StringBytesWritable(holder));

下面我們分析一下INodeFileUnderConstruction關鍵屬性以及方法

INodeFile這個物件僅僅表示一個檔案節點,它的大部分屬性都是與BlockInfo相關的。

INodeFileUnderConstruction就會有一些檔案建立以及追加時必要的資訊,,詳細如下:

//這個屬性表示當前檔案的租約屬主是哪次應用

StringBytesWritable clientName = null// lease holder

StringBytesWritable clientMachine = null;

//client很可能也是datanode其中之一

DatanodeDescriptor clientNode = null// if client is a cluster node too.

//這個屬性主要應用於block的recover操作(該操作後續會詳細描述

privateintprimaryNodeIndex = -1; // the node working on lease recovery

//檔案最後一個block需要寫入的機器,這是很重要的屬性,也是顯而易見的,檔案的追加寫入一定是對最後一個Block進行操作

private DatanodeDescriptor[] targets = null// locations for last block

privatelonglastRecoveryTime = 0;

下面看一個很重要的方法,這個方法後續會詳細描述。

void assignPrimaryDatanode()

當檔案寫入過程中,很可能在某些datanode上寫入失敗,這就需要對block進行recover操作,而恢復操作中的主節點就是那些寫入正常的datanode。