在Hadoop1中NameNode存在一個單點故障問題,若是NameNode所在的機器發生故障,整個集羣就將不可用(Hadoop1中雖然有個SecorndaryNameNode,可是它並非NameNode的備份,它只是NameNode的一個助理,協助NameNode工做,SecorndaryNameNode會對fsimage和edits文件進行合併,並推送給NameNode,防止因edits文件過大,致使NameNode重啓變慢),這是Hadoop1的不可靠實現。java
在Hadoop2中這個問題得以解決,Hadoop2中的高可靠性是指同時啓動NameNode,其中一個處於active工做狀態,另一個處於隨時待命standby狀態。這樣,當一個NameNode所在的服務器宕機時,能夠在數據不丟失的狀況下, 手工或者自動切換到另外一個NameNode提供服務。node
這些NameNode之間經過共享數據,保證數據的狀態一致。多個NameNode之間共享數據,能夠經過Network File System或者Quorum Journal Node。前者是經過Linux共享的文件系統,屬於操做系統的配置;後者是Hadoop自身的東西,屬於軟件的配置。linux
咱們這裏講述使用Quorum Journal Node的配置方式,方式是手工切換。web
集羣啓動時,能夠同時啓動2個NameNode。這些NameNode只有一個是active的,另外一個屬於standby狀態。active狀態意味着提供服務,standby狀態意味着處於休眠狀態,只進行數據同步,時刻準備着提供服務,如圖2所示。shell
圖2apache
在一個典型的HA集羣中,每一個NameNode是一臺獨立的服務器。在任一時刻,只有一個NameNode處於active狀態,另外一個處於standby狀態。其中,active狀態的NameNode負責全部的客戶端操做,standby狀態的NameNode處於從屬地位,維護着數據狀態,隨時準備切換。bootstrap
兩個NameNode爲了數據同步,會經過一組稱做JournalNodes的獨立進程進行相互通訊。當active狀態的NameNode的命名空間有任何修改時,會告知大部分的JournalNodes進程。standby狀態的NameNode有能力讀取JNs中的變動信息,而且一直監控edit log的變化,把變化應用於本身的命名空間。standby能夠確保在集羣出錯時,命名空間狀態已經徹底同步了,如圖3所示。安全
圖3服務器
爲了確保快速切換,standby狀態的NameNode有必要知道集羣中全部數據塊的位置。爲了作到這點,全部的datanodes必須配置兩個NameNode的地址,發送數據塊位置信息和心跳給他們兩個。架構
對於HA集羣而言,確保同一時刻只有一個NameNode處於active狀態是相當重要的。不然,兩個NameNode的數據狀態就會產生分歧,可能丟失數據,或者產生錯誤的結果。爲了保證這點,JNs必須確保同一時刻只有一個NameNode能夠向本身寫數據。
爲了部署HA集羣,應該準備如下事情:
* NameNode服務器:運行NameNode的服務器應該有相同的硬件配置。
* JournalNode服務器:運行的JournalNode進程很是輕量,能夠部署在其餘的服務器上。注意:必須容許至少3個節點。固然能夠運行更多,可是必須是奇數個,如三、五、七、9個等等。當運行N個節點時,系統能夠容忍至少(N-1)/2個節點失敗而不影響正常運行。
在HA集羣中,standby狀態的NameNode能夠完成checkpoint操做,所以不必配置Secondary NameNode、CheckpointNode、BackupNode。若是真的配置了,還會報錯。
HA集羣須要使用nameservice ID區分一個HDFS集羣。另外,HA中還要使用一個詞,叫作NameNode ID。同一個集羣中的不一樣NameNode,使用不一樣的NameNode ID區分。爲了支持全部NameNode使用相同的配置文件,所以在配置參數中,須要把「nameservice ID」做爲NameNode ID的前綴。
HA配置內容是在文件hdfs-site.xml中的。下面介紹關鍵配置項。
dfs.nameservices 命名空間的邏輯名稱。若是使用HDFS Federation,能夠配置多個命名空間的名稱,使用逗號分開便可。
<property> <name>dfs.nameservices</name> <value>mycluster</value> </property>
dfs.ha.namenodes.[nameservice ID] 命名空間中全部NameNode的惟一標示名稱。能夠配置多個,使用逗號分隔。該名稱是可讓DataNode知道每一個集羣的全部NameNode。當前,每一個集羣最多隻能配置兩個NameNode。
<property> <name>dfs.ha.namenodes.mycluster</name> <value>nn1,nn2</value> </property>
dfs.namenode.rpc-address.[nameservice ID].[name node ID] 每一個namenode監聽的RPC地址。以下所示
<property> <name>dfs.namenode.rpc-address.mycluster.nn1</name> <value>machine1.example.com:8020</value> </property> <property> <name>dfs.namenode.rpc-address.mycluster.nn2</name> <value>machine2.example.com:8020</value> </property>
dfs.namenode.http-address.[nameservice ID].[name node ID] 每一個namenode監聽的http地址。以下所示
<property> <name>dfs.namenode.http-address.mycluster.nn1</name> <value>machine1.example.com:50070</value> </property> <property> <name>dfs.namenode.http-address.mycluster.nn2</name> <value>machine2.example.com:50070</value> </property>
若是啓用了安全策略,也應該對每一個namenode配置htts-address信息,與此相似。
dfs.namenode.shared.edits.dir 這是NameNode讀寫JNs組的uri。經過這個uri,NameNodes能夠讀寫edit log內容。URI的格式"qjournal://host1:port1;host2:port2;host3:port3/journalId"。這裏的host一、host二、host3指的是Journal Node的地址,這裏必須是奇數個,至少3個;其中journalId是集羣的惟一標識符,對於多個聯邦命名空間,也使用同一個journalId。配置以下
<property> <name>dfs.namenode.shared.edits.dir</name> <value>qjournal://node1.example.com:8485;node2.example.com:8485;node3.example.com:8485/mycluster</value> </property>
這裏配置HDFS客戶端鏈接到Active NameNode的一個java類
<property> <name>dfs.client.failover.proxy.provider.mycluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property>
dfs.ha.fencing.methods
配置active namenode出錯時的處理類。當active namenode出錯時,通常須要關閉該進程。處理方式能夠是ssh也能夠是shell。
若是使用ssh,配置以下
<property> <name>dfs.ha.fencing.methods</name> <value>sshfence</value> </property> <property> <name>dfs.ha.fencing.ssh.private-key-files</name> <value>/home/exampleuser/.ssh/id_rsa</value> </property>
這種方法配置簡單,推薦使用。
fs.defaultFS
客戶端鏈接HDFS時,默認的路徑前綴。若是前面配置了nameservice ID的值是mycluster,那麼這裏能夠配置爲受權信息的一部分
能夠在core-site.xml中配置以下
<property> <name>fs.defaultFS</name> <value>hdfs://mycluster</value> </property>
dfs.journalnode.edits.dir
這是JournalNode進程保持邏輯狀態的路徑。這是在linux服務器文件的絕對路徑。
<property> <name>dfs.journalnode.edits.dir</name> <value>/path/to/journal/node/local/data</value> </property>
以上配置完成後,就能夠啓動JournalNode進程了。在各個JournalNode機器上執行命令「hadoop-daemon.sh journalnode」。
若是是一個新的HDFS集羣,還要首先執行格式化命令「hdfs namenode -format」,緊接着啓動本NameNode進程。
若是存在一個已經格式化過的NameNode,而且已經啓動了。那麼應該把該NameNode的數據同步到另外一個沒有格式化的NameNode。在未格式化過的NameNode上執行命令「hdfs namenode -bootstrapStandby」。
若是是把一個非HA集羣轉成HA集羣,應該運行命令「hdfs –initializeSharedEdits」,這會初始化JournalNode中的數據。
作了這些事情後,就能夠啓動兩個NameNode了。啓動成功後,經過web頁面觀察兩個NameNode的狀態,都是standby。
下面執行命令「hdfs haadmin -failover --forcefence serviceId serviceId2」。就會把NameNode的狀態進行安全的切換。其中後面一個會變爲active狀態。這時候再經過web頁面觀察就能看到正確結果了