使用 Quorum Journal Manager 的 HDFS 高可用性

目的

本指南概述 HDFS 高可用性 (HA) 功能,以及如何使用仲裁日誌管理員 (QJM) 功能設定和管理 HA HDFS 集群。

本文檔假設讀者對 HDFS 集群中的一般組件和節點類型有基本的了解。請參閱 HDFS 架構指南以取得詳細資訊。

注意:使用仲裁日誌管理員或傳統共享儲存

本指南說明如何設定和使用 HDFS HA,並使用仲裁日誌管理員 (QJM) 在活動和備用 NameNode 之間共用編輯日誌。如需有關如何設定 HDFS HA 以使用 NFS 作為共享儲存而非 QJM 的資訊,請參閱 此替代指南。如需有關如何設定 HDFS HA 以使用觀察者 NameNode 的資訊,請參閱 此指南

背景

在 Hadoop 2.0.0 之前,NameNode 是 HDFS 集群中的單點故障 (SPOF)。每個集群只有一個 NameNode,如果該機器或程序無法使用,則整個集群將無法使用,直到 NameNode 重新啟動或在另一台機器上啟動。

這會以兩種主要方式影響 HDFS 集群的總可用性

  • 如果發生機器故障等意外事件,則集群將無法使用,直到操作員重新啟動 NameNode。

  • 在 NameNode 機器上進行軟體或硬體升級等計畫維護事件將導致集群停機。

HDFS 高可用性功能透過在同一集群中以主動/被動設定執行兩個 (3.0.0 以上為兩個以上) 冗餘 NameNode 來解決上述問題,並提供熱備援。這允許在機器故障時快速故障轉移到新的 NameNode,或為了計畫維護而進行優雅的管理員啟動故障轉移。

架構

在典型的 HA 集群中,兩個或更多獨立的機器會設定為 NameNode。在任何時間點,恰好只有一個 NameNode 處於活動狀態,而其他則處於備用狀態。活動 NameNode 負責叢集中的所有用戶端操作,而備用 NameNode 僅充當工作人員,維護足夠的狀態,以便在必要時提供快速故障轉移。

為了讓備用節點讓其狀態與活動節點保持同步,兩個節點都會與稱為「JournalNode」(JN) 的一組獨立守護程式通訊。當活動節點執行任何名稱空間修改時,它會將修改記錄永久記錄到這些 JN 的大多數。備用節點能夠從 JN 讀取編輯,並且會持續觀察它們以了解編輯記錄的變更。當備用節點看到編輯時,它會將它們套用至自己的名稱空間。在故障轉移的情況下,備用節點會確保在將自己提升至活動狀態之前,已從 JournalNode 讀取所有編輯。這可確保在故障轉移發生之前,名稱空間狀態已完全同步。

為了提供快速故障轉移,備用節點還必須擁有有關叢集中區塊位置的最新資訊。為了達成此目的,DataNode 會設定為所有 NameNode 的位置,並將區塊位置資訊和心跳傳送給所有 NameNode。

對於 HA 集群的正確操作而言,一次只有一個 NameNode 處於活動狀態至關重要。否則,名稱空間狀態會在兩者之間快速分歧,冒著資料遺失或其他不正確結果的風險。為了確保此屬性並防止所謂的「分裂腦情況」,JournalNode 一次只會允許一個 NameNode 成為寫入器。在故障轉移期間,要成為活動狀態的 NameNode 只會接管寫入 JournalNode 的角色,這將有效阻止其他 NameNode 繼續處於活動狀態,讓新的活動 NameNode 能夠安全地繼續進行故障轉移。

硬體資源

為了部署 HA 集群,您應該準備下列事項

  • NameNode 機器 - 您執行活動和備用 NameNode 的機器應該具有彼此相同的硬體,以及在非 HA 集群中使用的相同硬體。

  • JournalNode 機器 - 執行 JournalNode 的機器。JournalNode 程式相對輕量,因此這些程式可以合理地與其他 Hadoop 程式並置於機器上,例如 NameNode、JobTracker 或 YARN ResourceManager。注意:至少必須有 3 個 JournalNode 程式,因為編輯記錄修改必須寫入大多數的 JN。這將允許系統容忍單一機器故障。您也可以執行超過 3 個 JournalNode,但為了實際增加系統可以容忍的故障數量,您應該執行奇數個 JN(即 3、5、7 等)。請注意,在執行 N 個 JournalNode 時,系統最多可以容忍 (N - 1) / 2 個故障並繼續正常運作。

