1. 程式人生 > >HADOOP docker(二):HDFS 高可用原理

HADOOP docker(二):HDFS 高可用原理

原來 gem relative 超時 proxy 問題 要求 his pro

1.環境簡述
2.QJM HA簡述
2.1為什麽要做HDFS HA?
2.2 HDFS HA的方式
2.2 HSFS HA的結構
2.3 機器要求
3.部署HDFS HA
3.1 詳細配置
3.2 部署HDFS HA
4. HDFS HA的管理
5.自動切換
5.1 使用zookeeper實現HA原理
5. 部署hdfs自動切換
5.1 關閉集群
5.2 添加HA配置
5.3 在zookeeper中初始化HA狀態
5.4 開啟集群
5.5 使用zookeeper時的安全機制
6.FAQ
7.做了HA後HDFS的升級、回滾
7.1 升級
7.2 finalize
7.3 回滾

1.環境簡述

上從在docker上裝完hadoop集群後,發現有很多問題,又重新建了一個,如下:

主機名IP角色
hadoop1 172.18.0.11 NN1 ZK RM
hadoop2 172.18.0.12 NN2 ZK RM JOBHISTORY
hadoop3 172.18.0.13 DN ZK ND
hadoop4 172.18.0.14 DN QJM1 ND
hadoop5 172.18.0.15 DN QJM2 ND
hadoop6 172.18.0.16 DN QJM3 ND

目前已經安裝了hdfs yarn zookeeper

2.QJM HA簡述

2.1為什麽要做HDFS HA?

在hadoop2.0之前,集群中只能有一個namenode,如果這個namenode宕機或者需要對namenode進行升級,那麽整個集群的服務將不可用。因此要做HA。

2.2 HDFS HA的方式

目前支持兩種HA方式:

  1. NFS
    namenode和standby namenode共享一個NFS磁盤,所以namenode的元數據變更立即同步到standby中。缺點是如果namenode或者standby namenode與NFS磁盤之間的網絡出了問題,HA即失效,即把namenode單獨故障轉移到了NFS上,NFS同樣存在單點故障問題。
  2. QJM
    namenode和standby namenode分別連接到一組Journal節點中,如果namenode出了故障,可以把standby namenode切換到activer狀態,不影響集群使用。本方式配合zookeeper可以實現自動切換。

2.2 HSFS HA的結構

技術分享
以上是QJM HA的典型的結構圖。集群中共有兩個namenode(簡稱NN),其中只有一個是active狀態,另一個是standby狀態。active 的NN負責響應DN(datanode)的請求,為了最快的切換為active狀態,standby狀態的NN同樣也連接到所有的datenode上獲取最新的塊信息(blockmap)。

active NN會把元數據的修改(edit log)發送到多數的journal節點上(2n+1個journal節點,至少寫到n+1個上),standby NN從journal節點上讀取edit log,並實時的合並到自己的namespace中。另外standby NN連接所有DN,實時的獲取最新的blockmap。這樣,一旦active的NN出現故障,standby NN可以立即切換為active NN.

註意:同一時刻只能有一個NAMENODE寫edit log,否則將hdfs 元數據將會"腦裂"

2.3 機器要求

  1. 兩個配置完全一樣的namenode節點
  2. 2n+1個 journal節點,journal節點不需要很好的配置,可以與集群中的其它角色一起。

3.部署HDFS HA

3.1 詳細配置

HDFS HA中用,nameserivce ID來標識一個HDFS服務,為了標識每個NN,還要加上namenode id。
hdfs-site.xml中:
1.設置集群的標識dfs.nameservice

  1. <property>
  2. <name>dfs.nameservices</name>
  3. <value>mycluster</value>
  4. </property>

這裏修改為dockercluster

2.設置namenode名稱 dfs.ha.namenodes.[nameservice ID]

  1. <property>
  2. <name>dfs.ha.namenodes.mycluster</name>
  3. <value>nn1,nn2</value>
  4. </property>

nn1 nn2為namenode的標識。
註意:當前只支持兩個namenode的HA

3.設置namenode對外提供服務的RPC地址 dfs.namenode.rpc-address.[nameservice ID].[name node ID]

  1. <property>
  2. <name>dfs.namenode.rpc-address.mycluster.nn1</name>
  3. <value>machine1.example.com:8020</value>
  4. </property>
  5. <property>
  6. <name>dfs.namenode.rpc-address.mycluster.nn2</name>
  7. <value>machine2.example.com:8020</value>
  8. </property>

這個RPC地址實際就是 dfs.defaultFS地址

