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。