請注意,在 HA 群集中,備用 NameNode 也會執行名稱空間狀態的檢查點,因此不需要在 HA 群集中執行次要 NameNode、檢查點節點或備份節點。事實上,這樣做會是一個錯誤。這也允許重新設定非 HA 已啟用 HDFS 群集為 HA 已啟用的人員重複使用他們先前專門用於次要 NameNode 的硬體。

部署

設定總覽

與聯合設定類似,HA 設定向下相容,並允許現有的單一 NameNode 設定在不變更的情況下運作。新設定的設計讓群集中的所有節點都可以有相同的設定,而不需要根據節點的類型將不同的設定檔部署到不同的機器。

與 HDFS 聯合一樣,HA 群集重複使用 名稱服務 ID 來識別實際上可能包含多個 HA NameNode 的單一 HDFS 執行個體。此外,HA 新增了一個稱為 NameNode ID 的新抽象。群集中每個不同的 NameNode 都有一個不同的 NameNode ID 來區分它。為了支援所有 NameNode 的單一設定檔,相關設定參數會加上 名稱服務 IDNameNode ID 的字尾。

設定詳細資料

若要設定 HA NameNode,您必須在 hdfs-site.xml 設定檔中新增幾個設定選項。

設定這些設定的順序並不重要,但您為 dfs.nameservicesdfs.ha.namenodes.[nameservice ID] 選擇的值將決定後續設定的鍵。因此,您應該在設定其他設定選項之前決定這些值。

  • dfs.nameservices - 此新名稱服務的邏輯名稱

    為此名稱服務選擇一個邏輯名稱,例如「mycluster」,並將此邏輯名稱用於此設定選項的值。您選擇的名稱是任意的。它將用於設定和作為叢集中絕對 HDFS 路徑的權限元件。

    注意:如果您也使用 HDFS 聯盟,此設定也應包含其他名稱服務的清單(HA 或其他),以逗號分隔清單。

    <property>
      <name>dfs.nameservices</name>
      <value>mycluster</value>
    </property>
    
  • dfs.ha.namenodes.[名稱服務 ID] - 名稱服務中每個 NameNode 的唯一識別碼

    使用逗號分隔的 NameNode ID 清單設定。這將由資料節點用於判斷叢集中的所有 NameNode。例如,如果您先前使用「mycluster」作為名稱服務 ID,並希望使用「nn1」、「nn2」和「nn3」作為 NameNode 的個別 ID,您會這樣設定

    <property>
      <name>dfs.ha.namenodes.mycluster</name>
      <value>nn1,nn2, nn3</value>
    </property>
    

    注意:HA 的 NameNode 最小數量為兩個,但您可以設定更多。建議不要超過 5 個(建議 3 個 NameNode),因為會產生通訊負擔。

  • dfs.namenode.rpc-address.[名稱服務 ID].[名稱節點 ID] - 讓每個 NameNode 監聽的完整 RPC 位址

    對於先前設定的兩個 NameNode ID,設定 NameNode 程序的完整位址和 IPC 埠。請注意,這會產生兩個獨立的設定選項。例如

    <property>
      <name>dfs.namenode.rpc-address.mycluster.nn1</name>
      <value>machine1.example.com:8020</value>
    </property>
    <property>
      <name>dfs.namenode.rpc-address.mycluster.nn2</name>
      <value>machine2.example.com:8020</value>
    </property>
    <property>
      <name>dfs.namenode.rpc-address.mycluster.nn3</name>
      <value>machine3.example.com:8020</value>
    </property>
    

    注意:如果您希望,也可以類似地設定「servicerpc-address」設定。

  • dfs.namenode.http-address.[名稱服務 ID].[名稱節點 ID] - 讓每個 NameNode 監聽的完整 HTTP 位址

    類似於上述的 rpc-address,設定兩個 NameNode 的 HTTP 伺服器要監聽的位址。例如

    <property>
      <name>dfs.namenode.http-address.mycluster.nn1</name>
      <value>machine1.example.com:9870</value>
    </property>
    <property>
      <name>dfs.namenode.http-address.mycluster.nn2</name>
      <value>machine2.example.com:9870</value>
    </property>
    <property>
      <name>dfs.namenode.http-address.mycluster.nn3</name>
      <value>machine3.example.com:9870</value>
    </property>
    

    注意:如果您已啟用 Hadoop 的安全功能,您也應為每個 NameNode 類似地設定 https-address

  • dfs.namenode.shared.edits.dir - 識別 NameNode 會寫入/讀取編輯的 JN 群組的 URI

    這是設定提供共用編輯儲存空間的 JournalNode 位址的地方,由 Active NameNode 寫入,並由備用 NameNode 讀取,以隨時更新 Active NameNode 所做的所有檔案系統變更。雖然您必須指定多個 JournalNode 位址,但您應只設定其中一個 URI。URI 應採用以下格式:qjournal://*host1:port1*;*host2:port2*;*host3:port3*/*journalId*。日誌 ID 是此名稱服務的唯一識別碼,允許一組 JournalNode 為多個聯盟名稱系統提供儲存空間。雖然不是必要條件,但建議為日誌識別碼重複使用名稱服務 ID。

    例如,如果此叢集的 JournalNode 在機器「node1.example.com」、「node2.example.com」和「node3.example.com」上執行,而名稱服務 ID 為「mycluster」,您會將下列內容用作此設定的值(JournalNode 的預設埠為 8485)

    <property>
      <name>dfs.namenode.shared.edits.dir</name>
      <value>qjournal://node1.example.com:8485;node2.example.com:8485;node3.example.com:8485/mycluster</value>
    </property>
    
  • dfs.client.failover.proxy.provider.[名稱服務 ID] - HDFS 客戶端用於連絡 Active NameNode 的 Java 類別

    設定 Java 類別的名稱,DFS Client 會使用該名稱來判斷哪個 NameNode 是目前的 Active,因此哪個 NameNode 目前正在服務客戶端要求。目前與 Hadoop 一起提供的兩個實作是 ConfiguredFailoverProxyProviderRequestHedgingProxyProvider(對於第一次呼叫,會同時呼叫所有名稱節點來判斷哪個是 active 的,而在後續要求中,會呼叫 active 的名稱節點,直到發生故障轉移),因此請使用其中一個,除非您正在使用自訂代理程式提供者。例如

    <property>
      <name>dfs.client.failover.proxy.provider.mycluster</name>
      <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
    </property>
    
  • dfs.ha.fencing.methods - 一份腳本或 Java 類別清單,將會在故障轉移期間用來隔離 Active NameNode

    對於系統的正確性而言,在任何給定的時間,只有一個 NameNode 處於 Active 狀態是理想的。重要的是,在使用 Quorum Journal Manager 時,只會允許一個 NameNode 寫入 JournalNodes,因此不會有從分割腦情況損毀檔案系統元資料的可能性。不過,當發生故障轉移時,前一個 Active NameNode 仍有可能對客戶端提供讀取要求,而這些要求可能在該 NameNode 嘗試寫入 JournalNodes 時關閉之前就已經過時。因此,即使在使用 Quorum Journal Manager 時,設定一些隔離方法仍然是理想的。不過,為了在隔離機制失敗時提升系統的可用性,建議設定一個隔離方法,以確保在清單中最後一個隔離方法時保證傳回成功。請注意,如果您選擇不使用任何實際的隔離方法,您仍必須為此設定設定一些內容,例如「shell(/bin/true)」。

    在故障轉移期間使用的隔離方法會設定為一個以換行符號分隔的清單,會依序嘗試,直到其中一個表示隔離已成功。Hadoop 提供兩種方法:shellsshfence。如需實作您自己的自訂隔離方法的資訊,請參閱 org.apache.hadoop.ha.NodeFencer 類別。


    sshfence - SSH 到 Active NameNode 並終止程序

    sshfence 選項會 SSH 到目標節點,並使用 fuser 終止在服務 TCP 埠上監聽的程序。為了讓這個隔離選項運作,它必須能夠在不提供密碼的情況下 SSH 到目標節點。因此,還必須設定 dfs.ha.fencing.ssh.private-key-files 選項,這是一個以逗號分隔的 SSH 私密金鑰檔案清單。例如

        <property>
          <name>dfs.ha.fencing.methods</name>
          <value>sshfence</value>
        </property>
    
        <property>
          <name>dfs.ha.fencing.ssh.private-key-files</name>
          <value>/home/exampleuser/.ssh/id_rsa</value>
        </property>
    

    選擇性地,可以設定非標準的使用者名稱或埠來執行 SSH。也可以設定 SSH 的逾時時間(以毫秒為單位),逾時後此圍欄方法將被視為失敗。可以像這樣設定

        <property>
          <name>dfs.ha.fencing.methods</name>
          <value>sshfence([[username][:port]])</value>
        </property>
        <property>
          <name>dfs.ha.fencing.ssh.connect-timeout</name>
          <value>30000</value>
        </property>
    

    shell - 執行任意 shell 指令來圍欄 Active NameNode

    shell 圍欄方法會執行任意 shell 指令。可以像這樣設定

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

    「()」之間的字串會直接傳遞給 bash shell,且不能包含任何關閉括弧。

    shell 指令會在設定為包含所有目前 Hadoop 設定變數的環境中執行,其中「_」字元會取代設定金鑰中的所有「.」字元。所使用的設定已經將任何特定於名稱節點的設定提升至其一般形式 - 例如 dfs_namenode_rpc-address 會包含目標節點的 RPC 位址,即使設定可能將該變數指定為 dfs.namenode.rpc-address.ns1.nn1

    此外,下列參考要圍欄的目標節點的變數也可用

    $target_host 要圍欄的節點主機名稱
    $target_port 要圍欄的節點 IPC 埠
    $target_address 以上兩者,結合為 host:port
    $target_nameserviceid 要圍欄的 NN 的名稱服務 ID
    $target_namenodeid 要圍欄的 NN 的名稱節點 ID

    這些環境變數也可以用作 shell 指令本身的替換。例如

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

    如果 shell 指令傳回 0 的結束代碼,則圍欄會被判定為成功。如果傳回任何其他結束代碼,則圍欄不成功,且會嘗試清單中的下一個圍欄方法。

    注意:此圍欄方法未實作任何逾時。如果需要逾時,應在 shell 腳本本身中實作(例如,fork 一個子 shell 在幾秒內終止其父 shell)。


  • fs.defaultFS - 當未提供 Hadoop FS 客戶端時,由其使用的預設路徑字首

    選擇性地,您現在可以設定 Hadoop 客戶端使用新的啟用 HA 的邏輯 URI 的預設路徑。如果您先前使用「mycluster」作為名稱服務 ID,這將會是所有 HDFS 路徑的授權部分的值。可以在 core-site.xml 檔案中像這樣設定

    <property>
      <name>fs.defaultFS</name>
      <value>hdfs://mycluster</value>
    </property>
    
  • dfs.journalnode.edits.dir - JournalNode 程式會儲存其本地狀態的路徑

    這是 JournalNode 電腦上 JN 使用的編輯和其他本地狀態將儲存的絕對路徑。您只能對此設定使用單一路徑。此資料的備援是透過執行多個獨立的 JournalNode,或是在本地連接的 RAID 陣列上設定此目錄來提供。例如

    <property>
      <name>dfs.journalnode.edits.dir</name>
      <value>/path/to/journal/node/local/data</value>
    </property>
    
  • dfs.ha.nn.not-become-active-in-safemode - 如果防止安全模式名稱節點變為 active

    是否允許名稱節點在安全模式時變為 active,當設定為 true 時,安全模式中的名稱節點會在自動故障轉移開啟時向 ZKFC 報告 SERVICE_UNHEALTHY,或在自動故障轉移關閉時擲回例外狀況以失敗轉換為 active。例如

    <property>
      <name>dfs.ha.nn.not-become-active-in-safemode</name>
      <value>true</value>
    </property>
    

