http://www.binospace.com/index.php/hdfs-ha-quorum-journal-manager/?utm_source=tuicool
1、背景
HDFS HA,即NameNode單點故障問題,一直是關係到HDFS穩定性最爲重要的特性。之前Hadoop0.23初探系列文章中,介紹了HDFS的Federeation概況、配置與部署的情況,以及有關HA的相關概念。
HDFS HA的發展經歷瞭如下幾個階段:
1)手動恢復階段。手動備份fsimage、fsedits數據,NN故障之後,重啓hdfs。這是最早期使用的辦法,由於早期數據量、機器規模、以及對應用的影響還比較小,該方案勉強堅持了一段時間。
2)藉助DRBD、HeartbeatHA實現主備切換。
使用DRBD實現兩臺物理機器之間塊設備的同步,即通過網絡實現Raid1,輔以Heartbeat HA實現兩臺機器動態角色切換,對外(DataNode、DFSClient)使用虛IP來統一配置。這種策略,可以很好地規避因爲物理機器損壞造成的hdfs元數據丟失,(這裏的元數據簡單地說,就是目錄樹,以及每個文件有哪些block組成以及它們之間的順序),但block與機器位置的對應關係僅會存儲在NameNode的內存中,需要DataNode定期向NameNode做block report來構建。因此,在數據量較大的情況下,blockMap的重建過程也需要等待一段時間,對服務會有一定的影響。
3)DataNode同時向主備NN彙報block信息。這種方案以Facebook AvatarNode爲代表。
PrimaryNN與StandbyNN之間通過NFS來共享FsEdits、FsImage文件,這樣主備NN之間就擁有了一致的目錄樹和block信息;而block的位置信息,可以根據DN向兩個NN上報的信息過程中構建起來。這樣再輔以虛IP,可以較好達到主備NN快速熱切的目的。但是顯然,這裏的NFS又引入了新的SPOF。
在主備NN共享元數據的過程中,也有方案通過主NN將FsEdits的內容通過與備NN建立的網絡IO流,實時寫入備NN,並且保證整個過程的原子性。這種方案,解決了NFS共享元數據引入的SPOF,但是主備NN之間的網絡連接又會成爲新的問題。
總結:在開源技術的推動下,針對HDFS NameNode的單點問題,技術發展經歷以上三個階段,雖然,在一定程度上緩解了hdfs的安全性和穩定性的問題,但仍然存在一定的問題。直到hadoop2.0.*之後,Quorum Journal Manager給出了一種更好的解決思路和方案。
2、Quorum Journal Manager原理
在一個典型的HA集羣,兩個獨立的物理節點配置爲NameNodes。在任何時間點,其中之一NameNodes是處於Active狀態,另一種是在Standby狀態。 Active NameNode負責所有的客戶端的操作,而Standby NameNode盡用來保存好足夠多的狀態,以提供快速的故障恢復能力。
爲了保證Active NN與Standby NN節點狀態同步,即元數據保持一致。除了DataNode需要向兩個NN發送block位置信息外,還構建了一組獨立的守護進程”JournalNodes”,用來FsEdits信息。當Active NN執行任何有關命名空間的修改,它需要持久化到一半以上的JournalNodes上。而Standby NN負責觀察JNs的變化,讀取從Active NN發送過來的FsEdits信息,並更新其內部的命名空間。一旦ActiveNN遇到錯誤,Standby NN需要保證從JNs中讀出了全部的FsEdits,然後切換成Active狀態。
預防腦裂現象”Brain Split”。HA需要保證在任何一個時間點,最多隻有一個NameNode處於Active狀態。否則的話,在兩個NN的NameSpace下的狀態會出現分歧,從而引起數據丟失、或者其它不可預見的錯誤。爲了預防該問題的發送,在任何時間點內JNs僅允許一個NN向其寫FsEdits信息,保證故障遷移的正常執行。
3、HDFS HA — JQM的配置
硬件資源:8臺物理主機,hostname爲GS-CIX-SEV0001~0008
軟件版本:hadoop-2.0.5-alpha
系統配置目標:
1) 配置hbasecluster,commoncluster兩個NameSpace,保證hbase集羣和common集羣命名空間的分離。
2) 對於每一個NameSpace下使用JQM配置HA。
3) 使用3個節點
系統環境清單:
系統設置兩個NameSpace:hbasecluster, commoncluster
hbasecluster |
commoncluster |
|
NameNode |
GS-CIX-SEV0001, GS-CIX-SEV0002 |
GS-CIX-SEV0003, GS-CIX-SEV0004 |
DataNode |
GS-CIX-SEV0001~0008 |
|
JournalNode |
GS-CIX-SEV0001,GS-CIX-SEV0002,GS-CIX-SEV0003 |
|
DFSZKFailoverController |
GS-CIX-SEV0001, GS-CIX-SEV0002 |
GS-CIX-SEV0003, GS-CIX-SEV0004 |
主要的配置文件有:hdfs-site.xml、core-site.xml
hdfs-site.xml
<configuration> <property> <name>dfs.replication</name> <value>3</value> </property> <property> <name>dfs.nameservices</name> <value>hbasecluster,commoncluster</value> </property> <property> <name>dfs.ha.namenodes.hbasecluster</name> <value>hnn1,hnn2</value> </property> <property> <name>dfs.ha.namenodes.commoncluster</name> <value>cnn1,cnn2</value> </property> <!--config rpc--> <property> <name>dfs.namenode.rpc-address.hbasecluster.hnn1</name> <value>GS-CIX-SEV0001:9100</value> </property> <property> <name>dfs.namenode.rpc-address.hbasecluster.hnn2</name> <value>GS-CIX-SEV0002:9100</value> </property> <property> <name>dfs.namenode.rpc-address.commoncluster.cnn1</name> <value>GS-CIX-SEV0003:9100</value> </property> <property> <name>dfs.namenode.rpc-address.commoncluster.cnn2</name> <value>GS-CIX-SEV0004:9100</value> </property> <!--config http-address--> <property> <name>dfs.namenode.http-address.hbasecluster.hnn1</name> <value>GS-CIX-SEV0001:50071</value> </property> <property> <name>dfs.namenode.http-address.hbasecluster.hnn2</name> <value>GS-CIX-SEV0002:50071</value> </property> <property> <name>dfs.namenode.http-address.commoncluster.cnn1</name> <value>GS-CIX-SEV0003:50071</value> </property> <property> <name>dfs.namenode.http-address.commoncluster.cnn2</name> <value>GS-CIX-SEV0004:50071</value> </property> <!-- qjournal config--> <!--dfs.namenode.shared.edits.dir dfs.namenode.shared.edits.dir--> <property> <name>dfs.journalnode.edits.dir</name> <value>/var/lib/ssd/disk1/hadoop/hdfs/journal/</value> </property> <property> <name>dfs.namenode.shared.edits.dir.hbasecluster.hnn1</name> <value>qjournal://GS-CIX-SEV0001:8485;GS-CIX-SEV0002:8485;GS-CIX-SEV0003:8485/hbasecluster</value> </property> <property> <name>dfs.namenode.shared.edits.dir.hbasecluster.hnn2</name> <value>qjournal://GS-CIX-SEV0001:8485;GS-CIX-SEV0002:8485;GS-CIX-SEV0003:8485/hbasecluster</value> </property> <property> <name>dfs.namenode.shared.edits.dir.commoncluster.cnn1</name> <value>qjournal://GS-CIX-SEV0001:8485;GS-CIX-SEV0002:8485;GS-CIX-SEV0003:8485/commoncluster</value> </property> <property> <name>dfs.namenode.shared.edits.dir.commoncluster.cnn2</name> <value>qjournal://GS-CIX-SEV0001:8485;GS-CIX-SEV0002:8485;GS-CIX-SEV0003:8485/commoncluster</value> </property> <property> <name>dfs.client.failover.proxy.provider.hbasecluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property> <property> <name>dfs.client.failover.proxy.provider.commoncluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property> <property> <name>dfs.ha.fencing.methods</name> <value>sshfence</value> </property> <property> <name>dfs.ha.fencing.ssh.private-key-files</name> <value>/home/hbase/.ssh/id_rsa</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:/var/lib/ssd/disk1/hadoop/hdfs/name</value> <final>true</final> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:/var/lib/ssd/disk1/hadoop/hdfs/data</value> <final>true</final> </property> <property> <name>dfs.ha.automatic-failover.enabled</name> <value>true</value> </property> </configuration> core-site.xml: |
core-site.xml:
<configuration> <property> <name>hadoop.tmp.dir</name> <value>/var/lib/ssd/disk1/hadoop/tmp</value> <description>A base for other temporarydirectories.</description> </property> <property> <property> <name>hadoop.proxyuser.hbase.hosts</name> <value>GS-CIX-SEV0001.goso.com</value> <description>設置代理的主機</description> </property> <property> <name>hadoop.proxyuser.hbase.groups</name> <value>*</value> </property> <property> <name>fs.defaultFS</name> <value>hdfs://hbasecluster</value> <description>設置默認前綴的形式,如果不設置的話,需要按照hdfs://${service_name}訪問</description> </property> <property> <name>ha.zookeeper.quorum</name> <value>10.100.1.1:2181,10.100.1.2:2181,10.100.1.3:2181</value> <description>設置ha所依賴的zk-server的路徑</description> </property> <property> <name>ha.zookeeper.parent-znode</name> <value>/hbase/hadoop-ha</value> <description>設置ha的zk路徑</description> </property> </configuration> |
4、HDFS HA 啓動過程
1) 設置HADOOP環境。
在${HADOOP_HOME_DIR}/etc/hadoop/hadoop-env.sh中設置:
export HADOOP_HOME=/opt/hadoop/hadoop/ #設置hadoop根目錄
export JAVA_HOME=/usr/local/jdk1.6.0_38/ #設置jdk的環境
export HADOOP_CONF_DIR=${HADOOP_HOME}/etc/hadoop #設置hadoop conf目錄
(ps:需要節點ssh無密碼登錄,具體方式可以參考網上內容)
按照本文第三部分的內容,根據自己環境配置hdfs-site.xml以及core-site.xml。
2) 啓動JournalNodes。爲此,可以準備如下的腳本。注意該部分不屬於官方配置方式。
${HADOOP_HOME}/etc/hadoop/journalnodes 配置journalnodes
GS-CIX-SEV0001
GS-CIX-SEV0002
GS-CIX-SEV0003
啓動腳本:${HADOOP_HOME}/start-journalnodes.sh
#!/bin/bash
bin=`dirname “${BASH_SOURCE-$0}”`
bin=`cd “$bin”; pwd`
DEFAULT_LIBEXEC_DIR=”$bin”/../libexec
HADOOP_LIBEXEC_DIR=${HADOOP_LIBEXEC_DIR:-$DEFAULT_LIBEXEC_DIR}
. $HADOOP_LIBEXEC_DIR/hdfs-config.sh
JOURNAL_NODES=$(cat ${HADOOP_CONF_DIR}/journalnodes)
echo “Starting journal nodes [$JOURNAL_NODES]“
“$HADOOP_PREFIX/sbin/hadoop-daemons.sh” \
–config “$HADOOP_CONF_DIR” \
–hostnames “$JOURNAL_NODES” \
–script “$bin/hdfs” start journalnode
使用 sbin/start-journalnodes.sh啓動JournaNodes。
3) 啓動NameNode。
配置HA,需要保證ActiveNN與StandByNN有相同的NameSpace ID,在format一臺機器之後,讓另外一臺NN同步目錄下的數據。
配置Federation,需要在啓動多個NameNode上format時,指定clusterid,從而保證2個NameService可以共享所有的DataNodes,否則兩個NameService在fornat之後,生成的clusterid不一致,DataNode會隨機註冊到不同的NameNode上。如下所示:
兩個NameService下各出現了4個DataNodes,並沒有達到DataNode共用的效果。因此在啓動NN的過程中,需要按照如下的方式進行:
l 在hbasecluster的一臺NN上執行:bin/hdfs namenode –format –clusterid cluster,然後啓動NN,sbin/hadoop-daemon.sh start namenode
l 在hbasecluster的另外一臺NN上執行:bin/hdfs namenode –bootstrapStandby 同步NN的文件,然後執行sbin/hadoop-daemon.sh start namenode
此時,hbasecluster上的2個NN都處於Standby狀態,需要啓動DFSZKFailoverController,該部分可以利用修改的sbin/start-dfs.sh啓動。
對於commoncluster的兩個NameNode,使用如上同樣的方式進行啓動。
4) 啓動zkfc,具體的方式,可以參考sbin/start-dfs.sh提供的腳本進行。
5) 啓動datanode,具體參見sbin/start-dfs.sh提供的啓動方式。
啓動之後,可以看到如下的目錄結構。
針對每一個NameService,在journal下有對應目錄存儲edits_***-***,而在name下是NameNode保存的本地fsimage和fsedits信息。
可以通過bin/hadoop fs –mkdir hdfs://hbasecluster/hbase
bin/hadoop fs –ls hdfs://hbasecluster/ 測試環境是否正常。
參考文獻:
http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/HDFSHighAvailabilityWithQJM.html