使用QJM構建HDFS HA架構(2.2+)


    本文主要介紹HDFS HA特性,以及如何使用QJM(Quorum Journal Manager)特性實現HDFS HA。

 

一、背景

    HDFS集羣中只有一個Namenode,這就會引入單點問題;即如果Namenode故障,那麼這個集羣將不可用,直到Namenode重啓或者其他Namenode接入。

    有兩種方式會影響集羣的整體可用性:

    1、意外的突發事件,比如物理機器crash,集羣將不可用,直到管理員重啓Namenode。

    2、系統維護,比如軟件升級等,需要關閉Namenode,也會導致集羣暫時性的失效。

 

    HDFS HA特性即解決這個問題,它通過在集羣中同時運行2個(redundant)Namenodes,並讓active和passive之間熱備(hot standby)。當Active Namenode故障失效後,即可快速故障轉移到新的Namenode上(passive Namenode);也可以在計劃維護期間,基於管理員發起(administrator-inited)的友好的failover。

 

二、Architecture

    在典型的HA架構中,有兩個獨立的機器作爲Namenode,任何時刻,只有一個Namenode處於Active狀態,另一個處於standby狀態(passive,備份);Active Namenode用於接收Client端請求,Standy節點作爲slave保持集羣的狀態數據以備快速failover。

 

    爲了讓Standby Node與Active Node保持同步,這兩個Node都與一組稱爲JNS的互相獨立的進程保持通信(Journal Nodes)。當Active Node上更新了namespace,它將記錄修改日誌發送給JNS的多數派。Standby noes將會從JNS中讀取這些edits,並持續關注它們對日誌的變更。Standby Node將日誌變更應用在自己的namespace中,當failover發生時,Standby將會在提升自己爲Active之前,確保能夠從JNS中讀取所有的edits;即在failover發生之前,Standy持有的namespace應該與Active保持完全同步。

 

    爲了支持快速failover,Standby node持有集羣中blocks的最新位置是非常必要的。爲了達到這一目的,Datanodes上需要同時配置這兩個Namenode的地址,同時和它們都建立心跳鏈接,並把block位置發送給它們。

 

    任何時刻,只有一個Active Namenode是非常重要的,否則將會導致集羣操作的混亂,那麼兩個Namenode將會分別有兩種不同的數據狀態,可能會導致數據丟失,或者狀態異常,這種情況通常稱爲“split-brain”(腦裂,三節點通訊阻斷,即集羣中不同的Datanodes卻看到了兩個Active Namenodes)。對於JNS(Journal Nodes)而言,任何時候只允許一個Namenode作爲writer;在failover期間,原來的Standby Node將會接管Active的所有職能,並負責向JNS寫入日誌記錄,這就阻止了其他Namenode基於處於Active狀態的問題。

 

 

三、硬件資源

    爲了構建HA集羣架構,你需要準備如下資源:

    1、Namenode機器:兩臺配置對等的物理機器,它們分別運行Active和Standby Node。

    2、JouralNode機器:運行JouralNodes的機器。JouralNode守護進程相當的輕量級,它們可以和hadoop的其他進程部署在一起,比如Namenodes、jobTracker、ResourceManager等。不過爲了形成多數派(majority),至少需要3個JouralNodes,因爲edits操作必須在多數派上寫入成功。當然JNS的個數可以 > 3,且通常爲奇數(3,5,7),這樣可以更好的容錯和形成多數派。如果你運行了N個JNS,那麼它可以允許(N-1)/2個JNS進程失效並且不影響工作。

 

    此外,在HA集羣中,standby namenode還會對namespace進行checkpoint操作(繼承Backup Namenode的特性),因此,就不需要在HA集羣中運行SecondaryNamenode、CheckpointNode或者BackupNode。事實上,HA架構中運行上述節點,將會出錯(不允許)。

 

四、部署

    一) 、配置

    和HDFS Federation類似,HA配置向後兼容,運行只有一個Namenode運行而無需做任何修改。新的配置中,要求集羣中所有的Nodes都有相同的配置文件,而不是根據不同的Node設定不同的配置文件。

 

    和HDFS Federation一樣,HA集羣重用了“nameservice ID”來標識一個HDFS 實例(事實上它可能包含多個HA Namenods);此外,“NameNode ID”概念被添加到HA中,集羣中每個Namenode都有一個不同的ID;爲了能夠讓一個配置文件支持所有的Namenodes(適用與Federation環境),那麼相關的配置參數都以“nameservice ID”或“Namenode ID”作爲後綴。

 

   修改hdfs-site.xml,增加如下幾個配置參數,其參數的順序無關。

    1、dfs.nameservices:nameservice的邏輯名稱。可以爲任意可讀字符串;如果在Federation中使用,那麼還應該包含其他的nameservices,以","分割。