部署詳細資訊

設定所有必要的組態選項後,您必須在將執行 JournalNode 的機器組上啟動 JournalNode 程式。這可以透過執行指令「hdfs --daemon start journalnode」並等待程式在各個相關機器上啟動來完成。

JournalNode 啟動後,必須先同步兩個 HA NameNode 的磁碟上元資料。

  • 如果您正在設定新的 HDFS 群集,您應該先在其中一個 NameNode 上執行格式化指令 (hdfs namenode -format)。

  • 如果您已經格式化 NameNode,或正在將非 HA 啟用群集轉換為 HA 啟用,您現在應該透過在未格式化的 NameNode 上執行指令「hdfs namenode -bootstrapStandby」將 NameNode 元資料目錄的內容複製到另一個未格式化的 NameNode。執行此指令也會確保 JournalNode (由 dfs.namenode.shared.edits.dir 組態) 包含足夠的編輯交易記錄,以便啟動兩個 NameNode。

  • 如果您正在將非 HA NameNode 轉換為 HA,您應該執行指令「hdfs namenode -initializeSharedEdits」,這將使用來自本機 NameNode 編輯目錄的編輯資料初始化 JournalNode。

此時,您可以像正常啟動 NameNode 一樣啟動所有 HA NameNode。

您可以透過瀏覽 NameNode 的組態 HTTP 位址,分別造訪每個 NameNode 的網頁。您應該會注意到,在組態的位址旁邊會顯示 NameNode 的 HA 狀態(「備用」或「啟用」)。每當 HA NameNode 啟動時,它最初會處於備用狀態。

