1. 程式人生 > >高可用完全分散式

高可用完全分散式

高可用叢集樣子

NN-1 NN-2 DN ZK ZKFC JNN
node01
node02 * *
node03 * *
node04 * *

這裡有些原則:各個程序(角色)放在一臺主機上,本地化傳輸方便,減少了網路IO
但是一臺節點上又會加重該節點的負載(cpu,記憶體,磁碟等)

高可用解決了NN單點故障問題,提高了可用性

有時候需要度量可用性與一致性的權衡問題:關於JN需要半數以上一致,NN就可以繼續寫入.首先明確一個概念:防止發生腦裂的最少需要同步的節點數叫做勢力範圍(恆為奇數),為了發生腦裂就得半數以上都同步才行,如果不可抗拒因素導致節點網路通訊中斷被分裂為2個獨立的通訊節點群,那麼少數的就會自殺,即使少數的是對的也會自殺,為了防止這種腦裂的事情發生所以需要同步的節點是半數以上(大於等於勢力範圍)。這樣就是說並不需要等待完全同步,NN再繼續寫入,只需要寫入的節點數大於等於勢力範圍即可,提高了可用性。

關於SSH免密比較特殊的是:需要NN2的公鑰給的主機和NN1配置一樣,因為standby和active能夠隨時轉換,同理hosts檔案也需要一樣。
(這裡有個主備切換的過程:當active壞了或者active的zkfc壞了,zookeeper都會通過zkfc的心跳接收到資訊,從而通過選舉找到下一個需要變為active的節點,通知到該節點的zkfc,然後先去連線那個壞的active節點,如果他是active(這種情況是因為原先的zkfc壞了,而NN沒壞,但是還是會被zookeeper更換狀態的),那就將其置為standby,然後將zkfc自己下面的NN置為active)

借鑑的一些說法:



HA即為High Availability,用於解決NameNode單點故障問題,該特性通過熱備的方式為主NameNode提供一個備用者,一旦主NameNode出現故障,可以迅速切換至備NameNode,從而實現對外提供更穩定的服務

SecondaryNameNode(冷備):只是階段性的合併edits和fsimage。當NN失效的時候,SNN無法立刻提供服務,甚至無法保證資料完整性:在SNN進行合併時,如果NN資料丟失的話,SNN也無法感知到,從而丟失部分操作

HDFS HA提供兩個NameNode,一個處於active狀態,對外提供服務;另一個處於standby狀態,同步元資料(在記憶體中)。當active狀態的NameNode掛掉時,standby轉為active。HA 是通過代理對外提供服務,客戶端請求由代理接收然後轉發到active狀態的NN

為了能夠實時同步Active和Standby兩個NameNode的元資料資訊,我們將元資料狀態(fsimage)和對元資料的操作(editlog)存放到 JN 叢集中,standby狀態的NN實時從JN中讀取資料並執行重演,同時所有DataNode向兩個NameNode都發送心跳,從而保證兩個NameNode狀態的同步

JNN叢集遵從半數以上的勢力劃分,所以其節點數量總為奇數。active-NN向JNN寫入editlog時,當半數以上的JNN節點儲存成功則停止寫入,其它JNN節點從這些已寫入的節點copy editlog。正常情況下叢集內各節點間保持通訊,standby-NN可以從任意節點上讀取到正確的資料,若是因為不可抗力而導致叢集分裂(叢集內節點通訊中斷),此時還可以相互通訊的節點組成叢集小勢力,那麼規定勢力範圍(叢集內節點數量)小於半數的叢集提供的資料視為無效。例如現在有3個JNN,分裂成了 1+1 和 1 兩股勢力,那麼此時即使 1 中的資料是正確的也會被視為無效,standby得知其節點數小於半數時會轉而去 1+1 中讀取資料


接下來,如果active狀態的NN掛掉了,我們就將另一臺切換為active狀態。那麼問題來了,active狀態的NN什麼時候會掛掉呢?難道我們要一直盯著伺服器看嗎?這當然是不可能的。這裡我們用到了zookeeper作為一個管理者代替我們進行監視。當然管理員也有管理員的脾氣,所以監視這種累人的工作zookeeper就交給了FailoverController。於是FailoverController就開始了兢兢業業的工作,認真的監視著兩個NN,並定時向zookeeper彙報NN的狀態資訊。如果active的NN掛掉了,FailoverController就彙報情況給zookeeper,得知情況後的zookeeper就通知監視另一個NN的FailoverController將standby的NN轉為active(如果有多個standby的NN則由zookeeper選舉出一個轉為active)。
那麼這裡有一個問題就是如果監視active狀態NN的FailoverController不幸掛掉了,那麼一定時間內沒有得到來自FailoverController心跳的zookeeper無法得知當前active狀態的NN究竟是否存活,就會認為其已經掛掉,會去選舉啟動一個新的active-NN,那麼這時可能就會同時存在兩臺active-NN,這時對外提供服務的代理可能就感覺不太好了,因為它無法確定要將請求轉發到哪一臺active-NN上。所以當FailoverController啟動新的active-NN的同時也會將原來為active狀態的NN置為standby而不管其是否已經掛掉,確保同一時間avtive狀態的NN只有一臺

