天天看點

Hadoop 系列(八)—— 基于 ZooKeeper 搭建 Hadoop 高可用叢集

一、高可用簡介

Hadoop 高可用 (High Availability) 分為 HDFS 高可用和 YARN 高可用,兩者的實作基本類似,但 HDFS NameNode 對資料存儲及其一緻性的要求比 YARN ResourceManger 高得多,是以它的實作也更加複雜,故下面先進行講解:

1.1 高可用整體架構

HDFS 高可用架構如下:

圖檔引用自:https://www.edureka.co/blog/how-to-set-up-hadoop-cluster-with-hdfs-high-availability/

HDFS 高可用架構主要由以下元件所構成:

  • Active NameNode 和 Standby NameNode:兩台 NameNode 形成互備,一台處于 Active 狀态,為主 NameNode,另外一台處于 Standby 狀态,為備 NameNode,隻有主 NameNode 才能對外提供讀寫服務。
  • 主備切換控制器 ZKFailoverController:ZKFailoverController 作為獨立的程序運作,對 NameNode 的主備切換進行總體控制。ZKFailoverController 能及時檢測到 NameNode 的健康狀況,在主 NameNode 故障時借助 Zookeeper 實作自動的主備選舉和切換,當然 NameNode 目前也支援不依賴于 Zookeeper 的手動主備切換。
  • Zookeeper 叢集:為主備切換控制器提供主備選舉支援。
  • 共享存儲系統:共享存儲系統是實作 NameNode 的高可用最為關鍵的部分,共享存儲系統儲存了 NameNode 在運作過程中所産生的 HDFS 的中繼資料。主 NameNode 和 NameNode 通過共享存儲系統實作中繼資料同步。在進行主備切換的時候,新的主 NameNode 在确認中繼資料完全同步之後才能繼續對外提供服務。
  • DataNode 節點:除了通過共享存儲系統共享 HDFS 的中繼資料資訊之外,主 NameNode 和備 NameNode 還需要共享 HDFS 的資料塊和 DataNode 之間的映射關系。DataNode 會同時向主 NameNode 和備 NameNode 上報資料塊的位置資訊。

1.2 基于 QJM 的共享存儲系統的資料同步機制分析

目前 Hadoop 支援使用 Quorum Journal Manager (QJM) 或 Network File System (NFS) 作為共享的存儲系統,這裡以 QJM 叢集為例進行說明:Active NameNode 首先把 EditLog 送出到 JournalNode 叢集,然後 Standby NameNode 再從 JournalNode 叢集定時同步 EditLog,當 Active NameNode 當機後, Standby NameNode 在确認中繼資料完全同步之後就可以對外提供服務。

需要說明的是向 JournalNode 叢集寫入 EditLog 是遵循 “過半寫入則成功” 的政策,是以你至少要有 3 個 JournalNode 節點,當然你也可以繼續增加節點數量,但是應該保證節點總數是奇數。同時如果有 2N+1 台 JournalNode,那麼根據過半寫的原則,最多可以容忍有 N 台 JournalNode 節點挂掉。

1.3 NameNode 主備切換

NameNode 實作主備切換的流程下圖所示:

  1. HealthMonitor 初始化完成之後會啟動内部的線程來定時調用對應 NameNode 的 HAServiceProtocol RPC 接口的方法,對 NameNode 的健康狀态進行檢測。
  2. HealthMonitor 如果檢測到 NameNode 的健康狀态發生變化,會回調 ZKFailoverController 注冊的相應方法進行處理。
  3. 如果 ZKFailoverController 判斷需要進行主備切換,會首先使用 ActiveStandbyElector 來進行自動的主備選舉。
  4. ActiveStandbyElector 與 Zookeeper 進行互動完成自動的主備選舉。
  5. ActiveStandbyElector 在主備選舉完成後,會回調 ZKFailoverController 的相應方法來通知目前的 NameNode 成為主 NameNode 或備 NameNode。
  6. ZKFailoverController 調用對應 NameNode 的 HAServiceProtocol RPC 接口的方法将 NameNode 轉換為 Active 狀态或 Standby 狀态。