管理指令

現在您的 HA NameNode 已組態並啟動,您將可以存取一些額外的指令來管理您的 HA HDFS 群集。具體來說,您應該熟悉「hdfs haadmin」指令的所有子指令。在沒有任何其他引數的情況下執行此指令,將顯示下列使用資訊

Usage: haadmin
    [-transitionToActive <serviceId>]
    [-transitionToStandby <serviceId>]
    [-failover [--forcefence] [--forceactive] <serviceId> <serviceId>]
    [-getServiceState <serviceId>]
    [-getAllServiceState]
    [-checkHealth <serviceId>]
    [-help <command>]

本指南說明這些子指令的各個高階用途。如需每個子指令的特定使用資訊,您應該執行「hdfs haadmin -help <command>」。

  • transitionToActivetransitionToStandby - 將指定 NameNode 的狀態轉換為 Active 或 Standby

    這些子命令分別會導致指定的 NameNode 轉換為 Active 或 Standby 狀態。這些命令不會嘗試執行任何圍欄,因此很少使用。相反,幾乎總是建議使用「hdfs haadmin -failover」子命令。

  • failover - 在兩個 NameNode 之間啟動故障轉移

    此子命令會導致故障從第一個提供的 NameNode 轉移到第二個。如果第一個 NameNode 處於 Standby 狀態,此命令只會將第二個轉換為 Active 狀態,而不會出現錯誤。如果第一個 NameNode 處於 Active 狀態,將嘗試優雅地將其轉換為 Standby 狀態。如果失敗,將嘗試圍欄方法(由 dfs.ha.fencing.methods 配置),直到其中一個成功。只有在這個過程之後,第二個 NameNode 才會轉換為 Active 狀態。如果沒有圍欄方法成功,第二個 NameNode 將不會轉換為 Active 狀態,並且會傳回錯誤。

  • getServiceState - 確定指定的 NameNode 是 Active 還是 Standby

    連線到提供的 NameNode 以確定其目前狀態,適當地將「standby」或「active」印出到 STDOUT。此子命令可用於 cron 作業或監控腳本,這些腳本需要根據 NameNode 目前是 Active 還是 Standby 而採取不同的行為。

  • getAllServiceState - 傳回所有 NameNode 的狀態

    連線到已配置的 NameNode 以確定目前狀態,適當地將「standby」或「active」印出到 STDOUT。

  • checkHealth - 檢查指定 NameNode 的健康狀態

    連線到提供的 NameNode 以檢查其健康狀態。NameNode 能夠對自身執行一些診斷,包括檢查內部服務是否如預期般執行。如果 NameNode 健康,此命令會傳回 0,否則會傳回非零值。可以將此命令用於監控目的。

    注意:這尚未實作,目前總是會傳回成功,除非指定的 NameNode 完全停機。

