非HA弊端
HDFS叢集的分布式存儲是靠namenode節點(namenode負責響應用戶端請求)來實作。在非HA叢集中一旦namenode當機,雖然中繼資料不會丢失,但整個叢集将無法對外提供服務,導緻HDFS服務的可靠性不高,這在實際應用場景中顯然是不可行的。
HA機制
已知導緻服務可靠性不高的原因是namenode節點當機,那麼怎麼才能避免這個namenode節點當機呢?一個容易想到的解決方案是部署兩台namenode節點,形成主備模式(active/standby模式),這樣一旦active節點當機,standby節點立即切換到active模式。事實上HA機制就是采取的這種方案。要想實作該機制,需要解決以下問題:
1.為什麼選擇主備模式,而不是主主模式(active/active模式),也即讓兩個namenode節點都響應用戶端的請求
一個顯然的前提是,兩台namenode節點需要儲存一緻的中繼資料。
我們知道namenode節點是用來管理這些中繼資料的,響應用戶端請求時(上傳)需要增加中繼資料資訊,如果使用主主模式,那麼兩個節點都将對中繼資料進行寫操作,怎麼同步是個很困難的問題。是以,隻能有一台機器響應請求,也即處在active狀态的節點(可稱為主節點),而另一台namenode在主節點正常工作情況下僅用來同步active節點的中繼資料資訊,這個namenode稱為備用節點(處在standby狀态),可見,要解決的問題主要是怎麼同步active節點的中繼資料資訊。
2.怎麼同步兩個namenode節點的中繼資料
響應用戶端請求的是active節點,是以隻有active節點儲存了最新的中繼資料。中繼資料分為兩部分,一部分是剛寫入新的中繼資料(edits),另一部分是合并後的較舊的(fsimage)。HA機制解決同步問題的方法是将active節點新寫入的edits中繼資料放在zookeeper叢集上(zookeeper叢集主要功能是實作少量資料的分布式同步管理),standby節點在active節點正常情況下隻需要将zookeeper叢集上edits檔案同步到自己的fsimage中就可以。
Hadoop架構為這個叢集專門寫了個分布式應用qjournal(依賴zookeeper實作),實作qjournal的節點稱為journalnode。
3.怎麼感覺active節點是否當機,并将standby節點快速切換到active狀态?
解決方案是專門在namenode節點上啟動一個監控程序,時刻監控namenode的狀态。對于處在active狀态的namenode,如果發現不正常就向zookeeper叢集中寫入一些資料。對于處在standby狀态的namenode,監控程序從zookeeper叢集中讀資料,進而感覺到active節點是否正常。如果發現異常,監控程序負責将standby狀态切換到active狀态。這個監控程序在hadoop中叫做zkfc(依賴zookeeper實作)。
4.如何在狀态切換時避免brain split(腦裂)?
腦裂:active namenode工作不正常後,zkfc在zookeeper中寫入一些資料,表明異常,這時standby namenode中的zkfc讀到異常資訊,并将standby節點置為active。但是,如果之前的active namenode并沒有真的死掉,出現了假死(死了一會兒後又正常了,哈哈,是不是很搞笑),這樣,就有兩台namenode同時工作了。這種現象稱為腦裂。
解決方案:standby namenode感覺到主用節點出現異常後并不會立即切換狀态,zkfc會首先通過ssh遠端殺死active節點的 namenode程序(kill -9 程序号)。但是(這樣還不行,驚訝),如果kill指令沒有執行成功咋辦??如果在一段時間内沒有收到執行成功的回執,standby節點會執行一個自定義腳本,盡量保證不會出現腦裂問題!這個機制在hadoop中稱為fencing(包括ssh發送kill指令,執行自定義腳本兩道保障)
解決上訴問題以後,基本上就實作了hadoop HA 。
HA實作
1.HA叢集規劃
機名 軟體 程序
hadoop01 jdk,hadoop,zookeeper QuorumPeerMain(zookeeper),journalnode,datanode,nodemanager
hadoop02 jdk,hadoop,zookeeper QuorumPeerMain(zookeeper),journalnode,datanode,nodemanager
hadoop03 jdk,hadoop,zookeeper QuorumPeerMain(zookeeper),journalnode,datanode,nodemanager
hadoop04 jdk,hadoop namenode,zkfc(active)
hadoop05 jdk,hadoop namenode,zkfc
hadoop06 jdk,hadoop resourcemanager
hadoop07 jdk,hadoop resourcemanager
(注:datanode,nodemanager一般放到一起。journalnode依賴zookeeper來實作,是以QuorumPeerMain(zookeeper),journalnode必須放一起!)
2.叢集安裝前的環境檢查
時間同步:
在指令行中做如下操作,來安裝ntpdate
yum install -y ntp
繼續在指令行中操作,進行同步時間
ntpdate 210.72.145.44 #中國國家授時中心
關閉防火牆:
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall開機啟動
設定主機名映射(root使用者)
機器之間的主機名和IP建立映射關系
192.168.169.129 hadoop01
192.168.169.130 hadoop02
192.168.169.131 hadoop03
192.168.169.132 hadoop04
192.168.169.133 hadoop05
192.168.169.134 hadoop06
192.168.169.135 hadoop07
建立專有的使用者(root使用者)
一般是建專有的hadoop使用者,不在root使用者上面搭建
建立組和使用者
這裡每台虛拟主機都應該有hadoop使用者
#先建立組cloud
groupadd cloud
#建立使用者并加入組cloud
useradd -g cloud hadoop
#修改使用者hadoop的密碼
passwd hadoop
将hadoop使用者加到sodu清單
1、檢視/etc/sudoers的權限
ls -l /etc/sudoers

