原因
- NameNode是HDFS的核心配置,HDFS又 Hadoop是核心組件, NameNodeHadoop在集羣中至關重要
- NameNode宕機,將導致集羣不可用,如果 NameNode數據丟失將導致整個集羣的數據丟失,而 NameNode的數據的更新又比較頻繁,實現 NameNode高可用勢在必行
解決方案
官方提供了兩種解決方案
- HDES With nes
- HDFS With QJM
兩種方案對比
- 都能實現熱備
- 都是一個 Active NNStandby和一個 NN
- 都使用 Zookeeper和ZKFC來實現自動失效恢復
- 失效切換都使用 FencinActive配置的方法來active NN
- NFS數據共享變更方案把數據存儲在共享存儲裏,我們還需要考慮NS的高可用設計
- QJM不需要共享存儲,但需要讓每一個DN都知道兩個NN的位置,並把塊信息和心跳包發送給 Active和Standby這兩個NN
使用QJM
使用原因
- 解決 NameNode單點故障問題
- Hadoop給出了HDFS的高可用HA方案:HDFS通常由兩個 NameNode組成,一個處於 Active狀態,另一個處於 Standby狀態。 Active NameNode對外提供服務,比如 處理來自客戶端的RPC請求,而 Standby NameNode則 不對外提供服務,僅同步 Active NameNode的狀態,以 便能夠在它失敗時進行切換
- Namenode會被配置在兩臺獨立的機器上,在任何時 候,一個 NameNode處於活動狀態,而另一個 NameNode則處於備份狀態
- 活動狀態的 NameNode會響應集羣中所有的客戶端, 備份狀態的 Namenode只是作爲一個副本,保證在必 要的時候提供一個快速的轉移
高可用架構
- 爲了讓 Standby Node與 Active node保持同步,這兩個Node都與一組稱爲JNS的互相獨立的進程保持通信( Journal nodes)。當 Active Node更新了 namespace ,它將記錄修改日誌發送給JNS的多數派。 Standby Node將從 JNS中讀取這些 edits,並持續關注它們對日誌的變更
- Standby Node將日誌變更應用在自己的 namespace中 ,當 Failover發生時, Standby將會在提升自己爲 Active之前確保能夠從JNS中讀取所有的 edits,即在 Failover發生之前 Standy持有的 namespace與 Active保持完全同步
- NameNode更新很頻繁,爲了保持主備數據的一致性,爲了支持快速Failover,Standby Node持有集羣中blocks的最新位置是非常必要的。爲了達到這一目的,DataNodes上需要同時配置這兩個Namenode的地址,同時和它們都建立心跳連接,並把block位置發送給它們
- 任何時刻,只能有一個Active NameNode,否則會導致集羣操作混亂,兩個NameNode將會有兩種不同的數據狀態,可能會導致數據丟失或狀態異常,這種情況通常稱爲"split-brain"(腦裂,三節點通訊阻斷,即集羣中不同的DataNode看到了不同的ActiveNameNodes)
- 對於JNS而言,任何時候只允許一個NameNode作爲writer;在Failover期間,原來的Standby Node將會接管Active的所有職能,並負責向JNS寫入日誌記錄,這種機制阻止了其他NameNode處於Active狀態的問題
1)系統規劃
主機 | 角色 |
---|---|
192.168.1.60 | NameNode1 |
192.168.1.66 | NameNode2 |
192.168.1.61 | DataNode/journalNode/Zookeeper |
192.168.1.62 | DataNode/journalNode/Zookeeper |
192.168.1.63 | DataNode/journalNode/Zookeeper |
2)配置高可用
- NameNode2配置
- 參考NameNode1
- 其餘機器使用之前的配置
- 修改配置文件
[root@nn01 ~] vim /usr/local/hadoop/etc/hadoop/core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
#mycluster是組名,訪問的時候訪問這個組
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/var/hadoop</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>node1:2181,node2:2181,node3:2181</value> #zookeepe的地址
</property>
<property>
<name>hadoop.proxyuser.nfs.groups</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.nfs.hosts</name>
<value>*</value>
</property>
</configuration>
[root@nn01 ~] vim /usr/local/hadoop/etc/hadoop/hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<property>
<name>dfs.ha.namenodes.nsdcluster</name>
#nn1,nn2名稱固定,是內置的變量,nsdcluster裏面有nn1,nn2
<value>nn1,nn2</value>
</property>
<property>
<name>dfs.namenode.rpc-address.nsdcluster.nn1</name>
#聲明nn1 8020爲通訊端口,是nn01的rpc通訊端口
<value>nn01:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.nsdcluster.nn2</name>
#聲明nn2是誰,nn02的rpc通訊端口
<value>nn02:8020</value>
</property>
<property>
<name>dfs.namenode.http-address.nsdcluster.nn1</name>
#nn01的http通訊端口
<value>nn01:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.nsdcluster.nn2</name>
#nn01和nn02的http通訊端口
<value>nn02:50070</value>
</property>
<property>
<name>dfs.namenode.shared.edits.dir</name>
#指定namenode元數據存儲在journalnode中的路徑
<value>qjournal://node1:8485;node2:8485;node3:8485/nsdcluster</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name>
#指定journalnode日誌文件存儲的路徑
<value>/var/hadoop/journal</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.nsdcluster</name>
#指定HDFS客戶端連接active namenode的java類
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<property>
<name>dfs.ha.fencing.methods</name> #配置隔離機制爲ssh
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name> #指定密鑰的位置
<value>/root/.ssh/id_rsa</value>
</property>
<property>
<name>dfs.ha.automatic-failover.enabled</name> #開啓自動故障轉移
<value>true</value>
</property>
</configuration>
[root@nn01 ~] vim /usr/local/hadoop/etc/hadoop/yarn-site.xml
<configuration>
<!-- Site specific YARN configuration properties -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name> #rm1,rm2代表nn01和nn02
<value>rm1,rm2</value>
</property>
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>node1:2181,node2:2181,node3:2181</value>
</property>
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yarn-ha</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>nn01</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>nn02</value>
</property>
</configuration>
3)初始化
- 檢查zookeeper服務是否可用
- 清理之前的數據信息
rm -rf /var/hadoop
- 清理日誌信息
rm -rf /usr/local/hadoop/logs/*
- 同步配置文件到所有主機
- 初始化ZK集羣
[root@nn01 ~] /usr/local/hadoop/bin/hdfs zkfc -formatZK
- node啓動journalnode
node1,node2,node3:
/usr/local/hadoop/sbin/hadoop-daemon.sh start journalnode
jps #查看角色:JournalNode
- NameNode1格式化hdfs
[root@nn01 ~] /usr/local/hadoop//bin/hdfs namenode -format
- nn02數據同步到本地 /var/hadoop/dfs
[root@nn02 ~] rsync -aXSH --delete nn01:/var/hadoop/ /var/hadoop/
- nn01初始化JNS
[root@nn01 ~] /usr/local/hadoop/bin/hdfs namenode -initializeSharedEdits
- Node節點關閉JournalNode
node1,node2,node3:
/usr/local/hadoop/sbin/hadoop-daemon.sh stop journalnode
4)啓動及驗證
[root@nn01 ~] /usr/local/hadoop/sbin/start-all.sh
[root@nn02 ~] /usr/local/hadoop/sbin/yarn-daemon.sh start resourcemanager
角色驗證:
[root@ansible ~] ansible all -m shell -a 'jps'
node2 | SUCCESS | rc=0 >>
2241 QuorumPeerMain
8322 JournalNode
8226 DataNode
8413 NodeManager
8575 Jps
nn02 | SUCCESS | rc=0 >>
7033 Jps
6731 NameNode
6908 ResourceManager
6830 DFSZKFailoverController
node1 | SUCCESS | rc=0 >>
8388 DataNode
8484 JournalNode
2469 QuorumPeerMain
8733 Jps
8575 NodeManager
node3 | SUCCESS | rc=0 >>
2240 QuorumPeerMain
8321 JournalNode
8225 DataNode
8412 NodeManager
8575 Jps
nn01 | SUCCESS | rc=0 >>
8864 DFSZKFailoverController
9296 Jps
2104 QuorumPeerMain
8968 ResourceManager
8559 NameNode
集羣驗證:
[root@nn01 ~] /usr/local/hadoop/bin/hdfs dfsadmin -report
Live datanodes (3):
[root@nn01 ~] /usr/local/hadoop/bin/yarn node -list
Total Nodes:3
Node-Id Node-State Node-Http-Address Number-of-Running-Containers
node1:39701 RUNNING node1:8042 0
node3:42280 RUNNING node3:8042 0
node2:40320 RUNNING node2:8042 0
主備驗證:
[root@nn01 ~] /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn1
active
[root@nn01 ~] /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn2
standby
[root@nn01 ~] /usr/local/hadoop/bin/yarn rmadmin -getServiceState rm1
active
[root@nn01 ~] /usr/local/hadoop/bin/yarn rmadmin -getServiceState rm2
standby
訪問集羣文件:
./bin/hadoop fs -mkdir /input
./bin/hadoop fs -ls /
主從切換Active:
[root@nn01 ~] /usr/local/hadoop/sbin/hadoop-daemon.sh stop namenode