負載平衡器設定

如果您在負載平衡器 (例如 AzureAWS ) 後面執行一組 NameNode,並希望負載平衡器指向活動 NN,您可以使用 /isActive HTTP 端點作為健康檢查。如果 NN 處於活動 HA 狀態,http://NN_HOSTNAME/isActive 將傳回 200 狀態碼回應,否則傳回 405。

執行中編輯記錄尾隨

在預設設定下,備用 NameNode 只會套用已完成編輯記錄區段中存在的編輯。如果希望備用 NameNode 擁有較新的名稱空間資訊,可以啟用執行中編輯區段的尾隨。此設定會嘗試從 JournalNode 上的記憶體快取中擷取編輯,並可將備用 NameNode 套用交易前的延遲時間縮短至毫秒等級。如果無法從快取提供編輯,備用 NameNode 仍可擷取編輯,但延遲時間會長很多。相關設定如下

  • dfs.ha.tail-edits.in-progress - 是否對執行中編輯記錄啟用尾隨。這也會在 JournalNode 上啟用記憶體中編輯快取。預設為停用。

  • dfs.journalnode.edit-cache-size.bytes - JournalNode 上編輯的記憶體中快取大小。在一般環境中,編輯大約各佔用 200 位元組,因此,例如,預設的 1048576 (1MB) 大小可以容納大約 5000 個交易。建議監控 JournalNode 指標 RpcRequestCacheMissAmountNumMisses 和 RpcRequestCacheMissAmountAvgTxns,它們分別計算快取無法提供的要求數量,以及要求成功所需的額外交易數量。例如,如果要求嘗試從交易 ID 10 開始擷取編輯,但快取中最舊的資料在交易 ID 20,則會將值 10 新增到平均值。

