このガイドでは、HDFS 高可用性 (HA) 機能の概要と、Quorum Journal Manager (QJM) 機能を使用して HA HDFS クラスタを構成および管理する方法について説明します。
このドキュメントでは、読者が HDFS クラスタの一般的なコンポーネントとノードタイプについて一般的な理解を持っていることを前提としています。詳細は、HDFS アーキテクチャガイドを参照してください。
このガイドでは、アクティブとスタンバイの NameNode 間で編集ログを共有するために Quorum Journal Manager (QJM) を使用して HDFS HA を構成および使用する方法について説明します。QJM の代わりに NFS を共有ストレージに使用して HDFS HA を構成する方法については、こちらの代替ガイドを参照してください。Observer NameNode を使用して HDFS HA を構成する方法については、こちらのガイドを参照してください。
Hadoop 2.0.0 より前では、NameNode は HDFS クラスタにおける単一障害点 (SPOF) でした。各クラスタには単一の NameNode があり、そのマシンまたはプロセスが利用できなくなった場合、NameNode が再起動されるか、別のマシンで起動されるまで、クラスタ全体が利用できなくなりました。
これは、HDFS クラスタの全体的な可用性に、主に 2 つの大きな影響を与えました。
マシンクラッシュなどの計画外のイベントの場合、オペレータが NameNode を再起動するまで、クラスタは使用できませんでした。
NameNode マシンでのソフトウェアまたはハードウェアのアップグレードなどの計画的なメンテナンスイベントにより、クラスタのダウンタイムが発生しました。
HDFS 高可用性機能は、同じクラスタ内で 2 つ (3.0.0 以降は 2 つ以上) の冗長 NameNode を、ホットスタンバイを備えたアクティブ/パッシブ構成で実行するオプションを提供することにより、上記の問題に対処します。これにより、マシンクラッシュが発生した場合に新しい NameNode に迅速にフェイルオーバーしたり、計画メンテナンスのために管理者主導のグレースフルフェイルオーバーを実行したりできます。
典型的な HA クラスタでは、2 つ以上の別々のマシンが NameNode として構成されます。どの時点でも、NameNode のうち 1 つだけが *アクティブ* 状態にあり、残りは *スタンバイ* 状態にあります。アクティブ NameNode はクラスタ内のすべてのクライアント操作を担当し、スタンバイは単にワーカーとして機能し、必要に応じて迅速なフェイルオーバーを提供するために十分な状態を維持します。
スタンバイノードがその状態をアクティブノードと同期させるために、両方のノードは「JournalNode」(JN) と呼ばれる個別のデーモングループと通信します。アクティブノードによって名前空間の変更が実行されると、変更のレコードがこれらの JN の過半数に永続的に記録されます。スタンバイノードは JN から編集を読み取ることができ、編集ログの変更を常に監視しています。スタンバイノードは編集を確認すると、それらを独自の名前空間に適用します。フェイルオーバーが発生した場合、スタンバイは、アクティブ状態に昇格する前に、JournalNode からすべての編集を読み取ったことを確認します。これにより、フェイルオーバーが発生する前に名前空間の状態が完全に同期されます。
迅速なフェイルオーバーを提供するには、スタンバイノードがクラスタ内のブロックの場所に関する最新の情報を持っていることも必要です。これを達成するために、DataNode はすべての NameNode の場所で構成され、すべての NameNode にブロックの場所情報とハートビートを送信します。
HA クラスタが正しく動作するためには、一度に 1 つの NameNode のみがアクティブであることが不可欠です。そうでない場合、名前空間の状態は 2 つのノード間で急速に乖離し、データの損失やその他の誤った結果のリスクが生じます。このプロパティを確保し、いわゆる「スプリットブレインシナリオ」を防ぐために、JournalNode は、一度に 1 つの NameNode のみをライターとして許可します。フェイルオーバー中、アクティブになる NameNode は、JournalNode への書き込みの役割を引き継ぎます。これは、事実上、他の NameNode がアクティブ状態を継続することを防ぎ、新しいアクティブが安全にフェイルオーバーを進めることができます。
HA クラスタをデプロイするには、以下を準備する必要があります。
**NameNode マシン** - アクティブおよびスタンバイ NameNode を実行するマシンは、互いに同等のハードウェア、および非 HA クラスタで使用されるものと同等のハードウェアを備えている必要があります。
**JournalNode マシン** - JournalNode を実行するマシン。JournalNode デーモンは比較的軽量であるため、これらのデーモンは、NameNode、JobTracker、または YARN ResourceManager などの他の Hadoop デーモンと同じマシンに配置することができます。**注記:** 編集ログの変更は JN の過半数に書き込まれる必要があるため、少なくとも 3 つの JournalNode デーモンが必要です。これにより、システムは単一マシンの障害を許容できます。3 つ以上の JournalNode を実行することもできますが、システムが許容できる障害の数を実際に増やすには、奇数個の JN (つまり 3、5、7 など) を実行する必要があります。N 個の JournalNode を実行する場合、システムは最大 (N - 1) / 2 の障害を許容し、正常に機能し続けることができます。
HA クラスタでは、スタンバイ NameNode も名前空間の状態のチェックポイントを実行するため、HA クラスタでセカンダリ NameNode、CheckpointNode、または BackupNode を実行する必要はありません。実際、そうすることはエラーになります。これにより、HA が有効ではない HDFS クラスタを HA が有効になるように再構成するユーザーは、以前にセカンダリ NameNode 専用にしていたハードウェアを再利用することもできます。
フェデレーション構成と同様に、HA 構成は下位互換性があり、既存の単一 NameNode 構成を 변경없이 작동させることができます。新しい構成は、ノードのタイプに基づいて異なる構成ファイルを異なるマシンにデプロイする必要なく、クラスタ内のすべてのノードが同じ構成を持つことができるように設計されています。
HDFS フェデレーションと同様に、HA クラスタは `nameservice ID` を再利用して、実際には複数の HA NameNode で構成される単一の HDFS インスタンスを識別します。さらに、HA では `NameNode ID` と呼ばれる新しい抽象化が追加されます。クラスタ内の個別の NameNode ごとに、それを区別するための異なる NameNode ID があります。すべての NameNode に単一の構成ファイルをサポートするために、関連する構成パラメータには、**NameNode ID** だけでなく **nameservice ID** も接尾辞として付けられます。
HA NameNode を構成するには、**hdfs-site.xml** 構成ファイルにいくつかの構成オプションを追加する必要があります。
これらの構成を設定する順序は重要ではありませんが、**dfs.nameservices** および **dfs.ha.namenodes.[nameservice ID]** に選択した値によって、後続のキーが決まります。したがって、残りの構成オプションを設定する前に、これらの値を決定する必要があります。
**dfs.nameservices** - この新しいネームサービスの論理名
このネームサービスの論理名 (例: 「mycluster」) を選択し、この構成オプションの値としてこの論理名を使用します。選択する名前は任意です。構成と、クラスタ内の絶対 HDFS パスの authority コンポーネントの両方で使用されます。
注記: HDFS Federationも使用している場合、この設定には、他のネームサービス(HAまたはそれ以外)のリストをカンマ区切りで含める必要があります。
<property> <name>dfs.nameservices</name> <value>mycluster</value> </property>
dfs.ha.namenodes.[ネームサービスID] - ネームサービス内の各NameNodeの一意の識別子
カンマ区切りのNameNode IDのリストで設定します。これは、DataNodeがクラスタ内のすべてのNameNodeを特定するために使用されます。たとえば、以前にネームサービスIDとして「mycluster」を使用し、NameNodeの個々のIDとして「nn1」、「nn2」、「nn3」を使用する場合、次のように設定します。
<property> <name>dfs.ha.namenodes.mycluster</name> <value>nn1,nn2, nn3</value> </property>
注記: HAのNameNodeの最小数は2つですが、それ以上設定することもできます。通信オーバーヘッドのため、5を超えないようにすることをお勧めします(推奨は3つのNameNode)。
dfs.namenode.rpc-address.[ネームサービスID].[ネームノードID] - 各NameNodeがリッスンする完全修飾RPCアドレス
以前に設定した両方のNameNode IDについて、NameNodeプロセスの完全なアドレスとIPCポートを設定します。これは2つの別々の設定オプションになります。例:
<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
これは、アクティブなNameNodeによって書き込まれ、スタンバイNameNodeによって読み取られて、アクティブなNameNodeが行うすべてのファイルシステムの変更を最新の状態に保つ、共有編集ストレージを提供するJournalNodeのアドレスを設定する場所です。複数のJournalNodeアドレスを指定する必要がありますが、これらのURIの1つだけを設定する必要があります。 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クライアントがアクティブなNameNodeに接続するために使用するJavaクラス
DFSクライアントがどのNameNodeが現在アクティブであるか、したがってどのNameNodeが現在クライアント要求を処理しているかを判断するために使用するJavaクラスの名前を設定します。現在Hadoopに付属している2つの実装は、ConfiguredFailoverProxyProviderとRequestHedgingProxyProvider(最初の呼び出しでは、すべてNameNodeを同時に呼び出してアクティブなNameNodeを決定し、後続の要求では、フェイルオーバーが発生するまでアクティブなNameNodeを呼び出す)です。カスタムプロキシプロバイダーを使用していない限り、これらのいずれかを使用してください。例:
<property> <name>dfs.client.failover.proxy.provider.mycluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property>
dfs.ha.fencing.methods - フェイルオーバー中にアクティブなNameNodeをフェンスするために使用されるスクリプトまたはJavaクラスのリスト
システムの正確性のために、いつでも1つのNameNodeだけがアクティブ状態であることが望ましいです。重要なのは、Quorum Journal Managerを使用する場合、1つのNameNodeだけがJournalNodeに書き込むことが許可されるため、スプリットブレインシナリオからファイルシステムメタデータが破損する可能性はありません。 ただし、フェイルオーバーが発生した場合、以前のアクティブなNameNodeがクライアントに読み取り要求を提供する可能性があり、JournalNodeへの書き込みを試行してシャットダウンするまで、古い可能性があります。このため、Quorum Journal Managerを使用する場合でも、いくつかのフェンシング方法を設定することをお勧めします。ただし、フェンシングメカニズムが失敗した場合のシステムの可用性を向上させるために、リストの最後のフェンシング方法として成功することが保証されているフェンシング方法を設定することをお勧めします。実際のフェンシング方法を使用しないことを選択した場合でも、この設定に何かを設定する必要があります。たとえば、「shell(/bin/true)
」です。
フェイルオーバー中に使用されるフェンシング方法は、復帰改行で区切られたリストとして設定され、フェンシングが成功したことを示すまで順番に試行されます。Hadoopには、shellとsshfenceの2つの方法が付属しています。独自のカスタムフェンシング方法を実装する方法については、org.apache.hadoop.ha.NodeFencerクラスを参照してください。
sshfence - アクティブなNameNodeにSSH接続し、プロセスを強制終了します
sshfenceオプションは、ターゲットノードにSSH接続し、fuserを使用してサービスのTCPポートでリッスンしているプロセスを強制終了します。このフェンシングオプションが機能するためには、パスフレーズを提供せずにターゲットノードにSSH接続できる必要があります。したがって、SSH秘密鍵ファイルのカンマ区切りリストであるdfs.ha.fencing.ssh.private-key-filesオプションも設定する必要があります。例:
<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 - 任意のシェルコマンドを実行して、アクティブなNameNodeをフェンスします
shellフェンシング方法は、任意のシェルコマンドを実行します。次のように設定できます。
<property> <name>dfs.ha.fencing.methods</name> <value>shell(/path/to/my/script.sh arg1 arg2 ...)</value> </property>
「(」と「)」の間の文字列はbashシェルに直接渡され、閉じ括弧を含めることはできません。
シェルコマンドは、現在のすべてのHadoop設定変数が含まれるように設定された環境で実行され、「_」文字は設定キーの「.」文字を置き換えます。使用される設定では、NameNode固有の設定がすでに一般的な形式に昇格されています。たとえば、dfs.namenode.rpc-address.ns1.nn1として変数を指定した場合でも、dfs_namenode_rpc-addressにはターゲットノードのRPCアドレスが含まれます。
さらに、フェンスされるターゲットノードを参照する次の変数も使用できます。
$target_host | フェンスされるノードのホスト名 |
$target_port | フェンスされるノードのIPCポート |
$target_address | 上記の2つをhost:portとして組み合わせたもの |
$target_nameserviceid | フェンスされるNNのネームサービスID |
$target_namenodeid | フェンスされるNNのNameNode ID |
これらの環境変数は、シェルコマンド自体で置換としても使用できます。例:
<property> <name>dfs.ha.fencing.methods</name> <value>shell(/path/to/my/script.sh --nameservice=$target_nameserviceid $target_host:$target_port)</value> </property>
シェルコマンドが終了コード0を返した場合、フェンシングは成功したと判断されます。他の終了コードが返された場合、フェンシングは成功せず、リストの次のフェンシング方法が試行されます。
注記: このフェンシング方法はタイムアウトを実装していません。タイムアウトが必要な場合は、シェルスクリプト自体に実装する必要があります(たとえば、サブシェルをフォークして、数秒後に親を強制終了します)。
fs.defaultFS - 指定されていない場合にHadoop FSクライアントが使用するデフォルトのパスプレフィックス
必要に応じて、Hadoopクライアントが新しいHA対応の論理URIを使用するようにデフォルトパスを設定できるようになりました。以前にネームサービスIDとして「mycluster」を使用した場合、これはすべてのHDFSパスの認証部分の値になります。これは、core-site.xmlファイルで次のように設定できます。
<property> <name>fs.defaultFS</name> <value>hdfs://mycluster</value> </property>
dfs.journalnode.edits.dir - JournalNodeデーモンがローカル状態を格納するパス
これは、JNによって使用される編集およびその他のローカル状態が格納されるJournalNodeマシンの絶対パスです。この設定には、1つのパスのみ使用できます。このデータの冗長性は、複数の個別の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 - セーフモードのNameNodeがアクティブになるのを防ぐ場合
セーフモードのときにNameNodeがアクティブになるのを許可するかどうか。trueに設定すると、セーフモードのNameNodeは、自動フェイルオーバーがオンの場合はZKFCにSERVICE_UNHEALTHYを報告し、自動フェイルオーバーがオフの場合は例外をスローしてアクティブへの遷移を失敗させます。例:
<property> <name>dfs.ha.nn.not-become-active-in-safemode</name> <value>true</value> </property>
必要なすべての設定オプションを設定したら、JournalNodeデーモンを実行するマシンのセットで起動する必要があります。これは、「hdfs --daemon start journalnode」コマンドを実行し、関連する各マシンでデーモンが起動するのを待つことによって行うことができます。
JournalNodeが起動したら、最初に2つの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を起動できます。
設定されたHTTPアドレスを参照することで、各NameNodeのWebページを個別に訪れることができます。設定されたアドレスの横に、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>」を実行してください。
transitionToActiveとtransitionToStandby - 指定されたNameNodeの状態をアクティブまたはスタンバイに移行します
これらのサブコマンドは、指定されたNameNodeをそれぞれアクティブ状態またはスタンバイ状態に移行させます。これらのコマンドはフェンシングを実行しようとしないため、めったに使用しないでください。 代わりに、ほとんどの場合、「hdfs haadmin -failover」サブコマンドを使用することをお勧めします。
failover - 2つのNameNode間のフェイルオーバーを開始します
このサブコマンドは、指定された最初のNameNodeから2番目のNameNodeへのフェイルオーバーを引き起こします。最初のNameNodeがスタンバイ状態の場合、このコマンドはエラーなく2番目のNameNodeをアクティブ状態に遷移させます。最初のNameNodeがアクティブ状態の場合、正常にスタンバイ状態に遷移させるための試行が行われます。これが失敗した場合、(dfs.ha.fencing.methods で設定されている)フェンシングメソッドが成功するまで順番に試行されます。このプロセスが完了した後でのみ、2番目のNameNodeがアクティブ状態に遷移します。フェンシングメソッドが成功しなかった場合、2番目のNameNodeはアクティブ状態に遷移せず、エラーが返されます。
getServiceState - 指定されたNameNodeがアクティブかスタンバイかを判別します
指定されたNameNodeに接続して現在の状態を判別し、「standby」または「active」を適切にSTDOUTに出力します。このサブコマンドは、NameNodeが現在アクティブかスタンバイかによって動作を変える必要があるcronジョブや監視スクリプトで使用される場合があります。
getAllServiceState - すべてのNameNodeの状態を返します
設定されているすべてのNameNodeに接続して現在の状態を判別し、「standby」または「active」を適切にSTDOUTに出力します。
checkHealth - 指定されたNameNodeのヘルスチェックを実行します
指定されたNameNodeに接続してヘルスチェックを実行します。NameNodeは、内部サービスが期待どおりに実行されているかどうかの確認など、自身でいくつかの診断を実行できます。このコマンドは、NameNodeが正常な場合は0を返し、そうでない場合は0以外の値を返します。このコマンドは監視目的で使用できます。
注:これはまだ実装されておらず、現時点では、指定されたNameNodeが完全にダウンしている場合を除き、常に成功を返します。
ロードバランサー(例:Azure または AWS)の背後でNameNodeのセットを実行し、ロードバランサーがアクティブなNNを指すようにしたい場合は、/isActive HTTPエンドポイントをヘルスプローブとして使用できます。http://NN_HOSTNAME/isActive は、NNがアクティブなHA状態の場合は200ステータスコードレスポンスを返し、そうでない場合は405を返します。
デフォルト設定では、スタンバイNameNodeは、確定された編集ログセグメントに存在する編集のみを適用します。より最新のネームスペース情報を持つスタンバイNameNodeが必要な場合は、処理中の編集セグメントのテーリングを有効にすることができます。この設定は、JournalNodeのメモリ内キャッシュから編集を取得しようとします。これにより、スタンバイ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デプロイメントに2つの新しいコンポーネントを追加します。ZooKeeperクォーラムとZKFailoverControllerプロセス(ZKFCと略記)です。
Apache ZooKeeperは、少量の調整データを維持し、そのデータの変更をクライアントに通知し、クライアントの障害を監視するための可用性の高いサービスです。HDFSの自動フェイルオーバーの実装は、次のことにZooKeeperに依存しています
障害検出 - クラスタ内の各NameNodeマシンは、ZooKeeperで永続セッションを維持します。マシンがクラッシュすると、ZooKeeperセッションが期限切れになり、フェイルオーバーをトリガーする必要があることが他のNameNodeに通知されます。
アクティブ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を保持していないことを確認した場合、ZKFC自体がロックの取得を試みます。成功した場合、「選挙に勝利」し、ローカルNameNodeをアクティブにするためのフェイルオーバーを実行する責任があります。フェイルオーバープロセスは、上記の手動フェイルオーバーに似ています。最初に、必要に応じて以前のアクティブがフェンスされ、次にローカルNameNodeがアクティブ状態に移行します。
自動フェイルオーバーの設計の詳細については、Apache HDFS JIRAのHDFS-2185に添付されている設計ドキュメントを参照してください。
典型的なデプロイでは、ZooKeeperデーモンは3つまたは5つのノードで実行するように構成されます。ZooKeeper自体はリソース要件が軽いため、ZooKeeperノードをHDFS NameNodeおよびスタンバイノードと同じハードウェアに配置することは許容されます。多くのオペレーターは、3つ目のZooKeeperプロセスをYARN ResourceManagerと同じノードにデプロイすることを選択します。最適なパフォーマンスと分離を実現するために、ZooKeeperノードをHDFSメタデータとは別のディスクドライブにデータを保存するように構成することをお勧めします。
ZooKeeperのセットアップはこのドキュメントの範囲外です。3つ以上のノードで実行されているZooKeeperクラスタをセットアップし、ZK CLIを使用して接続することでその正しい動作を確認済みであると想定します。
自動フェイルオーバーの構成を開始する前に、クラスタをシャットダウンする必要があります。現在、クラスタの実行中に手動フェイルオーバー設定から自動フェイルオーバー設定に移行することはできません。
自動フェイルオーバーの構成には、構成に2つの新しいパラメータを追加する必要があります。 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
を設定することにより、ネームサービスの1つに対してのみ自動フェイルオーバーを明示的に有効にできます。
自動フェイルオーバーの動作を制御するために設定できる他の構成パラメータもいくつかあります。ただし、それらはほとんどのインストールでは必要ありません。詳細については、構成キー固有のドキュメントを参照してください。
構成キーを追加したら、次の手順はZooKeeperで必要な状態を初期化することです。NameNodeホストの1つから次のコマンドを実行することで、これを行うことができます。
[hdfs]$ $HADOOP_HOME/bin/hdfs zkfc -formatZK
これにより、ZooKeeperにznodeが作成され、その内部に自動フェイルオーバーシステムがデータを保存します。
start-dfs.sh
を使用したクラスタの起動構成で自動フェイルオーバーが有効になっているため、start-dfs.sh
スクリプトは、NameNodeを実行するマシンでZKFCデーモンを自動的に起動するようになります。ZKFCが起動すると、アクティブになるNameNodeの1つが自動的に選択されます。
クラスタのサービスを手動で管理する場合は、NameNodeを実行する各マシンでzkfc
デーモンを手動で起動する必要があります。デーモンを起動するには、以下を実行します
[hdfs]$ $HADOOP_HOME/bin/hdfs --daemon start zkfc
セキュアなクラスタを実行している場合は、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 ガイドを参照してください)。
最初に設定されたファイルは、ZK CLIで使用されているのと同じ形式で、ZooKeeper認証のリストを指定します。たとえば、次のように指定できます。
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のWebインターフェースにアクセスすることで確認できます。各ノードはページの上部にHAの状態を報告します。
アクティブなNameNodeを見つけたら、そのノードで障害を発生させることができます。たとえば、kill -9 <NNのpid>
を使用してJVMクラッシュをシミュレートできます。または、マシンの電源を再投入するか、ネットワークインターフェースを取り外して、別の種類の停止をシミュレートすることもできます。テストする停止をトリガーした後、他のNameNodeは数秒以内に自動的にアクティブになるはずです。障害を検出してフェイルオーバーをトリガーするために必要な時間は、ha.zookeeper.session-timeout.ms
の設定によって異なりますが、デフォルトは5秒です。
テストが成功しない場合は、設定が誤っている可能性があります。問題をさらに診断するために、zkfc
デーモンとNameNodeデーモンのログを確認してください。
ZKFCとNameNodeデーモンを特定の順序で起動することは重要ですか?
いいえ。任意のノードで、ZKFCを対応するNameNodeの前または後に起動できます。
他にどのような監視を行うべきですか?
NameNodeを実行する各ホストで、ZKFCが実行され続けることを確認するための監視を追加する必要があります。たとえば、ZooKeeperの特定の種類の障害では、ZKFCが予期せず終了する可能性があり、システムが自動フェイルオーバーの準備ができていることを確認するために再起動する必要があります。
さらに、ZooKeeperクォーラムの各サーバーを監視する必要があります。ZooKeeperがクラッシュすると、自動フェイルオーバーは機能しません。
ZooKeeperがダウンするとどうなりますか?
ZooKeeperクラスターがクラッシュした場合、自動フェイルオーバーはトリガーされません。ただし、HDFSは影響を受けることなく引き続き実行されます。ZooKeeperが再起動すると、HDFSは問題なく再接続します。
NameNodeの1つをプライマリ/優先として指定できますか?
いいえ。現在、これはサポートされていません。最初に起動されたNameNodeがアクティブになります。優先ノードが最初に起動するように、特定の順序でクラスターを起動することを選択できます。
自動フェイルオーバーが設定されている場合、手動フェイルオーバーをどのように開始できますか?
自動フェイルオーバーが設定されている場合でも、同じhdfs haadmin
コマンドを使用して手動フェイルオーバーを開始できます。調整されたフェイルオーバーが実行されます。
HDFSのバージョン間を移行する場合、新しいソフトウェアをインストールしてクラスターを再起動するだけで済む場合があります。ただし、実行しているHDFSのバージョンをアップグレードするには、ディスク上のデータを変更する必要がある場合があります。この場合、新しいソフトウェアをインストールした後、HDFSのアップグレード/ファイナライズ/ロールバック機能を使用する必要があります。NNが依存するディスク上のメタデータは、定義上、ペアの2つのHA NNと、共有編集ストレージにQJMが使用されている場合はJournalNodeの両方で分散されるため、このプロセスはHA環境ではより複雑になります。このドキュメントセクションでは、HA設定でHDFSアップグレード/ファイナライズ/ロールバック機能を使用する手順について説明します。
HAアップグレードを実行するには、オペレーターは次の手順を実行する必要があります。
通常どおりすべてのNNをシャットダウンし、新しいソフトウェアをインストールします。
すべてのJNを起動します。アップグレード、ロールバック、またはファイナライズ操作を実行する際には、すべてのJNが実行されていることが非常に重要です。これらの操作の実行時にいずれかのJNがダウンしている場合、操作は失敗します。
NNの1つを'-upgrade'
フラグを付けて起動します。
起動時、このNNはHA設定で通常のようにスタンバイ状態になりません。代わりに、このNNはすぐにアクティブ状態になり、ローカルストレージディレクトリのアップグレードを実行し、共有編集ログのアップグレードも実行します。
この時点で、HAペアのもう一方のNNは、アップグレードされたNNと同期しなくなります。同期状態に戻し、再び高可用性設定にするには、'-bootstrapStandby'
フラグを付けてNNを実行することにより、このNameNodeを再ブートストラップする必要があります。 '-upgrade'
フラグを付けてこの2番目のNNを起動するとエラーになります。
ファイナライズまたはロールバックする前にNameNodeを再起動する場合は、特別な起動フラグなしで、つまり通常どおりNNを起動する必要があることに注意してください。
アップグレードのステータスを照会するには、オペレーターは、少なくとも1つのNNが実行されている間に`hdfs dfsadmin -upgrade query'
コマンドを使用します。このコマンドは、NNアップグレードプロセスが各NNに対してファイナライズされているかどうかを返します。
HAアップグレードをファイナライズするには、オペレーターは、NNが実行中で、そのうちの1つがアクティブな間に`hdfs dfsadmin -finalizeUpgrade'
コマンドを使用します。これが発生した時点のアクティブなNNは、共有ログのファイナライズを実行し、ローカルストレージディレクトリに以前のFS状態が含まれているNNは、そのローカル状態を削除します。
アップグレードのロールバックを実行するには、最初に両方のNNをシャットダウンする必要があります。オペレーターは、アップグレード手順を開始したNNでロールバックコマンドを実行する必要があります。これにより、ローカルディレクトリと、NFSまたはJNの共有ログでロールバックが実行されます。その後、このNNを起動し、オペレーターは他のNNで`-bootstrapStandby'
を実行して、2つのNNをこのロールバックされたファイルシステム状態と同期させる必要があります。