Hadoop 系列(八)—— 基於 ZooKeeper 搭建 Hadoop 高可用集羣

1、高可用簡介

Hadoop 高可用 (High Availability) 分爲 HDFS 高可用和 YARN 高可用,二者的實現基本相似,但 HDFS NameNode 對數據存儲及其一致性的要求比 YARN ResourceManger 高得多,因此它的實現也更加複雜,故下面先進行講解:html

1.1 高可用總體架構

HDFS 高可用架構以下:java

https://github.com/heibaiying

圖片引用自:www.edureka.co/blog/how-to…node

HDFS 高可用架構主要由如下組件所構成:git

  • Active NameNode 和 Standby NameNode:兩臺 NameNode 造成互備,一臺處於 Active 狀態,爲主 NameNode,另一臺處於 Standby 狀態,爲備 NameNode,只有主 NameNode 才能對外提供讀寫服務。github

  • 主備切換控制器 ZKFailoverController:ZKFailoverController 做爲獨立的進程運行,對 NameNode 的主備切換進行整體控制。ZKFailoverController 能及時檢測到 NameNode 的健康情況,在主 NameNode 故障時藉助 Zookeeper 實現自動的主備選舉和切換,固然 NameNode 目前也支持不依賴於 Zookeeper 的手動主備切換。web

  • Zookeeper 集羣:爲主備切換控制器提供主備選舉支持。shell

  • 共享存儲系統:共享存儲系統是實現 NameNode 的高可用最爲關鍵的部分,共享存儲系統保存了 NameNode 在運行過程當中所產生的 HDFS 的元數據。主 NameNode 和 NameNode 經過共享存儲系統實現元數據同步。在進行主備切換的時候,新的主 NameNode 在確認元數據徹底同步以後才能繼續對外提供服務。apache

  • DataNode 節點:除了經過共享存儲系統共享 HDFS 的元數據信息以外,主 NameNode 和備 NameNode 還須要共享 HDFS 的數據塊和 DataNode 之間的映射關係。DataNode 會同時向主 NameNode 和備 NameNode 上報數據塊的位置信息。vim

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 在確認元數據徹底同步以後就能夠對外提供服務。bash

須要說明的是向 JournalNode 集羣寫入 EditLog 是遵循 「過半寫入則成功」 的策略,因此你至少要有 3 個 JournalNode 節點,固然你也能夠繼續增長節點數量,可是應該保證節點總數是奇數。同時若是有 2N+1 臺 JournalNode,那麼根據過半寫的原則,最多能夠容忍有 N 臺 JournalNode 節點掛掉。

https://github.com/heibaiying

1.3 NameNode 主備切換

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

https://github.com/heibaiying

  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 來進行主備選舉。

https://github.com/heibaiying

2、集羣規劃

按照高可用的設計目標:須要保證至少有兩個 NameNode (一主一備) 和 兩個 ResourceManager (一主一備) ,同時爲知足「過半寫入則成功」的原則,須要至少要有 3 個 JournalNode 節點。這裏使用三臺主機進行搭建,集羣規劃以下:

https://github.com/heibaiying

3、前置條件

4、集羣配置

4.1 下載並解壓

下載 Hadoop。這裏我下載的是 CDH 版本 Hadoop,下載地址爲: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、啓動集羣

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。此時 hadoop001hadoop002 上的 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、查看集羣

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 的端口號分別爲 500708080,界面應該以下:

此時 hadoop001 上的 NameNode 處於可用狀態:

https://github.com/heibaiying
而 hadoop002 上的 NameNode 則處於備用狀態:


https://github.com/heibaiying

hadoop002 上的 ResourceManager 處於可用狀態:


https://github.com/heibaiying

hadoop003 上的 ResourceManager 則處於備用狀態:


https://github.com/heibaiying

同時界面上也有 Journal Manager 的相關信息:


https://github.com/heibaiying

7、集羣的二次啓動

上面的集羣初次啓動涉及到一些必要初始化操做,因此過程略顯繁瑣。可是集羣一旦搭建好後,想要再次啓用它是比較方便的,步驟以下(首選須要確保 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 開源項目大數據入門指南

相關文章
相關標籤/搜索