1.4 YARN高可用

YARN ResourceManager 的高可用與 HDFS NameNode 的高可用類似,但是 ResourceManager 不像 NameNode ,沒有那麼多的中繼資料資訊需要維護,是以它的狀态資訊可以直接寫到 Zookeeper 上,并依賴 Zookeeper 來進行主備選舉。

二、叢集規劃

按照高可用的設計目标:需要保證至少有兩個 NameNode (一主一備) 和 兩個 ResourceManager (一主一備) ,同時為滿足“過半寫入則成功”的原則,需要至少要有 3 個 JournalNode 節點。這裡使用三台主機進行搭建,叢集規劃如下:

三、前置條件

  • 所有伺服器都安裝有 JDK,安裝步驟可以參見:Linux 下 JDK 的安裝;
  • 搭建好 ZooKeeper 叢集,搭建步驟可以參見:Zookeeper 單機環境和叢集環境搭建
  • 所有伺服器之間都配置好 SSH 免密登入。

四、叢集配置

4.1 下載下傳并解壓

下載下傳 Hadoop。這裡我下載下傳的是 CDH 版本 Hadoop,下載下傳位址為:http://archive.cloudera.com/cdh5/cdh/5/

# tar -zvxf hadoop-2.6.0-cdh5.15.2.tar.gz            

4.2 配置環境變量

編輯

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           

4.3 修改配置

進入

${HADOOP_HOME}/etc/hadoop

目錄下,修改配置檔案。各個配置檔案内容如下:

1. hadoop-env.sh

# 指定JDK的安裝位置
export JAVA_HOME=/usr/java/jdk1.8.0_201/           

2. core-site.xml

<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>           

3. hdfs-site.xml

<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>           

4. yarn-site.xml

<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>           

5. mapred-site.xml

<configuration>
    <property>
        <!--指定 mapreduce 作業運作在 yarn 上-->
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>           

5. slaves

配置所有從屬節點的主機名或 IP 位址,每行一個。所有從屬節點上的

DataNode

服務和

NodeManager

服務都會被啟動。

hadoop001
hadoop002
hadoop003           

4.4 分發程式

将 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/           

五、啟動叢集

5.1 啟動ZooKeeper

分别到三台伺服器上啟動 ZooKeeper 服務:

zkServer.sh start           

5.2 啟動Journalnode

分别到三台伺服器的的

${HADOOP_HOME}/sbin

目錄下,啟動

journalnode

程序:

hadoop-daemon.sh start journalnode           

5.3 初始化NameNode

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/           

5.4 初始化HA狀态

在任意一台

NameNode

上使用以下指令來初始化 ZooKeeper 中的 HA 狀态:

hdfs zkfc -formatZK           

5.5 啟動HDFS

進入到

hadoop001

${HADOOP_HOME}/sbin

目錄下,啟動 HDFS。此時

hadoop001

hadoop002

上的

NameNode

服務,和三台伺服器上的

DataNode

服務都會被啟動:

start-dfs.sh           

5.6 啟動YARN

hadoop002

${HADOOP_HOME}/sbin

目錄下,啟動 YARN。此時

hadoop002

ResourceManager

NodeManager

start-yarn.sh           

需要注意的是,這個時候

hadoop003

ResourceManager

服務通常是沒有啟動的,需要手動啟動:

yarn-daemon.sh start resourcemanager           

六、檢視叢集

6.1 檢視程序

成功啟動後,每台伺服器上的程序應該如下:

[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           

6.2 檢視Web UI

HDFS 和 YARN 的端口号分别為

50070

8080

,界面應該如下:

此時 hadoop001 上的

NameNode

處于可用狀态:

而 hadoop002 上的

NameNode

則處于備用狀态:

<br/>

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           

參考資料

以上搭建步驟主要參考自官方文檔:

  • HDFS High Availability Using the Quorum Journal Manager
  • ResourceManager High Availability

繼續閱讀