HDFS HA-Quorum Journal Manager

http://www.binospace.com/index.php/hdfs-ha-quorum-journal-manager/?utm_source=tuicool

1、背景

HDFS HA,即NameNode單點故障問題,一直是關係到HDFS穩定性最爲重要的特性。之前Hadoop0.23初探系列文章中,介紹了HDFS的Federeation概況、配置與部署的情況,以及有關HA的相關概念。

 Hadoop0.23.0初探1—前因後果

Hadoop0.23.0初探2—HDFS Federation部署

Hadoop0.23.0初探3—HDFS NN,SNN,BN和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的重建過程也需要等待一段時間,對服務會有一定的影響。

 hdfs_DRBD_HeartBeat

3)DataNode同時向主備NN彙報block信息。這種方案以Facebook AvatarNode爲代表。

PrimaryNN與StandbyNN之間通過NFS來共享FsEdits、FsImage文件,這樣主備NN之間就擁有了一致的目錄樹和block信息;而block的位置信息,可以根據DN向兩個NN上報的信息過程中構建起來。這樣再輔以虛IP,可以較好達到主備NN快速熱切的目的。但是顯然,這裏的NFS又引入了新的SPOF。

 avatarnode_dep

在主備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狀態。

 slide-10-1024_副本

預防腦裂現象”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

?View Code 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:

?View Code 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上。如下所示:

 nn2nn1

兩個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提供的啓動方式。

啓動之後,可以看到如下的目錄結構。

 dir_ha_nn

針對每一個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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章