此功能主要與備用/觀察者讀取功能搭配使用。使用此功能,可以從非活動 NameNode 提供讀取要求;因此,執行中編輯尾隨可讓這些節點提供資料較新的要求。有關此功能的更多資訊,請參閱 Apache JIRA 票證 HDFS-12943。

自動故障轉移

簡介

上述各節說明如何設定手動故障轉移。在該模式中,即使活動節點已故障,系統也不會自動從活動 NameNode 觸發故障轉移到備用 NameNode。本節說明如何設定和部署自動故障轉移。

組件

自動故障轉移會在 HDFS 部署中新增兩個新組件:ZooKeeper 仲裁組和 ZKFailoverController 程序(簡稱 ZKFC)。

Apache ZooKeeper 是一種高可用性服務,用於維護少量協調資料,通知客戶端資料變更,並監控客戶端故障。自動 HDFS 故障轉移的實作仰賴 ZooKeeper 執行下列事項

  • 故障偵測 - 群集中每個 NameNode 電腦都在 ZooKeeper 中維護一個持續性工作階段。如果電腦發生故障,ZooKeeper 工作階段將會過期,並通知其他 NameNode(s) 應觸發故障轉移。

  • 主動 NameNode 選舉 - ZooKeeper 提供一個簡單的機制,可獨家選出一個節點為主動節點。如果目前的主動 NameNode 發生故障,另一個節點可能會在 ZooKeeper 中取得一個特別的獨家鎖定,表示它應成為下一個主動節點。

ZKFailoverController (ZKFC) 是新的組件,它是一個 ZooKeeper 客戶端,也會監控和管理 NameNode 的狀態。執行 NameNode 的每部電腦也會執行一個 ZKFC,而該 ZKFC 負責

  • 健康監控 - ZKFC 會定期使用健康檢查指令向其本機 NameNode 發送 ping。只要 NameNode 及時回應健康狀態,ZKFC 就會將節點視為健康。如果節點已發生故障、凍結或進入其他不健康狀態,健康監控器會將其標記為不健康。

  • ZooKeeper 工作階段管理 - 當本機 NameNode 健康時,ZKFC 會在 ZooKeeper 中保持一個開啟的工作階段。如果本機 NameNode 為主動狀態,它也會持有特別的「鎖定」znode。此鎖定會使用 ZooKeeper 對「暫時」節點的支援;如果工作階段過期,鎖定節點將會自動刪除。

  • 基於 ZooKeeper 的選舉 - 如果本機 NameNode 健康,且 ZKFC 看到目前沒有其他節點持有鎖定 znode,它本身會嘗試取得鎖定。如果成功,則表示它「贏得選舉」,並負責執行故障轉移,使其本機 NameNode 成為主動狀態。故障轉移程序類似於上述手動故障轉移:首先,如有必要,會將前一個主動節點圍住,然後本機 NameNode 會轉換為主動狀態。

如需有關自動故障轉移設計的更多詳細資訊,請參閱附加在 Apache HDFS JIRA 上的 HDFS-2185 設計文件。

部署 ZooKeeper

在典型的部署中,ZooKeeper 程式設定為在三個或五個節點上執行。由於 ZooKeeper 本身有輕量級資源需求,因此將 ZooKeeper 節點與 HDFS NameNode 和備用節點放在相同的硬體上是可接受的。許多操作員選擇將第三個 ZooKeeper 程序部署在與 YARN ResourceManager 相同的節點上。建議將 ZooKeeper 節點設定為將其資料儲存在與 HDFS 元資料分開的磁碟機上,以獲得最佳效能和隔離。

ZooKeeper 的設定不在本文件範圍內。我們假設您已設定在三個或更多節點上執行的 ZooKeeper 群集,並透過使用 ZK CLI 連線驗證其正確操作。

開始之前

在開始設定自動故障轉移之前,您應關閉您的群集。目前無法在群集執行期間從手動故障轉移設定轉換為自動故障轉移設定。

設定自動故障轉移

自動故障轉移的設定需要在您的設定中新增兩個新參數。在您的 hdfs-site.xml 檔案中,新增

 <property>
   <name>dfs.ha.automatic-failover.enabled</name>
   <value>true</value>
 </property>

這指定群集應設定為自動故障轉移。在您的 core-site.xml 檔案中,新增

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

這會列出執行 ZooKeeper 服務的主機埠對。