4.設置HDFS web頁面地址 dfs.namenode.http-address.[nameservice ID].[name node ID]

  1. <property>
  2. <name>dfs.namenode.http-address.mycluster.nn1</name>
  3. <value>machine1.example.com:50070</value>
  4. </property>
  5. <property>
  6. <name>dfs.namenode.http-address.mycluster.nn2</name>
  7. <value>machine2.example.com:50070</value>
  8. </property>

如果啟用的hdfs的安全機制,要設置 https-address

5.設置journal上edit log共享目錄 dfs.namenode.shared.edits.dir
格式是:qjournal://host1:port1;host2:port2;host3:port3/journalId 所有節點上路徑要保持一致

  1. <property>
  2. <name>dfs.namenode.shared.edits.dir</name><value>qjournal://node1.example.com:8485;node2.example.com:8485;node3.example.com:8485/mycluster</value>
  3. </property>

這裏我們改成: qjournal://hadoop4:8485;hadoop5:8485;hadoop6:8485/dockercluster

6.設置實現集群HA的類 dfs.client.failover.proxy.provider.[nameservice ID]

  1. <property>
  2. <name>dfs.client.failover.proxy.provider.mycluster</name>
  3. <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
  4. </property>

當前僅支持這個類

7.設置切換時執行的程序 dfs.ha.fencing.methods
當namenode發生切換時,原來active的NN可能依然在寫edit log,這時如果standby 也開始寫edit log,元數據會"腦裂"。為了防止"腦裂",必須要切換之前殺掉原來active 的NN,這個腳本就是實現這個目的。當前支持兩中fencing.method:shell 和 sshfence。另外,可能自定義org.apache.hadoop.ha.NodeFence來實現自己的保護程序。

7.1.sshfence(默認)
通過SSH登錄到原來active的NN,並使用fuser命令KILL掉NN進程。要使用SSH,必須配置rsa-key參數:dfs.ha.fencing.ssh.private-key-files

  1. <property>
  2. <name>dfs.ha.fencing.methods</name>
  3. <value>sshfence</value>
  4. </property>
  5. <property>
  6. <name>dfs.ha.fencing.ssh.private-key-files</name>
  7. <value>/home/hdfs/.ssh/id_rsa</value>
  8. </property>

也可以用其它用戶登錄,同樣可以配置超時參數:

  1. <property>
  2. <name>dfs.ha.fencing.methods</name>
  3. <value>sshfence([[username][:port]])</value>
  4. </property>
  5. <property>
  6. <name>dfs.ha.fencing.ssh.connect-timeout</name>
  7. <value>30000</value>
  8. </property>

7.2.shell
自定義一個shell腳本業殺死NAMENODE

  1. <property>
  2. <name>dfs.ha.fencing.methods</name>
  3. <value>shell(/path/to/my/script.sh arg1 arg2 ...)</value>
  4. </property>

shell腳本可以讀取到當前已經配置的HDFS變量,將"."替換為"_" 即可。對於某些共用的條目,如dfs_namenode_rpc-address可以自動的指向特定節點如dfs.namenode.rpc-address.ns1.nn1。以下變量也可以使用:

$target_host
$target_port
$target_address
$target_namenodeid

示例:

  1. <property>
  2. <name>dfs.ha.fencing.methods</name>
  3. <value>shell(/path/to/my/script.sh --nameservice=$target_nameserviceid $target_host:$target_port)</value>
  4. </property>

如果shell返回0,表示執行成功。如果不為0,則繼續執行其它的fencing.method.shell方式沒有timeout.

這時裏,我們也用ssh方式,比較簡單,只需要生成key就行了.在NN1 NN2上執行:

  1. [[email protected] ~]$ ssh-keygen -t rsa
  2. Generatingpublic/private rsa key pair.
  3. Enter file in which to save the key (/home/hdfs/.ssh/id_rsa):
  4. Enter passphrase (empty forno passphrase):
  5. Enter same passphrase again:
  6. Your identification has been saved in/home/hdfs/.ssh/id_rsa.
  7. Yourpublic key has been saved in/home/hdfs/.ssh/id_rsa.pub.
  8. The key fingerprint is:
  9. 6b:de:13:b7:55:ba:43:1c:28:ef:2e:b8:b7:0a:e0:15 [email protected]
  10. The key‘s randomart image is:
  11. +--[ RSA 2048]----+
  12. | |
  13. | |
  14. | E . |

