Hadoop 高可用 (High Availability) 分爲 HDFS 高可用和 YARN 高可用,二者的實現基本相似,但 HDFS NameNode 對數據存儲及其一致性的要求比 YARN ResourceManger 高得多,因此它的實現也更加複雜,故下面先進行講解:html
HDFS 高可用架構以下:java
圖片引用自:https://www.edureka.co/blog/how-to-set-up-hadoop-cluster-with-hdfs-high-availability/node
HDFS 高可用架構主要由如下組件所構成:git
目前 Hadoop 支持使用 Quorum Journal Manager (QJM) 或 Network File System (NFS) 做爲共享的存儲系統,這裏以 QJM 集羣爲例進行說明:Active NameNode 首先把 EditLog 提交到 JournalNode 集羣,而後 Standby NameNode 再從 JournalNode 集羣定時同步 EditLog,當 Active NameNode 宕機後, Standby NameNode 在確認元數據徹底同步以後就能夠對外提供服務。github
須要說明的是向 JournalNode 集羣寫入 EditLog 是遵循 「過半寫入則成功」 的策略,因此你至少要有3個 JournalNode 節點,固然你也能夠繼續增長節點數量,可是應該保證節點總數是奇數。同時若是有 2N+1 臺 JournalNode,那麼根據過半寫的原則,最多能夠容忍有 N 臺 JournalNode 節點掛掉。web
NameNode 實現主備切換的流程下圖所示:shell
HealthMonitor 初始化完成以後會啓動內部的線程來定時調用對應 NameNode 的 HAServiceProtocol RPC 接口的方法,對 NameNode 的健康狀態進行檢測。apache
HealthMonitor 若是檢測到 NameNode 的健康狀態發生變化,會回調 ZKFailoverController 註冊的相應方法進行處理。vim
若是 ZKFailoverController 判斷須要進行主備切換,會首先使用 ActiveStandbyElector 來進行自動的主備選舉。服務器
ActiveStandbyElector 與 Zookeeper 進行交互完成自動的主備選舉。
ActiveStandbyElector 在主備選舉完成後,會回調 ZKFailoverController 的相應方法來通知當前的 NameNode 成爲主 NameNode 或備 NameNode。
ZKFailoverController 調用對應 NameNode 的 HAServiceProtocol RPC 接口的方法將 NameNode 轉換爲 Active 狀態或 Standby 狀態。
YARN ResourceManager 的高可用與 HDFS NameNode 的高可用相似,可是 ResourceManager 不像 NameNode ,沒有那麼多的元數據信息須要維護,因此它的狀態信息能夠直接寫到 Zookeeper 上,並依賴 Zookeeper 來進行主備選舉。
按照高可用的設計目標:須要保證至少有兩個 NameNode (一主一備) 和 兩個 ResourceManager (一主一備) ,同時爲知足「過半寫入則成功」的原則,須要至少要有3個 JournalNode 節點。這裏使用三臺主機進行搭建,集羣規劃以下:
下載Hadoop。這裏我下載的是CDH版本Hadoop,下載地址爲:http://archive.cloudera.com/cdh5/cdh/5/
# tar -zvxf hadoop-2.6.0-cdh5.15.2.tar.gz
編輯profile
文件:
# vim /etc/profile
增長以下配置:
export HADOOP_HOME=/usr/app/hadoop-2.6.0-cdh5.15.2 export PATH=${HADOOP_HOME}/bin:$PATH
執行source
命令,使得配置當即生效:
# source /etc/profile
進入${HADOOP_HOME}/etc/hadoop
目錄下,修改配置文件。各個配置文件內容以下:
# 指定JDK的安裝位置 export JAVA_HOME=/usr/java/jdk1.8.0_201/
<configuration> <property> <!-- 指定namenode的hdfs協議文件系統的通訊地址 --> <name>fs.defaultFS</name> <value>hdfs://hadoop001:8020</value> </property> <property> <!-- 指定hadoop集羣存儲臨時文件的目錄 --> <name>hadoop.tmp.dir</name> <value>/home/hadoop/tmp</value> </property> <property> <!-- ZooKeeper集羣的地址 --> <name>ha.zookeeper.quorum</name> <value>hadoop001:2181,hadoop002:2181,hadoop002:2181</value> </property> <property> <!-- ZKFC鏈接到ZooKeeper超時時長 --> <name>ha.zookeeper.session-timeout.ms</name> <value>10000</value> </property> </configuration>
<configuration> <property> <!-- 指定HDFS副本的數量 --> <name>dfs.replication</name> <value>3</value> </property> <property> <!-- namenode節點數據(即元數據)的存放位置,能夠指定多個目錄實現容錯,多個目錄用逗號分隔 --> <name>dfs.namenode.name.dir</name> <value>/home/hadoop/namenode/data</value> </property> <property> <!-- datanode節點數據(即數據塊)的存放位置 --> <name>dfs.datanode.data.dir</name> <value>/home/hadoop/datanode/data</value> </property> <property> <!-- 集羣服務的邏輯名稱 --> <name>dfs.nameservices</name> <value>mycluster</value> </property> <property> <!-- NameNode ID列表--> <name>dfs.ha.namenodes.mycluster</name> <value>nn1,nn2</value> </property> <property> <!-- nn1的RPC通訊地址 --> <name>dfs.namenode.rpc-address.mycluster.nn1</name> <value>hadoop001:8020</value> </property> <property> <!-- nn2的RPC通訊地址 --> <name>dfs.namenode.rpc-address.mycluster.nn2</name> <value>hadoop002:8020</value> </property> <property> <!-- nn1的http通訊地址 --> <name>dfs.namenode.http-address.mycluster.nn1</name> <value>hadoop001:50070</value> </property> <property> <!-- nn2的http通訊地址 --> <name>dfs.namenode.http-address.mycluster.nn2</name> <value>hadoop002:50070</value> </property> <property> <!-- NameNode元數據在JournalNode上的共享存儲目錄 --> <name>dfs.namenode.shared.edits.dir</name> <value>qjournal://hadoop001:8485;hadoop002:8485;hadoop003:8485/mycluster</value> </property> <property> <!-- Journal Edit Files的存儲目錄 --> <name>dfs.journalnode.edits.dir</name> <value>/home/hadoop/journalnode/data</value> </property> <property> <!-- 配置隔離機制,確保在任何給定時間只有一個NameNode處於活動狀態 --> <name>dfs.ha.fencing.methods</name> <value>sshfence</value> </property> <property> <!-- 使用sshfence機制時須要ssh免密登陸 --> <name>dfs.ha.fencing.ssh.private-key-files</name> <value>/root/.ssh/id_rsa</value> </property> <property> <!-- SSH超時時間 --> <name>dfs.ha.fencing.ssh.connect-timeout</name> <value>30000</value> </property> <property> <!-- 訪問代理類,用於肯定當前處於Active狀態的NameNode --> <name>dfs.client.failover.proxy.provider.mycluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property> <property> <!-- 開啓故障自動轉移 --> <name>dfs.ha.automatic-failover.enabled</name> <value>true</value> </property> </configuration>
<configuration> <property> <!--配置NodeManager上運行的附屬服務。須要配置成mapreduce_shuffle後才能夠在Yarn上運行MapReduce程序。--> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <!-- 是否啓用日誌聚合(可選) --> <name>yarn.log-aggregation-enable</name> <value>true</value> </property> <property> <!-- 聚合日誌的保存時間(可選) --> <name>yarn.log-aggregation.retain-seconds</name> <value>86400</value> </property> <property> <!-- 啓用RM HA --> <name>yarn.resourcemanager.ha.enabled</name> <value>true</value> </property> <property> <!-- RM集羣標識 --> <name>yarn.resourcemanager.cluster-id</name> <value>my-yarn-cluster</value> </property> <property> <!-- RM的邏輯ID列表 --> <name>yarn.resourcemanager.ha.rm-ids</name> <value>rm1,rm2</value> </property> <property> <!-- RM1的服務地址 --> <name>yarn.resourcemanager.hostname.rm1</name> <value>hadoop002</value> </property> <property> <!-- RM2的服務地址 --> <name>yarn.resourcemanager.hostname.rm2</name> <value>hadoop003</value> </property> <property> <!-- RM1 Web應用程序的地址 --> <name>yarn.resourcemanager.webapp.address.rm1</name> <value>hadoop002:8088</value> </property> <property> <!-- RM2 Web應用程序的地址 --> <name>yarn.resourcemanager.webapp.address.rm2</name> <value>hadoop003:8088</value> </property> <property> <!-- ZooKeeper集羣的地址 --> <name>yarn.resourcemanager.zk-address</name> <value>hadoop001:2181,hadoop002:2181,hadoop003:2181</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> </configuration>
<configuration> <property> <!--指定mapreduce做業運行在yarn上--> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>
配置全部從屬節點的主機名或IP地址,每行一個。全部從屬節點上的DataNode
服務和NodeManager
服務都會被啓動。
hadoop001 hadoop002 hadoop003
將Hadoop安裝包分發到其餘兩臺服務器,分發後建議在這兩臺服務器上也配置一下Hadoop的環境變量。
# 將安裝包分發到hadoop002 scp -r /usr/app/hadoop-2.6.0-cdh5.15.2/ hadoop002:/usr/app/ # 將安裝包分發到hadoop003 scp -r /usr/app/hadoop-2.6.0-cdh5.15.2/ hadoop003:/usr/app/
分別到三臺服務器上啓動ZooKeeper服務:
zkServer.sh start
分別到三臺服務器的的${HADOOP_HOME}/sbin
目錄下,啓動journalnode
進程:
hadoop-daemon.sh start journalnode
在hadop001
上執行NameNode
初始化命令:
hdfs namenode -format
執行初始化命令後,須要將NameNode
元數據目錄的內容,複製到其餘未格式化的NameNode
上。元數據存儲目錄就是咱們在hdfs-site.xml
中使用dfs.namenode.name.dir
屬性指定的目錄。這裏咱們須要將其複製到hadoop002
上:
scp -r /home/hadoop/namenode/data hadoop002:/home/hadoop/namenode/
在任意一臺NameNode
上使用如下命令來初始化ZooKeeper中的HA狀態:
hdfs zkfc -formatZK
進入到hadoop001
的${HADOOP_HOME}/sbin
目錄下,啓動HDFS。此時hadoop001
和hadoop002
上的NameNode
服務,和三臺服務器上的DataNode
服務都會被啓動:
start-dfs.sh
進入到hadoop002
的${HADOOP_HOME}/sbin
目錄下,啓動YARN。此時hadoop002
上的ResourceManager
服務,和三臺服務器上的NodeManager
服務都會被啓動:
start-yarn.sh
須要注意的是,這個時候hadoop003
上的ResourceManager
服務一般是沒有啓動的,須要手動啓動:
yarn-daemon.sh start resourcemanager
成功啓動後,每臺服務器上的進程應該以下:
[root@hadoop001 sbin]# jps 4512 DFSZKFailoverController 3714 JournalNode 4114 NameNode 3668 QuorumPeerMain 5012 DataNode 4639 NodeManager [root@hadoop002 sbin]# jps 4499 ResourceManager 4595 NodeManager 3465 QuorumPeerMain 3705 NameNode 3915 DFSZKFailoverController 5211 DataNode 3533 JournalNode [root@hadoop003 sbin]# jps 3491 JournalNode 3942 NodeManager 4102 ResourceManager 4201 DataNode 3435 QuorumPeerMain
HDFS和YARN的端口號分別爲50070
和8080
,界面應該以下:
此時hadoop001上的NameNode
處於可用狀態:
而hadoop002上的NameNode
則處於備用狀態:
hadoop002上的ResourceManager
處於可用狀態:
hadoop003上的ResourceManager
則處於備用狀態:
同時界面上也有Journal Manager
的相關信息:
上面的集羣初次啓動涉及到一些必要初始化操做,因此過程略顯繁瑣。可是集羣一旦搭建好後,想要再次啓用它是比較方便的,步驟以下(首選須要確保ZooKeeper集羣已經啓動):
在 hadoop001
啓動 HDFS,此時會啓動全部與 HDFS 高可用相關的服務,包括 NameNode,DataNode 和 JournalNode:
start-dfs.sh
在hadoop002
啓動YARN:
start-yarn.sh
這個時候hadoop003
上的ResourceManager
服務一般仍是沒有啓動的,須要手動啓動:
yarn-daemon.sh start resourcemanager
以上搭建步驟主要參考自官方文檔:
關於Hadoop高可用原理的詳細分析,推薦閱讀:
Hadoop NameNode 高可用 (High Availability) 實現解析
更多大數據系列文章能夠參見我的 GitHub 開源項目: 大數據入門指南