前言
我們知道HDFS Rolling Upgrade功能在幾年前比較早的時間早已實現,但是我們往往只注意怎麼去做HDFS Rolling Upgrade這個事情本身,但是對於HDFS如何實現Rolling Upgrade這個功能可能瞭解的會比較少。本文筆者來聊聊其中部分要點的設計實現,爲了做到Rolling Upgrade的快速和安全性,社區在這塊實現上還是花了一些功夫的。本文主要基於HDFS Rolling Upgrade社區JIRA HDFS-5535:Umbrella jira for improved HDFS rolling upgrades來展開內容進行闡述。
HDFS NameNode端針對Rolling Upgrade的調整
HDFS針對Rolling Upgrade的實現,在NameNode和DataNode兩邊都進行了相關的調整實現。首先我們來看NameNode做了哪些模塊的調整。
第一個,NameNode在pre-upgrade, upgrade in-progress, finalized, downgrade/rollback這些期間
元數據文件的一個狀態處理,包括FsImage文件以及editlog文件。當我們執行Rolling Upgrade的rollback操作時,NN是可以支持撤銷rolling upgrade時的那個transaction後發生的所有transaction。簡單來說,它會忽略掉升級過程中執行過的那些事務transaction。
第二點,Layout的拆分,原有Layout一拆爲二,分別有NameNode和DataNode各自對應的NamenodeLayoutVersion和DatanodeLayoutVersion。Layout內會分別記有NameNode,DataNode這邊的當前版本所支持的各種feature或者標明目錄結構版本的信息,相關JIRA HDFS-5754(Split LayoutVerion into NamenodeLayoutVersion and DatanodeLayoutVersion)
例如以下是NameNode NamenodeLayoutVersion和DataNode DatanodeLayoutVersion的內部信息:
public class NameNodeLayoutVersion {
...
public enum Feature implements LayoutFeature {
ROLLING_UPGRADE(-55, -53, -55, "Support rolling upgrade", false),
EDITLOG_LENGTH(-56, -56, "Add length field to every edit log op"),
XATTRS(-57, -57, "Extended attributes"),
CREATE_OVERWRITE(-58, -58, "Use single editlog record for " +
"creating file with overwrite"),
XATTRS_NAMESPACE_EXT(-59, -59, "Increase number of xattr namespaces"),
BLOCK_STORAGE_POLICY(-60, -60, "Block Storage policy"),
TRUNCATE(-61, -61, "Truncate"),
APPEND_NEW_BLOCK(-62, -61, "Support appending to new block"),
QUOTA_BY_STORAGE_TYPE(-63, -61, "Support quota for specific storage types"),
ERASURE_CODING(-64, -61, "Support erasure coding"),
EXPANDED_STRING_TABLE(-65, -61, "Support expanded string table in fsimage");
private final FeatureInfo info;
...
}
public class DataNodeLayoutVersion {
...
public enum Feature implements LayoutFeature {
FIRST_LAYOUT(-55, -53, "First datanode layout", false),
BLOCKID_BASED_LAYOUT(-56,
"The block ID of a finalized block uniquely determines its position " +
"in the directory structure"),
BLOCKID_BASED_LAYOUT_32_by_32(-57,
"Identical to the block id based layout (-56) except it uses a smaller"
+ " directory structure (32x32)");
private final FeatureInfo info;
...
}
Layout信息的定義在系統做Rolling Upgrade時還是比較常見的,Layout可以明確標明當期服務啓動版本所在的當前版本號以及它現有所支持的新特性(這裏指的是一些具有不兼容改動的特性或者涉及數據結構目錄layout的改動)。當服務在Upgrade啓動後,發現當前運行版本的layout值大於當前存儲於本地的layout version值時,就表明此時服務是換了一個新的version版本在跑。
第三點,Rolling Upgrade admin操作命令的支持。這個很好理解,這是爲了Rolling Upgrade過程能更加安全,可以人工操作操作模式進行而不是完全的自動化升級,對於存儲有海量數據規模的存儲系統,完全自動化的Rolling Upgrade危險係數難免太高。
HDFS DataNode端針對Rolling Upgrade的調整
說完HDFS NameNode這邊的調整,下面我們再來說說HDFS在DataNode對於Rolling Upgrade的支持做了哪些調整。
一般對於一個系統做升級,master節點的升級要更爲重要,slave之類的節點所需要進行的操作要輕量級很多。如果在新升級版本內沒有不兼容特性引入的話,那麼升級的步驟就很簡單了,只需要一個簡單的替換安裝包重啓服務的過程。
不過HDFS社區在做這塊實現時圍繞以下幾點目標做了額外的優化:
- DataNode的快速啓動優化(HDFS-5498: Improve datanode startup time)
- DataNode的OOB信息實現(HDFS-5583: Make DN send an OOB Ack on shutdown before restarting)
上述兩點都是爲了儘可能減少Rolling Upgrade過程DataNode節點重啓服務所帶來的影響。DataNode節點的重啓Rolling,中間會涉及到的時間可能比較長,這個由實際集羣所包含的DataNode數量規模而定。
上面第一點,社區主要的優化點在於將DataNode初始掃磁盤block添加到自身內存的操作進行了異步化處理,相關JIRAHDFS-5498(Improve datanode startup time)。
這裏主要談談上述第二點DataNode OOB信息實現。OOB在這裏的全稱是out of band,意爲額外的傳送信息。DataNode定義和利用這個OOB信息做什麼呢?答案是用來向其它正在讀寫此DataNode數據的client表明它將要馬上做restart操作了,然後告訴這些client它們應該在一定超時時間內等待並忽略與此重啓操作引發的異常錯誤。這可以避免client遇到這類異常馬上執行錯誤recovery這類cost更高的操作。筆者認爲這個設計點還是比較巧妙的。與此相關的JIRA HDFS-5583(Make DN send an OOB Ack on shutdown before restarting)和HDFS-5924(Utilize OOB upgrade message processing for writes)
除上述兩點外,DataNode這邊另外做的一個變動是延遲刪除處理,在rolling upgrade期間刪除的block數據,會移動到trash目錄,不會進實質的刪除。只有到升級finalized後,纔會進行數據的刪除,相關JIRA HDFS-5907(BlockPoolSliceStorage trash to handle block deletions during rolling upgrade)
關於HDFS Rolling Upgrade更詳細實現的內容可參閱社區JIRA HDFS-5535(Umbrella jira for improved HDFS rolling upgrades)。
引用
[1].https://issues.apache.org/jira/browse/HDFS-5535