天天看點

使用 QJM 實作 HDFS 的 HA

本文是在hadoop叢集部署(yarn)基礎上增加的配置内容,因為那篇缺少HDFS的HA配置,在生産環境不夠完整。

hadoop官方提供了兩種HDFS的HA配置方案,兩種方案殊途同歸,但是需要的錢、精力和技術不同。

如果對HDFS架構熟悉的話(如果不熟悉,可以通過HDFS架構了解),就應該知道,NameNode通過FsImage和EditLog兩個檔案管理DataNode的資料,Secondary NameNode會定期合并EditLog,以減少NameNode啟動時的安全檢查。EditLog檔案存儲的是對檔案的一條條的操作,也就是說,隻要保證有另外一個NameNode的EditLog檔案一直與目前正在運作的NameNode的EditLog檔案是一樣的,那就可以随時使用新的NameNode替換老的NameNode。官方目前給出的兩種HA方案也大體是這樣:

QJM:the Quorum Journal Manager,翻譯是法定經濟管理人,實在沒法想象,是以大家都親切的稱之為QJM。這種方案是通過JournalNode共享EditLog的資料,使用的是Paxos算法(沒錯,zookeeper就是使用的這種算法),保證活躍的NameNode與備份的NameNode之間EditLog日志一緻。

NFS:Network File System 或 Conventional Shared Storage,傳統共享存儲,其實就是在伺服器挂載一個網絡存儲(比如NAS),活躍NameNode将EditLog的變化寫到NFS,備份NameNode檢查到修改就讀取過來,是兩個NameNode資料一緻。

客觀的說,Secondary NameNode也算是對NameNode的備份,但是使用Secondary NameNode需要手動處理,不如QJM和NFS兩種可以自動處理簡單,是以沒有被列入HA解決方案中。

但是,這兩種方案在部署方式上差别比較大。QJM需要啟動幾個JournalNode即可,NFS需要挂在一個共享存儲。因為條件限制,我隻能通過QJM的方式實作HDFS的HA,如果想看NFS方案,可以直接看官方文檔。

1. hdfs-site.xml

dfs.nameservices:指定nameservice的名稱,這個需要自定義,可以是任意的名稱。這個值需要用在後面的配置和HDFS叢集管理路徑中。

<property>
  <name>dfs.nameservices</name>
  <value>mycluster</value>
</property>      

dfs.ha.namenodes.[nameservice ID]:指定叢集中兩個NameNode的id,目前隻能支援最多兩個NameNode,是以就需要兩個id,以逗号分隔。

<property>
  <name>dfs.ha.namenodes.mycluster</name>
  <value>nn1,nn2</value>
</property>      

dfs.namenode.rpc-address.[nameservice ID].[namenode ID]:指定NameNode的rpc位址,用于資料傳輸。因為有兩個NameNode,是以需要給出兩個節點。

<property>
  <name>dfs.namenode.rpc-address.mycluster.nn1</name>
  <value>s108:8020</value>
</property>
<property>
  <name>dfs.namenode.rpc-address.mycluster.nn2</name>
  <value>s109:8020</value>
</property>      

dfs.name.http-address.[nameservice ID].[namenode ID]:同3,還需要http位址。

<property>
  <name>dfs.namenode.http-address.mycluster.nn1</name>
  <value>s108:50070</value>
</property>
<property>
  <name>dfs.namenode.http-address.mycluster.nn2</name>
  <value>s109:50070</value>
</property>      

dfs.namenode.shared.edits.dir:需要提供JournalNode的配置位址,用于活躍NameNode向該位置寫變化資料,備份NameNode從該位置讀取資料應用與自身。如果配置過Kafka就應該可以了解這個。配置位址格式是:qjournal://host1:port1;hots2:port2;host3:port3/journalId,位址端口為一對,每對之間通過分号隔開,最後的journalId是為了區分不同的nameservice的。也就是說,一組JournalNode可以支撐多個NameNode的HA配置。是以,比較好的配置方式是,journalId與nameservice的名稱一緻。

<property>
  <name>dfs.namenode.shared.edits.dir</name>
  <value>qjournal://s108:8485;s109:8485;s110:8485/mycluster</value>
</property>      