與文件中先前描述的參數一樣,這些設定可以透過在設定金鑰後面加上名稱服務 ID 來針對每個名稱服務進行設定。例如,在啟用聯合的群集中,您可以透過設定 dfs.ha.automatic-failover.enabled.my-nameservice-id 來明確只為其中一個名稱服務啟用自動故障轉移。

還有幾個其他設定參數可以設定來控制自動故障轉移的行為;但是,大多數安裝不需要這些參數。請參閱設定金鑰特定文件以取得詳細資訊。

在 ZooKeeper 中初始化 HA 狀態

新增設定金鑰後,下一步是在 ZooKeeper 中初始化所需的狀態。您可以從其中一個 NameNode 主機執行下列指令來執行此操作。

[hdfs]$ $HADOOP_HOME/bin/hdfs zkfc -formatZK

這會在 ZooKeeper 中建立一個 znode,自動故障轉移系統會在其內部儲存其資料。

使用 start-dfs.sh 啟動群集

由於已在設定中啟用自動故障轉移,因此 start-dfs.sh 腳本現在會自動在執行 NameNode 的任何機器上啟動 ZKFC 程式。當 ZKFC 啟動時,它們會自動選取其中一個 NameNode 成為活動狀態。

手動啟動群集

如果您手動管理叢集中的服務,您將需要在執行 NameNode 的每部機器上,手動啟動 zkfc 程式。您可以透過執行以下指令來啟動程式

[hdfs]$ $HADOOP_HOME/bin/hdfs --daemon start zkfc

保護存取 ZooKeeper 的安全性

如果您執行的是安全叢集,您可能會希望確保儲存在 ZooKeeper 中的資訊也受到保護。這可以防止惡意用戶修改 ZooKeeper 中的元資料,或可能觸發錯誤的故障轉移。

為了保護 ZooKeeper 中的資訊,請先將以下內容新增到 core-site.xml 檔案

 <property>
   <name>ha.zookeeper.auth</name>
   <value>@/path/to/zk-auth.txt</value>
 </property>
 <property>
   <name>ha.zookeeper.acl</name>
   <value>@/path/to/zk-acl.txt</value>
 </property>

請注意這些值中的「@」字元,這表示組態不是內嵌的,而是指向磁碟上的檔案。驗證資訊也可以透過 CredentialProvider 讀取(請參閱 hadoop-common 專案中的 CredentialProviderAPI 指南)。

第一個已組態的檔案指定 ZooKeeper 驗證清單,其格式與 ZK CLI 使用的格式相同。例如,您可以指定類似以下的內容

digest:hdfs-zkfcs:mypassword

…其中 hdfs-zkfcs 是 ZooKeeper 的唯一使用者名稱,而 mypassword 是用作密碼的唯一字串。

接下來,使用類似於以下指令的指令,產生與此驗證相符的 ZooKeeper ACL