具體的一些配置:

  1. 高可用性完全分散式中需要先配置zookeeper,再啟動(zkfc程序的格式化需要依賴這個)
    關於zookeeper,沒有在hadoop安裝包中

下載zookeeper安裝包並解壓,這裡以 zookeeper-3.4.12 為例。zookeeper是執行在 node02,node03 和 node04 上的,這裡我們先將安裝包放在node02上進行配置,配置結束後傳送到 node03 和 node04
將 zookeeper 安裝包下 conf 目錄下的 zoo_simple.cfg 修改為 zoo.cfg

[[email protected] conf]# mv  zoo_simple.cfg  zoo.cfg

修改 zoo.cfg 檔案,修改 dataDir 的位置(隨意修改)並新增服務配置,其中1、2、3是zookeeper的服務編號,後面是對應伺服器的主機名

dataDir=/var/abc/zookeeper
server.1=node02:2888:3888
server.2=node03:2888:3888
server.3=node04:2888:3888

建立你剛才宣告 dataDir的目錄,並在下面 建立一個myid檔案,在這個檔案中只寫上當前節點所對應的服務ID號。當前為 node02 節點,由上配置 server.1=node02:2888:3888 確定服務ID號為 1

[[email protected] ~]# cat /var/zgl/zookeeper/myid

將配置好的zookeeper安裝包傳送到node03 node04

[[email protected] software]# scp -r zookeeper-3.4.12 [email protected]:/opt/software/
[[email protected] software]# scp -r zookeeper-3.4.12 [email protected]:/opt/software/

在node03,node04 上分別修改 myid 中的 ID號。node03–>2,node04–>3
在 node02 node03 node04 上配置zookeeper的環境變數,這裡配置到使用者環境中,在 ~/.bashrc 檔案中新增如下

export PATH=$PATH:/opt/software/zookeeper-3.4.12/bin

在 node02 node03 node04 上分別執行 zkServer.sh start 命令啟動 zookeeper。
使用 jps 命令檢視,如果 QuorumPeerMain 程序啟動則配置成功

[[email protected] zgl]# jps
22035 QuorumPeerMain
23100 Jps
  1. 幾個配置檔案的配置
    先在 node01 上進行配置,配置完成後傳送到其他節點
    修改 hdfs-site.xml 檔案
<property>
        <name>dfs.nameservices</name>			<!-- 配置一個服務(叢集名稱) -->
        <value>mycluster</value>
</property>

<property>
        <name>dfs.ha.namenodes.mycluster</name>		<!--  提供服務的節點 -->
        <value>nn1,nn2</value>
</property>

<!-- 配置兩個NameNode的rpc協議的地址和埠 -->
<property>
        <name>dfs.namenode.rpc-address.mycluster.nn1</name>
        <value>node01:8020</value>
</property>
<property>
        <name>dfs.namenode.rpc-address.mycluster.nn2</name>
        <value>node02:8020</value>
</property>

<!-- 配置兩個NameNode的http協議的地址和埠 -->
<property>
        <name>dfs.namenode.http-address.mycluster.nn1</name>
        <value>node01:50070</value>
</property>
<property>
        <name>dfs.namenode.http-address.mycluster.nn2</name>
        <value>node02:50070</value>
</property>

<!-- 設定journalnade的位置資訊 -->
<property>
        <name>dfs.namenode.shared.edits.dir</name>
        <value>qjournal://node01:8485;node02:8485;node03:8485/mycluster</value>
</property>

<!-- journalnade儲存資料用的目錄-->
<property>
        <name>dfs.journalnode.edits.dir</name>
        <value>/var/abj/hadoop/ha/jn</value>
</property>

<!-- 通過代理類來讓客戶端連線active的NameNode -->
<property>
        <name>dfs.client.failover.proxy.provider.mycluster</name>
        <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