<property>
  <name>dfs.nameservices</name>
  <value>hadoop-ha,hadoop-federation</value>
</property>

 

    2、dfs.ha.namenodes. [nameservice ID]

<property>
  <name>dfs.ha.namenodes.hadoop-ha</name>
  <value>nn1,nn2</value>
</property>

    其中“hadoop-ha”需要和1)中配置的nameservice ID匹配,此處我們定義“hadoop-ha”下有2個namenode ID。

 

    3、dfs.namenode.rpc-address. [nameservice ID][namenode ID]

    

<property>
  <name>dfs.namenode.rpc-address.hadoop-ha.nn1</name>
  <value>machine1.example.com:8020</value>
</property>
<property>
  <name>dfs.namenode.rpc-address.hadoop-ha.nn2</name>
  <value>machine2.example.com:8020</value>
</property>

    其中nameservice ID需要和1)匹配,namenode ID需要和2) 匹配。配置項的值爲相應namenode的hostname以及通訊端口號(Client與namenode RPC通訊端口),它和non-ha模式下“dfs.namenode.rpc-address”作用一樣。每個namenode ID都需要單獨配置。

 

    你可以根據需要,配置“dfs.namenode.servicerpc-address”,格式和上述一致。(SNN,backup節點與Namenode通訊地址)

 

    4、dfs.namenode.http-address.[nameservice ID].[namenode ID]

<property>
  <name>dfs.namenode.http-address.hadoop-ha.nn1</name>
  <value>machine1.example.com:50070</value>
</property>
<property>
  <name>dfs.namenode.http-address.hadoop-ha.nn2</name>
  <value>machine2.example.com:50070</value>
</property>

    各個namenode的HTTP地址。它和non-ha下的"dfs.namenode.http-address"配置作用一樣。

 

     5、dfs.namenode.shared.edits.dir:

    

<property>
  <name>dfs.namenode.shared.edits.dir</name>
  <value>qjournal://node1.example.com:8485;node2.example.com:8485;node3.example.com:8485/hadoop-ha</value>
</property>

    配置JNS組的url地址,Namenodes將會從JNS組中讀寫edits。這是一個共享存儲區,Active Namenode寫入,Standby Node讀取,每個Namenodeservice必須配置足夠多的JNS地址(>=3,多數派),每條的格式爲:

    “qjournal://host1:port1;host2:port2;host3:port3/journalId”

    其中journalId需要和上述配置中的“nameserviceID”匹配。

<property>
  <name>dfs.journalnode.rpc-address</name>
  <value>0.0.0.0:8485</value>
</property>
<property>
  <name>dfs.journalnode.http-address</name>
  <value>0.0.0.0:8480</value>
</property>

    此外,我們還需要在相應的JournalNodes上增加上述配置。

 

    6、dfs.client.failover.proxy.provider. [nameservice ID]

    HDFS Client鏈接Namenode所使用的類,Client可以通過此類來判定哪個Namenode爲Alive,並與它保持通信。目前hadoop中唯一的實現類爲"ConfiguaredFailoverProxyProvider"。

<property>
  <name>dfs.client.failover.proxy.provider.hadoop-ha</name>
  <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

 

    7、dfs.ha.fencing.methods:在failover期間用來隔離Active Namenode的腳本或者java 類列表。

    雖然JNS可以確保集羣中只有一個Active Node寫入edits,這對保護edits一致性很重要,但是在failover期間,有可能Acitive Node仍然存活,Client可能還與其保持連接提供舊的數據服務,我們可以通過此配置,指定shell腳本或者java程序,SSH到Active NameNode然後Kill Namenode進程。它有兩種可選值(具體參見官方文檔):

    1) sshfence:SSH登錄到Active Namenode,並Kill此進程。首先當前機器能夠使用SSH登錄到遠端,前提是已經授權(rsa)。

    2) shell:運行shell指令隔離Active Namenode。

<property>
  <name>dfs.ha.fencing.methods</name>
  <value>shell(/path/to/my/script.sh arg1 arg2 ...)</value>
</property>

    “()”之間爲shell腳本的路徑,以及參數列表。

 

    8、fs.defaultFS(core-site.xml):

    在non-ha下,這個參數值爲namenode的地址:“hdfs://namenode:8020”;不過在HA架構下,將使用namenservice名稱替代

<property>
  <name>fs.defaultFS</name>
  <value>hdfs://hadoop-ha</value>