可以看的是隻讀權限,如果我們要修改就必須先改變該檔案的權限
2、修改權限
chmod 777 /etc/sudoers
3、将hadoop添加root權限
vim /etc/sudoers
在root下加入下面hadoop使用者
4、還原權限
chmod 440 /etc/sudoers
拷貝/etc/sudoers到其它主機
scp /etc/sudoers hadoop02:/etc/
scp /etc/sudoers hadoop03:/etc/
scp /etc/sudoers hadoop04:/etc/
scp /etc/sudoers hadoop05:/etc/
scp /etc/sudoers hadoop06:/etc/
scp /etc/sudoers hadoop07:/etc/
配置免密碼登入(hadoop使用者)
切換hadoop使用者
su hadoop
進入到目前使用者的根目錄
cd ~
檢視所有檔案
ls –la
進入.ssh目錄
cd .ssh
生産公鑰和私鑰(四個回車)
ssh-keygen -t rsa
執行完這個指令後,會生成兩個檔案id_rsa(私鑰)、id_rsa.pub(公鑰)
将公鑰拷貝到要免登陸的機器上
ssh-copy-id hadoop01
ssh-copy-id hadoop02
ssh-copy-id hadoop03
ssh-copy-id hadoop04
ssh-copy-id hadoop05
ssh-copy-id hadoop06
ssh-copy-id hadoop07
這時會在hadoop02
主機的.ssh/下産生一個名為authorized_keys的檔案,這時通過 ssh hadoop02時可以直接免登陸進入主機
如下:
同理可以給其他機器也設定免密碼登入。
準備軟體
在/home/hadoop/下建立cloud檔案夾,用來安裝相關軟體,同時所用安裝包放在cloud下的soft-install檔案夾下,如:
cd /home/hadoop
mkdir cloud
mkdir soft-install
上傳我們所需要的軟體到這個目錄
安裝jdk
解壓
tar -zxvf jdk-8u91-linux-x64.tar.gz -C /home/hadoop/cloud/
配置環境變量
# 修改配置檔案
sudo vi /etc/profile
# 在最後下添加
export JAVA_HOME=/home/hadoop/cloud/jdk1.8.0_91
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
# 重新整理配置檔案
source /etc/profile
将jdk和環境變量分别拷貝到其他主機上
可以直接将cloud檔案夾複制過去
scp -r cloud/ hadoop02:/home/hadoop/
scp -r cloud/ hadoop03:/home/hadoop/
scp -r cloud/ hadoop04:/home/hadoop/
scp -r cloud/ hadoop05:/home/hadoop/
scp -r cloud/ hadoop06:/home/hadoop/
scp -r cloud/ hadoop07:/home/hadoop/
将環境變量拷貝到其他主機下
sudo scp /etc/profile hadoop02:/etc/
sudo scp /etc/profile hadoop03:/etc/
sudo scp /etc/profile hadoop04:/etc/
sudo scp /etc/profile hadoop05:/etc/
sudo scp /etc/profile hadoop06:/etc/
sudo scp /etc/profile hadoop07:/etc/
重新整理環境變量
source /etc/profile
安裝zookeeper
如果不懂Zookeeper請參考:https://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/
下載下傳位址:http://mirrors.hust.edu.cn/apache/zookeeper/
安裝
前面我們已經安裝的jdk,現在我們在hadoop01、hadoop02、hadoop03上安裝Zookeeper
1、解壓
tar -zxvf zookeeper-3.4.9.tar.gz -C /home/hadoop/cloud/
2、修改Zookeeper的預設配置 conf/zoo_sample.cfg
mv zoo_sample.cfg zoo.cfg
vi zoo.cfg
配置如下:
#修改dataDir指向我們資料
dataDir=/home/hadoop/cloud/zookeeper-3.4.9/data
#并在最後添加
server.1=hadoop01:2888:3888
server.2=hadoop02:2888:3888
server.3=hadoop03:2888:3888
3、在/home/hadoop/cloud/zookeeper-3.4.9/目錄下建立data檔案夾
mkdir data
4、在data檔案夾下建立myid檔案指明本機id
vi myid
id 分别對應為hadoop01為1,hadoop02為2,hadoop03為3 後面我們再統一拷貝
5、複制zookeeper-3.4.8到hadoop02、hadoop03機器上并修改相應的myid
scp -r zookeeper-3.4.9/ hadoop02:/home/hadoop/cloud/zookeeper-3.4.9/
scp -r zookeeper-3.4.9/ hadoop03:/home/hadoop/cloud/zookeeper-3.4.9/
啟動Zookeeper
分别在hadoop01、hadoop02、hadoop03上啟動Zookeeper
#執行/home/hadoop/cloud/zookeeper-3.4.9/bin目錄下的腳本啟動
./zkServer.sh start
檢視zookeeper的狀态
./zkServer.sh status
在bin/目錄下運作,運作結果如下說明成功(此時至少運作2台)
其實我們可以找到leader 然後stop,會發現Zookeeper會立即切換Leader
安裝hadoop
安裝(現在hadoop01安裝,然後複制其他機器)
解壓
tar -zxvf hadoop-2.7.3.tar.gz -C /home/hadoop/cloud/
配置環境變量
# 修改配置檔案
sudo vi /etc/profile
# 在最後下添加
export HADOOP_HOME=/home/hadoop/cloud/hadoop-2.7.3
export PATH=$PATH:$HADOOP_HOME/bin
# 重新整理配置檔案
source /etc/profile
測試:
which hadoop
修改配置檔案(6個)
#hadoop2.x的配置檔案全部在$HADOOP_HOME/etc/hadoop下
cd /home/hadoop/cloud/hadoop-2.7.3/etc/hadoop
hadoop-env.sh
# The java implementation to use.
export JAVA_HOME=/home/hadoop/cloud/jdk1.8.0_91
core-site.xml
<configuration>
<!-- 指定hadoop運作時産生檔案的存儲路徑 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/home/hadoop/cloud/hadoop-2.7.3/tmp</value>
</property>
<!-- 指定hdfs的nameservice為ns1 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://ns1</value>
</property>
<!-- 指定zookeeper位址,多個用,分割 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<!-- dfs.nameservices 命名空間的邏輯名稱,多個用,分割 -->
<property>
<name>dfs.nameservices</name>
<value>ns1</value>
</property>
<!-- 指定ns1下有兩個namenode,分别是nn1,nn2 -->
<property>
<name>dfs.ha.namenodes.ns1</name>
<value>nn1,nn2</value>
</property>
<!-- 指定nn1的RPC通信位址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn1</name>
<value>hadoop04:8020</value>
</property>
<!-- 指定nn1的HTTP通信位址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn1</name>
<value>hadoop04:50070</value>
</property>
<!-- 指定nn2的RPC通信位址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn2</name>
<value>hadoop05:8020</value>
</property>
<!-- 指定nn2的HTTP通信位址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn2</name>
<value>hadoop05:50070</value>
</property>
<!-- 指定namenode的中繼資料存放的Journal Node的位址,必須基數,至少三個 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop01:8485;hadoop02:8485;hadoop03:8485/ns1</value>
</property>
<!--這是JournalNode程序保持邏輯狀态的路徑。這是在linux伺服器檔案的絕對路徑-->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/home/hadoop/cloud/hadoop-2.7.3/journal/</value>
</property>
<!-- 開啟namenode失敗後自動切換 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!-- 配置失敗自動切換實作方式 -->
<property>
<name>dfs.client.failover.proxy.provider.ns1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 配置隔離機制方法,多個機制用換行分割 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>
<!-- 使用sshfence隔離機制時需要ssh免登陸 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hadoop/.ssh/id_rsa</value>
</property>
<!-- 配置sshfence隔離機制逾時時間30秒 -->
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
</configuration>
mapred-site.xml.template
需要重命名: mv mapred-site.xml.template mapred-site.xml
<configuration>
<!-- 通知架構MR使用YARN -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
yarn-site.xml
<configuration>
<!-- 開啟RM高可用 -->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<!-- 指定RM的cluster id -->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yrc</value>
</property>
<!-- 指定RM的名字 -->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<!-- 分别指定RM的位址 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop06</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>hadoop07</value>
</property>
<!-- 指定zk叢集位址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>
修改/home/hadoop/cloud/hadoop-2.7.3/etc/hadoop/slaves檔案
slaves檔案是指定子節點的位置
要在hadoop4上啟動hdfs,按照叢集配置,需要指定datanode在hadoop01,hadoop02,hadoop3上
要在hadoop6上啟動yarn,按照叢集配置,需要指定nodemanager在hadoop01,hadoop02,hadoop3上。
vi slaves
#子節點的位置
hadoop01
hadoop02
hadoop03
并在 hadoop-2.7.3檔案下 建立tmp檔案:
mkdir tmp
将配置好的檔案拷貝到其他主機
scp -r hadoop-2.7.3/ hadoop02:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop03:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop04:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop05:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop06:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop07:/home/hadoop/cloud/hadoop-2.7.3/
将環境變量拷貝到其他主機下
sudo scp /etc/profile hadoop02:/etc/
sudo scp /etc/profile hadoop03:/etc/
sudo scp /etc/profile hadoop04:/etc/
sudo scp /etc/profile hadoop05:/etc/
sudo scp /etc/profile hadoop06:/etc/
sudo scp /etc/profile hadoop07:/etc/
重新整理環境變量
source /etc/profile
啟動
啟動的時候注意啟動順序
1、啟動zookeeper(在hadoop01、02、03)
./zkServer.sh start
檢視zookeeper狀态:./zkServer.sh status, 正确的狀态是一個leader,兩個follower。
2、啟動journal node(在hadoop01、02、03)
#hadoop-2.7.3/sbin下
./sbin/hadoop-daemon.sh start journalnode
啟動成功後會多出一個JournalNode程序。
3.格式化HDFS
在hadoop04上執行格式化指令:./bin/hadoop namenode -format
并把/home/hadoop/cloud/hadoop-2.7.3/tmp 檔案夾拷貝到另一台namenode的目錄下
scp -r /home/hadoop/cloud/hadoop-2.7.3/tmp hadoop05:/home/hadoop/cloud/hadoop-2.7.3/
4.格式化zkfc
在hadoop4上執行格式化指令:./bin/hdfs zkfc -formatZK
格式化成功後會在zookeeper叢集建立新的檔案路徑(該路徑下存放zkfc監控namenode節點的資訊)
5、啟動zkfc來監控NN狀态(在hadoop04、05)
./sbin/hadoop-daemon.sh start zkfc
6、啟動HDFS(namenode)(在hadoop04即可)
#hadoop-2.7.3/sbin下
./sbin/start-dfs.sh
7、啟動YARN
在hadoop06上執行./sbin/start-yarn.sh
在hadoop07上執行./sbin/yarn-daemon.sh start resourcemanager
通過浏覽器測試如下:
http://192.168.169.132:50070/
http://192.168.169.133:50070/
可以看出hadoop04的namenode是處于一種standby狀态,那麼hadoop05應該是處于active狀态
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2
把hadoop05(192.168.169.133)的namenode 程序kill掉
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2
可以看出hadoop04的namenode是處于一種active狀态,hadoop05不能通路
重新啟動hadoop05的namenode
./sbin/hadoop-daemon.sh start namenode
hadoop05會變成standby狀态
檢視YARN的狀态
http://192.168.169.134:8088/
輸入:http://192.168.169.135:8088/ 會跳轉到 http://hadoop06:8088/