dfs.client.failover.proxy.provider.[nameservice ID]:HDFS用戶端連接配接活躍NameNode的方式,配置一個Java類。因為NameNode隻有一個是活躍的,也就是隻有一個提供服務,另一個是備份。是以用戶端需要知道哪個是活躍節點。是以需要某種方式找到這個活躍節點。這裡提供一個代理類,目前Hadoop隻實作了一個代理類ConfiguredFailoverProxyProvider,也可以自己定義:

<property>
  <name>dfs.client.failover.proxy.provider.mycluster</name>
  <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>      

dfs.ha.fencing.methods:用于故障轉移過程中,在活躍節點執行的一組腳本或Java類。HDFS叢集有一條原則是:隻能有一個NameNode處于活躍狀态。QJM隻允許一個NameNode寫入JournalNode叢集,是以可以避免鬧裂的發生。但是故障轉移過程中,還可能會有其他的問題,是以需要提供一些防護方法。需要注意的是,如果不想使用具體的防護方法,也必須提供一個腳本,比如shell(/bin/true)。

sshfence:通過ssh方式連接配接活躍NameNode,并kill掉程序。是以還需要通過dfs.ha.fencing.ssh.private-key-files配置ssh key,還可以通過dfs.ha.fencing.ssh.connect-timeout配置ssh連接配接逾時時間。

<property>
<name>dfs.ha.fencing.methods</name>
<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.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>      

如果對于不是标準ssh端口或相同使用者的,可以在sshfence後添加使用者名和端口,格式為sshfence([[username][:port]])。

shell:運作任意的腳本來進行防護。我是使用sshfence方式配置的,是以下面就列出配置格式,具體資訊檢視官網。

<property>
<name>dfs.ha.fencing.methods</name>
<value>shell(/path/to/my/script.sh arg1 arg2 ...)</value>
</property>      

dfs.journalnode.edits.dir:JournalNode守護程序存儲資料的本地路徑。這是啟動JournalNode需要配置的配置項。當然整個叢集配置相同也不會有不好的影響,需要是本地絕對路徑。

<property>
  <name>dfs.journalnode.edits.dir</name>
  <value>/data/hadoop/journal</value>
</property>      

dfs.ha.automatic-failover.enabled:自動故障轉移,該配置向需要與core-site.xml中的ha.zookeeper.quorum配合使用。

<property>
  <name>dfs.ha.automatic-failover.enabled</name>
  <value>true</value>
</property>      

2. core-site.xml

fs.defaultFS:這個在單點NameNode的時候配置過,這裡需要再次配置,需要使用hdfs-site.xml中的nameservice名稱。

<property>
  <name>fs.defaultFS</name>
  <value>hdfs://mycluster</value>
</property>      

ha.zookeeper.quorum:這個就是前面提到hdfs-site.xml中配置自動故障轉移配合使用的配置項,需要提供zookeeper叢集位址

<property>
  <name>ha.zookeeper.quorum</name>
  <value>s109:2181,s110:2181,s111:2181</value>
</property>      

3. 開始啟動

3.1 JournalNode

需要首先啟動JournalNode,如上面配置的,需要s108/s109/s110三個節點啟動JournalNode,預設端口就是8045。啟動指令是hadoop-daemon.sh start journalnode。

3.2 NameNode資料準備

JournalNode啟動完成後,因為有兩個NameNode節點,就需要先同步兩個NameNode節點的資料。

如果是全新的HDFS叢集,這個時候直接hdfs namenode -format格式化即可

已經格式化或是從非HA設定為HA的叢集,需要把格式化後的NameNode節點的資料拷貝到為格式化節點上。未格式化NameNode節點執行hdfs namenode -bootstrapStandby指令。

如果是從非HA到HA的配置,需要執行hdfs namenode -initializeSharedEdits将原有的NameNode日志寫入JournalNode中。

3.3 Zookeeper中的HA狀态

因為上面配置了自動故障轉移,是以需要在Zookeeper中初始化HA狀态。執行指令hdfs zkfc -formatZK。

3.4 啟動

直接使用start-dfs.sh指令啟動NameNode、DataNode,以及ZKFS程序,啟動成功之後就可以通過s108:50070和s109:50070通路web頁面檢視具體哪個NameNode是Active或Standby狀态的了。

啟動的時候可以注意到,啟動過程沒有啟動Secondary NameNode,這是用為HA不會啟動Secondary NameNode。也就是master配置檔案配置内容無效了。

4. 管理

可以通過hdfs haadmin指令進行管理。具體檢視官網說明。

參考

1. HDFS High Availability Using the Quorum Journal Manager

2. HDFS High Availability