8.在core-site.xml中設置hdfs 服務 fs.defaultFS
一旦使用了HDFS HA,那麽fs.defaultFS就不能寫成host:port文件,而要寫成服務方式,寫上nameservice id:

  1. <property>
  2. <name>fs.defaultFS</name>
  3. <value>hdfs://mycluster</value>
  4. </property>

這裏改成hdfs://dockercluster

9.journal節點守護進程自己的數據目錄 dfs.journalnode.edits.dir

  1. <property>
  2. <name>dfs.journalnode.edits.dir</name>
  3. <value>/path/to/journal/node/local/data</value>
  4. </property>

3.2 部署HDFS HA

1.啟動所有journal節點hadoop-daemon.sh start journalnode

2.如果是新建的集群,在其中一個NN上執行hdfs format命令hdfs namenode -format
3.如果從非HA集群升級為HA集群,或者是已經執行過hdfs format命令,把已經formatted的NN上的元數據拷貝到沒有formatted的NN上,然後在沒有formatted的NN上執行hdfs namenode -bootstrapStandby,該命令會讓journal節點做好連接兩個namenode的準備。
4.如果將非HA的NN切換為HA,執行hdfs namenode -initializeSharedEdits將本地的edit log初始化到journal中。
執行完以上後,像平時一樣啟動每個NN。
在每個NN的web頁面中,將會顯示NN的狀態是active或者standby

————————————————-更改—————————————–
後續更新:
在做實驗時發現,官網這個步驟有問題!
正確的步驟是:
1.啟動所有journal節點hadoop-daemon.sh start journalnode
2.執行journal 節點初始化hdfs namenode -initializeSharedEdits
3.啟動原來的namenode $HADOOP_HOME/sbin/hadoop-daemon.sh --config $HADOOP_CONF_DIR --script hdfs start namenode
4.初始化standby hdfs namenode -bootstrapStandby,
5.啟動standby $HADOOP_HOME/sbin/hadoop-daemon.sh --config $HADOOP_CONF_DIR --script hdfs start namenode
————————————————-更改—————————————–

.

4. HDFS HA的管理

HDFS HA的管理主要靠hdfs haadmin命令實現:

  1. [[email protected] ~]$ hdfs haadmin
  2. Usage: haadmin
  3. [-transitionToActive [--forceactive]<serviceId>]
  4. [-transitionToStandby <serviceId>]
  5. [-failover [--forcefence][--forceactive]<serviceId><serviceId>]
  6. [-getServiceState <serviceId>]
  7. [-checkHealth <serviceId>]
  8. [-help <command>]
  9. Generic options supported are
  10. -conf <configuration file> specify an application configuration file
  11. -D <property=value>use value for given property
  12. -fs <local|namenode:port> specify a namenode
  13. -jt <local|resourcemanager:port> specify a ResourceManager
  14. -files <comma separated list of files> specify comma separated files to be copied to the map reduce cluster
  15. -libjars <comma separated list of jars> specify comma separated jar files to include in the classpath.
  16. -archives <comma separated list of archives> specify comma separated archives to be unarchived on the compute machines.
  17. The general command line syntax is
  18. bin/hadoop command [genericOptions][commandOptions]
  • transitionToActive 和 transitionToStandby
    切換為active或者standby。註意:不會使用任務fencing措施,因此一般不使用這兩個命令,用hdfs haadmin -failover
  • failover
    對hdfs做一次主備切換。在切換前,如果原來active的NN現在是standby狀態,那麽會直接把原來standby的NN切換為active狀態。如果原來active狀態的NN還是acitve狀態,則會先將該NN切換為standby狀態,如果切換為standby失敗,則會調用dfs.ha.fencing.methods裏指定的fencing方式來確保原來的acitve NN被幹掉。如果沒有定義fencing方式,或者fencing執行失敗,則會拋出異常,同時不會切換原來的standby 為acitve
  • getServiceState
    獲取指定NN的狀態是active還是standby
  • checkHealth
    檢查指定NN的狀態。NN會對自己的服務做檢查,返回0表示正常,0之外的為異常。註意:當前這個功能還沒有實現(形同虛設),只要不停機就會返回0

5.自動切換

以上講了如何手動切換HA,現在來說說實在切換HA

5.1 使用zookeeper實現HA原理