</property>

 

    9、dfs.journalnode.edits.dir:

   指定journalNode存儲edits文件的本地路徑。

 

    最終,上述配置信息,需要在server和Client端同時配置纔能有效的適應HA與failover特性。

 

    二)、部署

    上述配置調整完畢後,我們就可以啓動journalNodes守護進程,默認的"sbin/start-dfs.sh"腳本會根據"dfs.namenode.shared.edits.dir"配置,在相應的Datanode上啓動journalNodes。當然我們可以使用::"bin/hdfs start journalnode"分別在相應的機器上啓動。

    一旦JournalNodes啓動成功,它們將會從Namenode上同步metadata。

    1、如果你的HDFS集羣是新建的,那麼需要在每個Namenode上執行"hdfs namenode -format"指令。

    2、如果你的namenodes已經format了,或者是將non-ha轉換成ha架構,你應該在將其中一個namenode上的metadata複製到另一臺上(dfs.namenode.name.dir目錄下的數據),然後在那個沒有format的新加入的namenode上執行"hdfs namenode -bootstrapStandby"。運行這個指令需要確保JournalNodes中持有足夠多的edits。

    3、如果你將一個non-ha的Namenode(比如backup,其已經formated)切換成HA,你需要首先運行"hdfs -initializeSharedEdits",這個指令將本地Namenode中的edits初始化Journalnodes。

 

    此後,你就可以啓動HA Namenodes。可以通過配置指定的HTTP地址(dfs.namenode.https-address)來查看各個Namenode的狀態,Active or Standby。

 

    三)、管理員指令

    HA集羣啓動後,我們可以通過一些指令來管理HDFS集羣。“bin/hdfs haadmin -DFSHAAdmin”指令,其可選參數:

    1、-transitionToActive <namenode id>與-transitionToStandbyl <namenode id>:將指定的namenode ID切換爲Active或者standby。這個指令並不會觸發“fencing method”,所以不常用,我們通常使用"hdfs haadmin -failover"來切換Namenode狀態。

    2、-failover [--forcefence] [--foreactive] <serviceId-fist> <serviceId-second>:在兩個Namenode之間failover。這個指令會觸發將first節點failover到second節點。如果first處於standby,那麼只是簡單的將second提升爲Active。如果first爲Active,那麼將會友好的將其切換爲standby,如果失敗,那麼fencing methods將會觸發直到成功,此後second將會提升爲Active。如果fencing method失敗,那麼second將不會被提升爲Active。

    例如:"hdfs haadmin -DFSHAAdmin -failover nn1 nn2"

    3、-getServiceState <serviceId>:獲取serviceId的狀態,Active還是Standby。鏈接到指定的namenode上,並獲取其當前的狀態,打印出“standby”或者“active”。我可以在crontab中使用此命令,用來監測各個Namenode的狀況。

    4、-checkHealth <serviceId>:檢測指定的namenode的健康狀況。

 

五、自動Failover

    上述介紹瞭如何配置手動failover,在這種模式下,系統不會自動觸發failover,即不會將Standby提升爲Active,即使Active已經失效。接下來介紹如何實現自動failover。

    一)、組件

    Automatic Failover中,增加了2個新的組件:zookeeper集羣,ZKFailoverController進程(簡稱爲ZKFC)。

    Zookeeper是一個高可用的調度服務,可以保存一系列調度數據,當這些數據變更(notify)時可以通知Client,以及監控(montitor)Clients失效,自動failover的實現將依賴於Zookeeper的幾個特性:

    1、Failure delection:失效檢測,每個Namenode將會和zookeeper建立一個持久session,如果Namenode失效,那麼次session將會過期失效,此後Zookeeper將會通知另一個Namenode,然後觸發Failover。

    2、Active Namenode election:zookeeper提供了簡單的機制來實現Acitve Node選舉,如果當前Active失效,Standby將會獲取一個特定的排他鎖(lock),那麼獲取(持有)鎖的Node接下來將會成爲Active。

 

    ZKFailoverControllor(ZKFC)是一個zookeeper客戶端,它主要用來監測和管理Namenodes的狀態,每個Namenode機器上都會運行一個ZKFC程序,它的職責爲:

    1、Health monitoring:ZKFC間歇性的使用health-check指令ping本地的Namenode,Namenode也會及時的反饋自己的health status。如果Namenode失效,或者unhealthy,或者無響應,那麼ZKFS將會標記其爲“unhealthy”。

    2、Zookeeper session manangement:當本地Nanenode運行良好時,ZKFC將會持有一個zookeeper session,如果本地Namenode爲Active,它同時也持有一個“排他鎖”(znode);這個lock在zookeeper中爲“ephemeral” znode(臨時節點),如果session過期,那麼次lock所對應的znode也將被刪除。(參見zookeeper特性)

    3、Zookeeper-based election:如果本地Namenode運行良好,並且ZKFS沒有發現其他的的Namenode持有lock(比如Active失效後,釋放了lock),它將嘗試獲取鎖,如果獲取成功,即“贏得了選舉”,那麼此後將會把本地Namenode標記爲Active,然後觸發Failover:首先,調用fencing method,然後提升本地Namenode 爲Active。

 

    具體Failover過程和詳細內容,請參見 HDFS-2185

 

    二)、配置

    在Automatic Failover中,需要把一個重要的配置項添加到hdfs-site.xml中。