[hdfs]$ java -cp $ZK_HOME/lib/*:$ZK_HOME/zookeeper-3.4.2.jar org.apache.zookeeper.server.auth.DigestAuthenticationProvider hdfs-zkfcs:mypassword
output: hdfs-zkfcs:mypassword->hdfs-zkfcs:P/OQvnYyU/nF/mGYvB/xurX8dYs=

將此輸出的「->」字串後的區段複製並貼到 zk-acls.txt 檔案中,並加上「digest:」字串作為前綴。例如

digest:hdfs-zkfcs:vlUvLnd8MlacsE80rDuu6ONESbM=:rwcda

為了讓這些 ACL 生效,您應該重新執行 zkfc -formatZK 指令,如上所述。

執行此操作後,您可以從 ZK CLI 驗證 ACL,如下所示

[zk: localhost:2181(CONNECTED) 1] getAcl /hadoop-ha
'digest,'hdfs-zkfcs:vlUvLnd8MlacsE80rDuu6ONESbM=
: cdrwa

驗證自動故障轉移

一旦設定好自動故障轉移,您應該測試其操作。為此,請先找出活動的 NameNode。您可以透過拜訪 NameNode 網路介面來判斷哪個節點是活動的,每個節點都會在頁面頂端報告其 HA 狀態。

找到活動的 NameNode 後,您可以在該節點上造成故障。例如,您可以使用 kill -9 <pid of NN> 來模擬 JVM 崩潰。或者,您可以循環電源或拔除其網路介面,以模擬不同類型的中斷。觸發您要測試的中斷後,另一個 NameNode 應該會在幾秒鐘內自動變為活動狀態。偵測故障並觸發故障轉移所需的時間取決於 ha.zookeeper.session-timeout.ms 的組態,但預設為 5 秒。

如果測試未成功,您可能有錯誤的組態。請檢查 zkfc 程式和 NameNode 程式的記錄,以進一步診斷問題。

自動故障轉移常見問題

  • 我是否一定要按照特定順序啟動 ZKFC 和 NameNode 程式?

    否。在任何給定的節點上,您可以在其對應的 NameNode 之前或之後啟動 ZKFC。

  • 我應該新增什麼額外的監控?

    您應該在執行 NameNode 的每個主機上新增監控,以確保 ZKFC 持續執行。例如,在某些類型的 ZooKeeper 故障中,ZKFC 可能意外退出,且應重新啟動以確保系統已準備好自動故障轉移。

    此外,您應該監控 ZooKeeper 法定人數中的每個伺服器。如果 ZooKeeper 發生故障,則自動故障轉移將無法運作。

  • 如果 ZooKeeper 發生故障會怎樣?

    如果 ZooKeeper 群集發生故障,則不會觸發任何自動故障轉移。但是,HDFS 將繼續執行且不受任何影響。當 ZooKeeper 重新啟動時,HDFS 將重新連線且不會出現問題。

  • 我可以將我的其中一個 NameNode 指定為主要/優先嗎?

    不行。目前不支援此功能。首先啟動的 NameNode 將會變為活動狀態。您可以選擇以特定順序啟動群集,以便您的優先節點先啟動。

  • 當已設定自動故障轉移時,我如何啟動手動故障轉移?

    即使已設定自動故障轉移,您仍可以使用相同的 hdfs haadmin 指令啟動手動故障轉移。它將執行協調故障轉移。

已啟用 HA 的 HDFS 升級/最終化/回滾

在 HDFS 版本之間移動時,有時可以簡單地安裝較新的軟體並重新啟動群集。然而,有時升級您正在執行的 HDFS 版本可能需要變更磁碟資料。在此情況下,必須在安裝新軟體後使用 HDFS 升級/最終化/回滾功能。此程序在 HA 環境中會變得更複雜,因為 NN 依賴的磁碟中繼資料根據定義是分散的,同時存在於這對中的兩個 HA NN 上,以及在使用 QJM 作為共用編輯儲存時存在於 JournalNodes 上。本文件說明部分說明在 HA 設定中使用 HDFS 升級/最終化/回滾功能的程序。

若要執行 HA 升級,操作員必須執行下列動作

  1. 正常關閉所有 NN,並安裝較新的軟體。

  2. 啟動所有 JN。請注意,在執行升級、回滾或最後完成作業時,所有 JN 必須執行,這一點至關重要。如果在執行任何這些作業時任一 JN 發生故障,則作業將失敗。

  3. 使用 '-upgrade' 旗標啟動其中一個 NN。

  4. 啟動後,此 NN 不同於 HA 設定中的常態,不會進入備用狀態。相反地,此 NN 會立即進入活動狀態,執行其本地儲存目錄的升級,並執行共享編輯記錄的升級。

  5. 此時,HA 配對中的另一個 NN 將與已升級的 NN 不同步。為了讓其重新同步並再次擁有高可用性設定,您應該使用 '-bootstrapStandby' 旗標執行 NN,重新啟動此 NameNode。使用 '-upgrade' 旗標啟動此第二個 NN 是錯誤的。

請注意,如果您在最後完成或回滾升級之前想要重新啟動 NameNode,您應該正常啟動 NN,即不使用任何特殊啟動旗標。

查詢升級狀態時,作業員會使用 `hdfs dfsadmin -upgrade query' 指令,同時至少有一個 NN 正在執行。此指令會傳回每個 NN 的 NN 升級程序是否已最後完成。

最後完成 HA 升級時,作業員會使用 `hdfs dfsadmin -finalizeUpgrade' 指令,同時 NN 正在執行,其中一個處於活動狀態。此時的活動 NN 會執行共享記錄的最後完成,而其本地儲存目錄包含先前檔案系統狀態的 NN 會刪除其本地狀態。

執行升級的回滾時,首先應該關閉兩個 NN。作業員應該在啟動升級程序的 NN 上執行回滾指令,這會在該處的本地目錄和共享記錄(NFS 或 JN)上執行回滾。之後,應該啟動此 NN,作業員應該在另一個 NN 上執行 `-bootstrapStandby',讓兩個 NN 與此回滾檔案系統狀態同步。