使用QJM實現HDFS的HA配置
使用QJM實現HDFS的HA配置
1、背景
hadoop 2.0.0之前,namenode存在單點故障問題(SPOF,single point of failure),如果主機或進程不可用時,整個集群就變得不可用,直到namenode進行重啟或產生新的namenode。主要有兩種方式會影響到HDFS集群:
- 不可預期事件比如機器宕機,集群變得不可用直到操作人員重啟namenode。
- 可預期事件比如軟硬件升級也會導致集群的下線。
HDFS的高可用特性解決了以上兩個問題,通過在一個集群中運行兩個冗余的Namenode,分別以active/passiave配置方式實現一個熱備處理。這允許namenode宕機後能夠快速容災到新節點,或者管理員以優雅的方式進行計劃性運維容災處理。
2、架構
在電信的HA集群中,配置兩臺獨立的主機為namenode。任何時刻,只有一臺主機處於active狀態,另一臺為standby狀態。active節點負責集群中所有客戶端的操作,standby節點只是扮演一個從屬的角色,他會維護足夠多的狀態信息進行必要條件下的快速容災處理。
為了讓standby節點同active節點保持狀態同步,兩個節點都需要同一組稱之為“JournalNode”的進程通信。當active節點對名字空間進行了修改後,都會記錄這條修改記錄到JN節點的半數以上節點。Standby節點即可從JN節點上讀取這些編輯日誌,Standby節點不斷觀察編輯日誌的修改行為,如果有修改動作發生,便會立刻應用到自己的名字空間中。容災發生時,standby節點在切換到active狀態前要確保從JN上讀取了所有的修改動作。這可以保證在容災發生前,名字空間的狀態是完全同步的。
為了提供快速容災,讓Standby節點擁有最新的block位置信息也是非常有必要的。為了做到這一點,需要使用兩個namenode位置對Datanode進行配置,並且datanode會同時發送block信息和心跳信息給兩個namenode。
正確操作HA集群的一個重點事項就是同一時刻只有一個namenode處於active狀態,否則,名字空間狀態很快在兩者之間產生偏差,從而導致數據丟失或不一致的風險。為了確保這一屬性並防止所謂的“腦裂場景”,JournalNode節點只允許同一時刻一個namenode進行寫入。容災期間,成為active的namenode只是接管journalNode的寫操作,有效防止其他的namenode節點,允許新的active節點安全處理容災工作。
3、硬件資源
為了部署HA集群,需要做如下準備:
namenode主機
運行active和standby的namenode主機,他們具有相同的硬件配置,這種相同的硬件配置也會用在非HA集群下。
Journalnode主機
運行journalnode節點的主機。journalnode進程是輕量級進程,因此可以和他其他hadoop守護進程並存,例如namenode、resourcemanager等。註意:必須至少配置3個Journalnode守護進程,因為編輯日誌必須要寫入JN的半數以上。這允許系統容忍一臺journalnode節點掛掉。為增加系統的容災能力,應該運行奇數個journalnode節點,例如3,5,7臺。當運行n個journalnode節點時,最多容忍(n - 1)/ 2節點故障。
註意,在HA集群模式下,standby節點也會對名字空間狀態進行檢查點操作,因此沒有必要運行secondary namenode,checkpointnode或BackupNode。實際上,這樣做會導致錯誤,這也運行通過改造非HA模式下的secondaryNode成為HA模式。
4、部署
4.1 配置概覽
HA配置是向後兼容的,允許現有的namenode配置不做修改就可以工作。集群中所有節點具有相同的配置,而不需要個不同主機依據節點類型進行不同的配置。
HA集群使用nameservice id區分一個HDFS實例,他可以包含多個HA的namenode節點。集群中的Namenode使用唯一的namenode ID進行區分。為了對所有節點使用一個配置文件,配置可以使用nameservice ID和namenode ID作為後綴。
4.2 配置細節
配置HA Namenode,需要添加幾個選項給hdfs-site.xml配置文件。
這些選項的順序並不重要,但是dfs.nameservices 和dfs.ha.namenodes.[nameservice ID]值很關鍵,因此配置前需要確定這些值的內容。
dfs.nameservices
名稱服務的邏輯名,該名稱是任意的,將會用於配置和HDFS路徑的授權。
<property> <name>dfs.nameservices</name> <value>mycluster</value> </property>
dfs.ha.namenodes.[nameservice ID]
名稱服務中每個namenode的唯一標識。使用“,”號分割的名稱列表,datanode通過他來檢測集群中的所有namenode。
<property> <name>dfs.ha.namenodes.mycluster</name> <value>nn1,nn2</value> </property>
註意:目前最多只支持兩個名稱節點。
dfs.namenode.rpc-address.[nameservice ID].[name node ID]
配置每個名稱節點的IPC端口,需要在單獨的元素進行配置。
<property> <name>dfs.namenode.rpc-address.mycluster.nn1</name> <value>s101:8020</value> </property> <property> <name>dfs.namenode.rpc-address.mycluster.nn2</name> <value>s102:8020</value> </property>
?
dfs.namenode.http-address.[nameservice ID].[name node ID]
配置每個namenode的http監聽地址。
<property> <name>dfs.namenode.http-address.mycluster.nn1</name> <value>s101:50070</value> </property> <property> <name>dfs.namenode.http-address.mycluster.nn2</name> <value>s102:50070</value> </property>
?
dfs.namenode.shared.edits.dir
namenode從JNs集合上讀寫日誌的uri地址。
<property> <name>dfs.namenode.shared.edits.dir</name> <value>qjournal://s102:8485;s103:8485;s104:8485/mycluster</value> </property>
?
dfs.client.failover.proxy.provider.[nameservice ID]
容災代理提供商類,用來檢測哪個namenode是active狀態,哪個namenode用來服務於客戶端請求。當前hadoop只有一個實現。
<property> <name>dfs.client.failover.proxy.provider.mycluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha .ConfiguredFailoverProxyProvider</value> </property>
?
dfs.ha.fencing.methods
容災期間防護namenode的java類或者腳本列表。使用QJM(Quorum journal manager)時只允許一個namenode向journalnodes寫入數據,因此不存在因為腦裂損壞系統元數據的可能。但是,容災發生時,依然有可能的是上一個active節點向客戶端提供讀請求服務,直到向JN節點寫入數據失敗造成namenode停止後導致的時間過期。基於這一原因,使用QJM時仍有必要配置一些防護方法。為提升系統在防護事件失敗時的可用性,建議配置防護方法確保列表中最後一個防護方法返回成功。註意如果選擇使用並無實際的防護方法,也要進行一些配置,比如“shell(bin/true)”等。
防護方法可以配置成列表,然後按序調用直到防護方法成功為止。hadoop給出了兩種方式:shell和sshfence。自定義防護方法可以實現org.apache.hadoop.ha.NodeFencer類。
?
防護方法配置成多行列表的形式,容災時按順序進行調用直到防護方法返回成功為止。hadoop有兩種方式:shell和sshfence。自定義的話可以實現org.apache.hadoop.ha.NodeFencer類。
?
sshfence方式是ssh到active的namenode節點並將進程殺死,該中方式必須能夠無密登錄到目標節點,因此必須要配置私鑰(dfs.ha.fencing.ssh.private-key-files )選項,可以配置成逗號分隔的多個私鑰列表,配置方式如下:
<property> <name>dfs.ha.fencing.methods</name> <value>sshfence</value> </property> <property> <name>dfs.ha.fencing.ssh.private-key-files</name> <value>/home/centos/.ssh/id_rsa</value> </property>
shell方式是運行一個shell腳本來防護active namenode。配置方式如下:
<property> <name>dfs.ha.fencing.methods</name> <value>shell(/path/to/my/script.sh arg1 arg2 ...)</value> </property>
?
fs.defaultFS
hadoop文件系統客戶端沒有指定前綴時使用的默認路徑前綴。
<property> <name>fs.defaultFS</name> <value>hdfs://mycluster</value> </property>
?
dfs.journalnode.edits.dir
Journanode守護進程存放本地狀態的路徑,該路徑使用絕對路徑,使用一個路徑即可。
<property> <name>dfs.journalnode.edits.dir</name> <value>/path/to/journal/node/local/data</value> </property>
4.3 部署細節
配置完成後,必須在JN節點啟動所有的JN守護進程,可使用如下命令完成:
hadoop-daemon.sh start journalnode
一旦JN進程啟動完成,必須要對兩個HA的namenode節點的磁盤元數據進行初始同步
如果搭建的是全新的hdfs集群,應該在其中的一個namenode上運行如下命令進行格式化
hdfs namenode -format
如果已經格式化過namenode或者轉換非HA模式到HA模式下,需要復制namenode的元數據目錄到另一個namenode相同目錄下,未格式化的namenode節點運行如下命令,完成待命狀態引導。該命令還會保證jn節點包含足夠多了編輯動作,以便能夠啟動兩個namenode節點。
hdfs namenode -bootstrapStandby
如果正在將非HA模式轉換成HA,你應該運行如下命令,將會從本地namenode的編輯日誌初始化JN節點的編輯數據。
hdfs namenode -initializeSharedEdits
此時可以像以往啟動namenode一樣啟動兩個namenode。同時,可以分別使用兩個namenode各自的webui地址查看各自的狀態。你會發現兩臺namenode的狀態都是standby。
http://s101:50070
http://s105:50070
4.4 管理命令
配置並啟動namenode後,就可以進行管理工作,可以使用如下管理命令對namenode進行管理:
Usage: haadmin
[-transitionToActive <serviceId>]
[-transitionToStandby <serviceId>]
[-failover [--forcefence] [--forceactive] <serviceId> <serviceId>]
[-getServiceState <serviceId>]
[-checkHealth <serviceId>]
[-help <command>]
transitionToActive和transitionToStandby
切換狀態到active或standby狀態,這些命令不會進行防護處理,盡量少使用,而是用使用failover代替。
failover
在兩個namenode間進行容災演練,從第一個nn到第二個nn進行容災處理,如果第一個nn是standby,就將第二個nn變換成active態。如果第一個是active,首先嘗試優雅變換到standby狀態。如果這一個過程失敗,就按序執行防護方法直到成功,此過程過後,第二個nn才會變成active態。如果防護方法都沒有成功,則第二個nn就不會變成active態並返回一個錯誤。
getServiceState
檢測指定的nn的狀態,連接到namenode檢測其狀態,打印active或standby字樣。
checkHealty
檢查給定namenode的健康狀況,namenode本省能夠執行一個診斷工作,包括檢查是否內部服務在進行,如果健康返回0,否則返回非0。
註意該命令還未實現,始終返回0,除非namenode完全停止。
5、自動容災
5.1 介紹
以上部分描述了如何配置手動容災,在該模式下,系統無法自動觸發容災處理,哪怕是active掛掉。本章描述如何配置自動容災。
5.2 組件
自動容災引入兩個新組件:一個是Zookeeper的quorum,一個是ZKFailoverController進程(簡稱zkfc)。
apache zookeeper是高可用服務用於維護少量協同數據,通知客戶端數據變更、監控客戶端故障。自動容災依賴zookeeper一下內容:
故障檢測
集群中每個namenode主機都在zookeeper中維護了永久session。如果機器宕機,session就會超時,通知其他namenode觸發容災。
active namenode選舉
zookeeper提供一種簡單機制能夠以獨占方式選舉一個node為active。如果當前active節點宕機,另一個namenode就會接管一個排他鎖表明自己將成為下一個active。
zkfc是zookeeper客戶端管理監控namenode狀態的新組件。每個運行namenode主機都會運行一個zkfc進程。zkfc進程負責如下工作:
監控檢查
zkfc周期性ping本地namenode的狀態,如果namenode能夠及時響應,則認為namenode是健康的。如果node宕機或進入某種不監控狀態,監控器就標記其位不健康狀態。
zk session管理
如果本地namenode是健康的,zkfc會持有zk的session。如果namenode是健康的,zkfc還會持有一把臨時鎖。若session過期,lock節點將會被刪除。
基於zk的選舉
如果namenode是健康的,zkfc就會知道不會有其他人持有lock節點,自己就會嘗試上鎖。如若成功就贏得選舉,並運行容災程序,本地namenode就成為active狀態。
5.3 部署zookeeper
典型配置zookeeper模式是使用3或5個節點,由於zookeeper是輕量級的,因此可以和其他進程位於同一主機,例如namenode或datanode。許多人選擇部署第三節點在ResourceManager主機上。建議配置zookeeper在單獨的磁盤驅動器上存儲數據,同hdfs元數據分開,以獲得更好的性能和隔離處理。搭建zookeeper集群請參考相關文章,這裏不做介紹。
5.4 開始前準備工作
停止hdfs集群。
5.5 配置自動容災
在hdfs-site.xml文件中添加如下配置啟用自動容災。
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
在core-site.xml文件中添加zk節點地址。
<property>
<name>ha.zookeeper.quorum</name>
<value>s102:2181,s103:2181,s104:2181</value>
</property>
5.6 在zk中初始化HA狀態
在其中的一個namenode節點上運行如下命令:
hdfs zkfc -formatZK
該命令會在zk中創建相應節點存儲用於容災的數據。
5.7 使用start-dfs.sh啟動集群
由於已經啟用了自動容災,因此啟動namenode時,會自動啟動zkfc進程,並自動選舉一個namenode為active節點。
5.8 手動啟動zkfc進程
也可以手動啟動zkfc進程,運行如下命令:
hadoop-daemon.sh start zkfc
使用QJM實現HDFS的HA配置