<!-- 通過遠端登入,殺掉NameNode來保證只有一個active的NameNode(保證
已經設定了免密登入) -->
<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>

<!--配置NameNode的自動切換的開關 -->
<property>
        <name>dfs.ha.automatic-failover.enabled</name>
        <value>true</value>
</property>

修改core-site.xml 檔案

<property>
   		<name>fs.defaultFS</name>		<!--  HDFS檔案預設地址字首(簡化實際訪問時路徑書寫) -->
  		<value>hdfs://mycluster</value>
</property>

<!--配置三臺zookeeper的位置資訊 -->
<property>
   		<name>ha.zookeeper.quorum</name>
   		<value>node02:2181,node03:2181,node04:2181</value>
</property>
<!-- HDFS檔案儲存位置,實際上預設是引用該地址這裡只是被引用了,所以該目錄下有很多資料 -->
<property>
        <name>hadoop.tmp.dir</name>			
        <value>/var/abcd/hadoop/cluster</value>
</property>

修改slaves配置檔案
配置DataNode節點,注意每行寫一個

node02
node03
node04

修改hadoop-env.sh配置檔案

#The java implementation to use.
export JAVA_HOME=/opt/zgl/jdk1.8.0_151
#在hadoop-env.sh 配置一條hadoop配置檔案所在目錄
export HADOOP_CONF_DIR=/opt/zgl/hadoop-2.6.5/etc/hadoop

重新整理配置 source hadoop-env.sh

高可用性完全分散式的啟動順序:
1.zookeeper啟動zkServer.sh start-》是zkfc程序格式化的前提

2.JN啟動hadoop-daemon.sh start journalnode-》主要用於namenode格式化

3.ANN格式化hdfs namenode -format-》如何用到journalnode叢集?一開始沒有edits檔案的(因為在完全分散式中NN的格式化只是建立了fsimage“檔案”和edits“物件”,可以通過在格式化完成後在檔案中尋找發現只有fsimage檔案,但沒有edits檔案)??就是一些簡單的連通,在叢集啟動的時候才會建立edits檔案

4.ANN啟動 hadoop-daemon.sh start namenode-》用於standbyNN的同步引導

5.SNN引導同步(不是啟動)hdfs namenode -bootstrapStandby->需要同步2臺name node之間的元資料。具體做法:從第一臺NN拷貝元資料(fsimage)到放到另一臺NN(磁碟中)(如果是格式化了那就沒有了,所以這一步也不需要了),然後啟動第一臺的NameNode程序,再到另一臺名稱節點上做standby引導(將叢集號之類基本資訊同步過去)。重啟動的時候記憶體中肯定已經沒有了元資料等,這個同步引導的過程??就是將一些資訊複製到SNN中磁碟中

6.格式化ZKFC(ZooKeeperFailoverContraller) hdfs zkfc -formatZK->依賴zookeeper的啟動,不知是否依賴NN的格式化?NN啟動??不依賴。僅僅依賴zookeeper啟動

7.關閉hdfs的程序(zookeeper除外)stop-dfs.sh-》這裡為何要關閉?為何要同時啟動??其實這裡沒有硬性要求,主要是防止腦裂

8.啟動start-dfs.sh

一些常用到的命令:
用命令檢視namenode的狀態(兩臺namenode,2個namenode節點的名字為nn1,nn2)

hdfs haadmin -getServiceState nn1

使用如下命令,將nn1強制切為active–>自動切換模式沒用,手動模式可以用

hdfs haadmin -transitionToActive --forcemanual nn1

active與standby切換,kill namenode 此時zkfc(監控)和zookeeper(監控和選舉)就會去自動切換,將另一個變為active ,你再去啟動剛才關閉的namenode就會被置為standby hadoop-daemon.sh namenode 自動模式就會來實現主備切換

關於格式化的一些理解

格式化操作:刪除資料資訊以及日誌檔案,生成一些引數檔案
每一次format主節點namenode,dfs/name/current目錄下的VERSION檔案會產生新的clusterID、namespaceID。但是如果子節點的dfs/name/current仍存在,hadoop格式化時就不會重建該目錄,因此形成子節點的clusterID、namespaceID與主節點(即namenode節點)的clusterID、namespaceID不一致。最終導致hadoop啟動失敗。

format:hdfs namenode -format,hdfs zkfc -formatZK

在執行hdfs namenode –format時僅建立了fsimage檔案,並沒有建立edits檔案,但已經建立了相關物件。這一點也可以在執行完format後在本地檔案系統中確認,目錄中只有fsimage檔案,但是可以理解為建立了