<property>
	<name>dfs.ha.automatic-failover.enabled</name>
	<value>true</value>
</property>

    此外還需要在core-site.xml中,增加如下配置:

<property>
	<name>ha.zookeeper.quorum</name>
	<value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value>
</property>

    上述zookeeper集羣爲即備,儘可能選擇相對平穩的zk集羣。

 

    其中"dfs.ha.automatic-failover.enabled"可以爲每個nameservice ID分別配置:dfs.ha.automatic-failover.enabled.[nameservice ID]。此外在core-site.xml中還可以配置Zookeeper Client的相關參數,比如sessionTimeout,這些配置項以"ha.zookeeper"開頭,其中"dfs.ha."開頭的部分配置項可以用來設定fencing method的相關控制。

 

     三)、初始化HA狀態

    上述準備工作結束後,我們還需要在zookeeper中初始化HA的狀態,通過執行“hdfs zkfc -formatZK”,此命令將會在zookeeker中創建一個znode,用來保存HA或failover的數據。

 

    四)、啓動集羣

    可以使用"start-dfs.sh"這個便捷的指令,它啓動了hdfs所需要的所有守護進程,當然包括ZKFC。也可以使用"hadoop-daemon.sh start zkfc"手動啓動ZKFC客戶端。

   

    五)、檢驗Failover

    一旦Automatic Failover集羣啓動之後,我們需要檢測Failover是否符合預期。首先,我們需要通過命令(getServiceState)或者在Namenode的Web UI上查看各個Namenode的狀態,確認兩個Namenode是否分別處於Active和Standby;此後,你可以手動關閉Active Namenode,比如使用kill -9 <pid num>,在確定Acitve Node失效後,再次檢測原來的Standby是否已經提升爲Active;不過因爲zookeeper session過期判定需要達到sessionTimeout(可配置,ha.zookeeper.session-timeout),這個failover過程可能需要滯後數秒,默認爲5秒。

 

    如果沒有按照預期failover,那麼你需要檢測配置文件是否正確,zk服務是否正確。此外,我們還可以使用上述DFSHAAadmin指令多次嘗試。

 

六、FAQ

    1、ZKFC和Namenodes守護進程的啓動順序是否重要?

    No,對於指定的Namenode,你可以在其之前或者之後啓動ZKFC均可以,ZKFC只是調度Namenode的存活狀態,如果不啓動ZKFC,此Namenode將無法參與自動failover過程。

    2、是否需要額外的monitoring?

    你需要在Namenode機器上,添加額外的monitor用來監控ZKFC是否運行。在某些情況下,zookeeper集羣的故障可能導致ZKFC意外中斷,你需要適時的重啓ZKFC。此外,還需要監控Zookeeper集羣的運行狀況,如果Zookeeper集羣失效,那麼HA集羣將無法failover。

    3、如果Zookeeper失效,將會怎麼樣?

    如果zookeeper集羣故障,那麼Automatic Failover將不會觸發,即使Namenode失效,這也意味着ZKFC無法正常運行。不過,如果Namenodes正常(即使有一個失效),那麼HDFS系統將不會受到影響。因爲HDFS Client並沒有基於zookeeper做任何事情,當zookeeper集羣仍需要儘快的恢復以避免當前Active失效而造成的“split-brain”等問題。

    4、是否可以在Namenodes之間指定優先級?

    NO,這是不能支持的。首先啓動的Namenode將作爲Active,我們只能認爲控制Namenode啓動的順序來做到“優先級”。

    5、在Automatic Failover中,手動Failover怎麼做?

    和普通的Failover一樣,我們總是可以通過"hdfs haadmin -DFSHAAdmin -failover"來實現手動Failover。


原文:http://itindex.net/detail/50686-hdfs-ha-qjm 

發佈了49 篇原創文章 · 獲贊 7 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章