自動切換的HA需要用到zookeeper中的兩個組件ZooKeeper quorum和ZKFailoverController process (ZKFC)。
zoookeeper會做以下兩件事:

  • Failure detection 失效檢測
    每個namenode都會在zookeeper裏保存一個持久會話,一旦某個namenode掛了,zookeeper中的會話就會過期,zookeeper檢測機制會通知另外一個namenode需要做failover了
  • Active NameNode election 選擇新的acitve namenode
    zookeeper可以通過簡單的機制來選出唯一一個acitve的namdenode.當active的namenode掛了後,另外一個namenode會在zookeeper中保存一個獨占鎖來標明自己將會是下一個active的namenode.
    ZKFC是同namenode在同一臺機器上的zookeeper客戶端。ZKFC負責以下事情:
  • Health monitoring 健康檢測
    ZKFC使用health-check命令定時去pingnamenode,如果在超時時間內得到了響應並且狀態是健康的(當前不是只能返回0嗎?),就認為namenode是健康的,如果超過時間沒有響應,則認為namenode宕機。
  • ZooKeeper session management 會話管理
    當namenode是健康的時間,ZKFC會和zookeeper保持一個會話,對於acitve的namenode節點,還會在zookeeper上創建一個臨時的znode(如/hdfs/active.lock),如果會話過期,則znode會被自動刪除
  • ZooKeeper session management
    在active的節點上ZKFC會在zookeeper裏創建一個臨時的znode並創建文件(如果/hdfs/acitve.lock),這時其它的namenode節點就不能創建同樣一個znode,那麽其它節點就會監控這個znode,一旦原來active的namenode宕機,則znode被刪除,原來standby的namenode上的ZKFC就可以創建znode並切換standby namenode為acitve

5. 部署hdfs自動切換

5.1 關閉集群

將手動的HA切換為自動的HA必須先關閉集群

5.2 添加HA配置

1.修改hdfs-site.xml
添加:

  1. <property>
  2. <name>dfs.ha.automatic-failover.enabled</name>
  3. <value>true</value>
  4. </property>

2.修改core-site.xml
添加zookeer的server列表:

  1. <property>
  2. <name>ha.zookeeper.quorum</name>
  3. <value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value>
  4. </property>

這裏我修改為 hadoop1 hadoop2 hadoop3

註意,如果使用了hdfs federation,需要加上nameservice-id,如dfs.ha.automatic-failover.enabled.my-nameservice-id.

5.3 在zookeeper中初始化HA狀態

在其中一臺namenode上執行:

[hdfs]HADOOP_PREFIX/bin/hdfs zkfc -formatZK

5.4 開啟集群

  • 使用start-dfs.sh啟動集群
    如果配置了SSH,使用start-dfs.sh啟動集群,該腳本會自動啟動ZKFC,然後ZKFC選擇出一個active的namenode
  • 手動啟動集群
    在每個namenode機器上執行:

    [hdfs]HADOOP_PREFIX/sbin/hadoop-daemon.sh - -script $HADOOP_PREFIX/bin/hdfs start zkfc

5.5 使用zookeeper時的安全機制

略,有興趣的自己上官網看吧。

6.FAQ

1.ZKFC和NAMENODE有沒有特定的啟動順序
2.需要對ZKFC進程做監控,某些時候自動切換失效是因為ZKFC掛了
3.如果zookeeper掛了,則自動failover失效,但不會到HDFS服務有影響。當zookeeper啟動後,自動failover功能恢復正常
4.當前並不技能人為的設置某個namenode為primary或者preferred
5.在自動HA的情況下,可以人為的切換namenode,執行hdfs hadmin命令。

7.做了HA後HDFS的升級、回滾

註意**在升級、回滾、finalization中必須保持所有journal節點是開啟的(至關重要!)

7.1 升級

1.停止所有的namenode,並安裝新的軟件
2.開啟所有的journal節點,註意在升級、回滾、finalization中必須保持所有journal節點是開啟的(至關重要!)
3.以-upgrade方式啟動一臺namenode
4.啟動後,一般該namenode會直接進入active狀態,然後執行本地元數據和JNs上edit log的升級
5.另外一臺要namenode如果使用-upgrade啟動會報錯,正確方式是重新初始化-bootstrapStandby

7.2 finalize

註意:如果做回滾或者finalization,則以正常方式重啟所有的namenode(不帶其它參數)
在active的namenode上執行hdfs dfsadmin -finalizeUpgrade,這裏active的NN將會定稿edit log並在本地上目錄中刪除舊版本的元數據

7.3 回滾

註意:如果做回滾或者finalization,則以正常方式重啟所有的namenode(不帶其它參數)
關閉所有的NN,在其中一臺namenode上執行roll back命令,然後啟動這個NN。在另外一個NN上執行-bootstrapStandby命令來同步狀態



null



HADOOP docker(二):HDFS 高可用原理