【Hadoop】NameNode 詳解
簡(jiǎn)介
NameNode管理著(zhù)整個(gè)HDFS文件系統的元數據。
從架構設計上看,元數據大致分成兩個(gè)層次:Namespace管理層,負責管理文件系統中的樹(shù)狀目錄結構以及文件與數據塊的映射關(guān)系;
塊管理層,負責管理文件系統中文件的物理塊與實(shí)際存儲位置的映射關(guān)系BlocksMap,如圖1所示。
Namespace管理的元數據除內存常駐外,也會(huì )周期Flush到持久化設備上FsImage文件;BlocksMap元數據只在內存中存在;
當NameNode發(fā)生重啟,首先從持久化設備中讀取FsImage構建Namespace,之后根據DataNode的匯報信息重新構造BlocksMap。
這兩部分數據結構是占據了NameNode大部分JVM Heap空間。
除了對文件系統本身元數據的管理之外,NameNode還需要維護整個(gè)集群的機架及DataNode的信息、Lease管理以及集中式緩存引入的緩存管理等等。
這幾部分數據結構空間占用相對固定,且占用較小。
內存全景
NameNode整個(gè)內存結構大致可以分成四大部分:Namespace、BlocksMap、NetworkTopology及其它
- Namespace:維護整個(gè)文件系統的目錄樹(shù)結構及目錄樹(shù)上的狀態(tài)變化;
- BlockManager:維護整個(gè)文件系統中與數據塊相關(guān)的信息及數據塊的狀態(tài)變化;
- NetworkTopology:維護機架拓撲及DataNode信息,機架感知的基礎;
- 其他:
- LeaseManager:讀寫(xiě)的互斥同步就是靠Lease實(shí)現,支持HDFS的Write-Once-Read-Many的核心數據結構;
- CacheManager:Hadoop 2.3.0引入的集中式緩存新特性,支持集中式緩存的管理,實(shí)現memory-locality提升讀性能;
- SnapshotManager:Hadoop 2.1.0引入的Snapshot新特性,用于數據備份、回滾,以防止因用戶(hù)誤操作導致集群出現數據問(wèn)題;
- DelegationTokenSecretManager:管理HDFS的安全訪(fǎng)問(wèn); 另外還有臨時(shí)數據信息、統計信息metrics等等
NameNode常駐內存主要被Namespace和BlockManager使用,二者使用占比分別接近50%。其它部分內存開(kāi)銷(xiāo)較小且相對固定,與Namespace和BlockManager相比基本可以忽略。
內存分析
HDFS對文件系統的目錄結構也是按照樹(shù)狀結構維護,Namespace保存了目錄樹(shù)及每個(gè)目錄/文件節點(diǎn)的屬性。
除在內存常駐外,這部分數據會(huì )定期flush到持久化設備上,生成一個(gè)新的FsImage文件,方便NameNode發(fā)生重啟時(shí),從FsImage及時(shí)恢復整個(gè)Namespace。
下圖所示為Namespace內存結構。前述集群中目錄和文件總量即整個(gè)Namespace目錄樹(shù)中包含的節點(diǎn)總數,可見(jiàn)Namespace本身其實(shí)是一棵非常巨大的樹(shù)。
在整個(gè)Namespace目錄樹(shù)中存在兩種不同類(lèi)型的INode數據結構:INodeDirectory和INodeFile。其中INodeDirectory標識的是目錄樹(shù)中的目錄,INodeFile標識的是目錄樹(shù)中的文件。
由于二者均繼承自INode,所以具備大部分相同的公共信息INodeWithAdditionalFields,除常用基礎屬性外,其中還提供了擴展屬性features,
如Quota、Snapshot等均通過(guò)Feature增加,如果以后出現新屬性也可通過(guò)Feature方便擴展。
不同的是,INodeFile特有的標識副本數和數據塊大小組合的header(2.6.1之后又新增了標識存儲策略ID的信息)及該文件包含的有序Blocks數組;
INodeDirectory則特有子節點(diǎn)的列表children。
這里需要特別說(shuō)明children是默認大小為5的ArrayList,按照子節點(diǎn)name有序存儲,雖然在插入時(shí)會(huì )損失一部分寫(xiě)性能,但是可以方便后續快速二分查找提高讀性能,
對一般存儲系統,讀操作比寫(xiě)操作占比要高。具體的繼承關(guān)系見(jiàn)下圖。
BlockManager
BlocksMap在NameNode內存空間占據很大比例,由BlockManager統一管理,相比Namespace,BlockManager管理的這部分數據要復雜的多。
Namespace與BlockManager之間通過(guò)前面提到的INodeFile有序Blocks數組關(guān)聯(lián)到一起。圖5所示BlockManager管理的內存結構。
每一個(gè)INodeFile都會(huì )包含數量不等的Block,具體數量由文件大小及每一個(gè)Block大?。J為64M)比值決定,這些Block按照所在文件的先后順序組成BlockInfo數組,
如上圖所示的BlockInfo[A~K],BlockInfo維護的是Block的元數據,結構如下圖所示,數據本身是由DataNode管理,所以BlockInfo需要包含實(shí)際數據到底由哪些DataNode管理的信息,
這里的核心是名為triplets的Object數組,大小為3*replicas
,其中replicas是Block副本數量。triplets包含的信息:
- triplets[i]:Block所在的DataNode;
- triplets[i+1]:該DataNode上前一個(gè)Block;
- triplets[i+2]:該DataNode上后一個(gè)Block;
其中i表示的是Block的第i個(gè)副本,i取值[0,replicas)。
為了快速通過(guò)blockid快速定位Block,引入了BlocksMap。
BlocksMap底層通過(guò)LightWeightGSet實(shí)現,本質(zhì)是一個(gè)鏈式解決沖突的哈希表。
為了避免rehash過(guò)程帶來(lái)的性能開(kāi)銷(xiāo),初始化時(shí),索引空間直接給到了整個(gè)JVM可用內存的2%,并且不再變化。
NameNode內存中所有數據都要隨讀寫(xiě)情況發(fā)生變化,BlockManager當然也需要管理這部分動(dòng)態(tài)數據。
當Block發(fā)生變化不符合預期時(shí)需要及時(shí)調整Blocks的分布。這里涉及幾個(gè)核心的數據結構:
- excessReplicateMap: 某個(gè)Block實(shí)際存儲的副本數多于預設副本數,這時(shí)候需要刪除多余副本,這里多余副本會(huì )被置于excessReplicateMap中。
excessReplicateMap是從DataNode的StorageID到Block集合的映射集。 - neededReplications: 若某個(gè)Block實(shí)際存儲的副本數少于預設副本數,這時(shí)候需要補充缺少副本,這里哪些Block缺少多少個(gè)副本都統一存在neededReplications里,
本質(zhì)上neededReplications是一個(gè)優(yōu)先級隊列,缺少副本數越多的Block之后越會(huì )被優(yōu)先處理。 - invalidateBlocks: 若某個(gè)Block即將被刪除,會(huì )被置于invalidateBlocks中。
invalidateBlocks是從DataNode的StorageID到Block集合的映射集。如某個(gè)文件被客戶(hù)端執行了刪除操作,該文件所屬的所有Block會(huì )先被置于invalidateBlocks中。 - corruptReplicas:有些場(chǎng)景Block由于時(shí)間戳/長(cháng)度不匹配等等造成Block不可用,會(huì )被暫存在corruptReplicas中,之后再做處理。
BlockManager內部的ReplicationMonitor線(xiàn)程會(huì )持續從其中取出數據并通過(guò)邏輯處理后分發(fā)給具體的DatanodeDescriptor對應數據結構,
當對應DataNode的心跳過(guò)來(lái)之后,NameNode會(huì )遍歷DatanodeDescriptor里暫存的數據,將其轉換成對應指令返回給DataNode,DataNode收到任務(wù)并執行完成后再反饋回NameNode,
之后DatanodeDescriptor里對應信息被清除。
NetworkTopology
NameNode不僅需要管理所有DataNode,由于數據寫(xiě)入前需要確定數據塊寫(xiě)入位置,NameNode還維護著(zhù)整個(gè)機架拓撲N(xiāo)etworkTopology。
包含兩個(gè)部分:機架拓撲結構NetworkTopology和DataNode節點(diǎn)信息。
其中樹(shù)狀的機架拓撲是根據機架感知(一般都是外部腳本計算得到)在集群?jiǎn)?dòng)完成后建立起來(lái),整個(gè)機架的拓撲結構在NameNode的生命周期內一般不會(huì )發(fā)生變化;
另一部分是比較關(guān)鍵的DataNode信息,BlockManager已經(jīng)提到每一個(gè)DataNode上的Blocks集合都會(huì )形成一個(gè)雙向鏈表,
更準確的應該是DataNode的每一個(gè)存儲單元DatanodeStorageInfo上的所有Blocks集合會(huì )形成一個(gè)雙向鏈表,這個(gè)鏈表的入口就是機架拓撲結構葉子節點(diǎn)即DataNode管理的DatanodeStorageInfo。
LeaseManager
Lease 機制是重要的分布式協(xié)議,廣泛應用于各種實(shí)際的分布式系統中。HDFS支持Write-Once-Read-Many,對文件寫(xiě)操作的互斥同步靠Lease實(shí)現。
Lease實(shí)際上是時(shí)間約束鎖,其主要特點(diǎn)是排他性??蛻?hù)端寫(xiě)文件時(shí)需要先申請一個(gè)Lease,一旦有客戶(hù)端持有了某個(gè)文件的Lease,其它客戶(hù)端就不可能再申請到該文件的Lease,
這就保證了同一時(shí)刻對一個(gè)文件的寫(xiě)操作只能發(fā)生在一個(gè)客戶(hù)端。NameNode的LeaseManager是Lease機制的核心,
維護了文件與Lease、客戶(hù)端與Lease的對應關(guān)系,這類(lèi)信息會(huì )隨寫(xiě)數據的變化實(shí)時(shí)發(fā)生對應改變。
上圖為為L(cháng)easeManager內存結構,包括以下三個(gè)主要核心數據結構:
- sortedLeases:Lease集合,按照時(shí)間先后有序組織,便于檢查L(cháng)ease是否超時(shí);
- leases:客戶(hù)端到Lease的映射關(guān)系;
- sortedLeasesByPath:文件路徑到Lease的映射關(guān)系;
其中每一個(gè)寫(xiě)數據的客戶(hù)端會(huì )對應一個(gè)Lease,每個(gè)Lease里包含至少一個(gè)標識文件路徑的Path。
Lease本身已經(jīng)維護了其持有者(客戶(hù)端)及該Lease正在操作的文件路徑集合,之所以增加了leases和sortedLeasesByPath為提高通過(guò)Lease持有者或文件路徑快速索引到Lease的性能。
當Lease發(fā)生超時(shí)后需要強制回收,內存中與該Lease相關(guān)的內容要被及時(shí)清除。超時(shí)檢查及超時(shí)后的處理邏輯由LeaseManager.Monitor統一執行。
LeaseManager中維護了兩個(gè)與Lease相關(guān)的超時(shí)時(shí)間:軟超時(shí)(softLimit)和硬超時(shí)(hardLimit),使用場(chǎng)景稍有不同。
客戶(hù)端向集群寫(xiě)文件前需要向NameNode的LeaseManager申請Lease;寫(xiě)文件過(guò)程中定期更新Lease時(shí)間,以防Lease過(guò)期,周期與softLimit相關(guān);寫(xiě)完數據后申請釋放Lease。
整個(gè)過(guò)程可能發(fā)生兩類(lèi)問(wèn)題:
(1)寫(xiě)文件過(guò)程中客戶(hù)端沒(méi)有及時(shí)更新Lease時(shí)間;
(2)寫(xiě)完文件后沒(méi)有成功釋放Lease。
兩個(gè)問(wèn)題分別對應為softLimit和hardLimit。兩種場(chǎng)景都會(huì )觸發(fā)LeaseManager對Lease超時(shí)強制回收。
如果客戶(hù)端寫(xiě)文件過(guò)程中沒(méi)有及時(shí)更新Lease超過(guò)softLimit時(shí)間后,另一客戶(hù)端嘗試對同一文件進(jìn)行寫(xiě)操作時(shí)觸發(fā)Lease軟超時(shí)強制回收;
如果客戶(hù)端寫(xiě)文件完成但是沒(méi)有成功釋放Lease,則會(huì )由LeaseManager的后臺線(xiàn)程LeaseManager.Monitor檢查是否硬超時(shí)后統一觸發(fā)超時(shí)回收。
