第6章 ネットワーク接続

6.1. 自動フェイルオーバー

クライアントは、接続障害が発生した場合にスレーブブローカーに再接続できるように、すべてのマスターとスレーブブローカーに関する情報を受け取ることができます。その後、スレーブブローカーは、フェイルオーバー前に各接続に存在したセッションとコンシューマーを自動的に再作成します。この機能により、アプリケーションで手動で再接続ロジックをコーディングする必要がなくなります。

セッションがスレーブで再作成されると、送信または確認済みのメッセージを認識しない状態になります。フェイルオーバー時のインフライト送信または確認も失われる可能性があります。ただし、透過的なフェイルオーバーがなくても、トランザクションの重複検出と再試行の組み合わせを使用することで、障害が発生した場合でも once and only once (1 回限り) 配信を保証するのは簡単です。

クライアントは、設定可能な期間内に、ブローカーからパケットを受信しないと接続の障害を検出します。詳細は、「デッド接続の検出」 を参照してください。

マスターおよびスレーブについての情報を受信するようにクライアントを設定する方法は複数あります。1 つのオプションは、特定のブローカーに接続し、クラスターの他のブローカーに関する情報を受信するようにクライアントを設定することです。詳細は、「静的検出の設定」 を参照してください。ただし、最も一般的な方法は、ブローカー検出 を使用することです。ブローカー検出の設定方法の詳細は、「動的検出の設定」 を参照してください。

また、以下の例のように、ブローカーへの接続に使用される URI のクエリー文字列にパラメーターを追加して、クライアントを設定することもできます。

connectionFactory.ConnectionFactory=tcp://localhost:61616?ha=true&reconnectAttempts=3

手順

クエリー文字列を使用してフェイルオーバーを行うようにクライアントを設定するには、URI の以下のコンポーネントが適切に設定されていることを確認します。

  1. URI の host:port 部分は、バックアップで適切に設定されたマスターブローカーを示している必要があります。このホストおよびポートは最初の接続にのみ使用されます。host:port の値は、ライブサーバーとバックアップサーバー間の実際の接続フェイルオーバーとは関係ありません。上記の例では、localhost:61616host:port に使用されます。
  2. (任意手順) 複数のブローカーを最初の接続の候補として使用するには、以下の例のように host:port エントリーをグループ化します。

    connectionFactory.ConnectionFactory=(tcp://host1:port,tcp://host2:port)?ha=true&reconnectAttempts=3
  3. 名前と値のペア ha=true をクエリー文字列の一部として追加し、クライアントがクラスターの各マスターおよびスレーブブローカーに関する情報を受け取るようにします。
  4. 名前と値のペア reconnectAttempts=n を含めます。n は 0 よりも大きな整数です。このパラメーターは、クライアントがブローカーへの再接続を試行する回数を設定します。
注記

フェイルオーバーは、ha=true および reconnectAttempts が 0 よりも大きい場合にのみ発生します。また、他のブローカーについての情報を取得するためには、クライアントはマスターブローカーへ最初の接続を確立する必要があります。最初の接続に失敗した場合、クライアントは再試行して接続を確立することしかできません。詳細は、「最初の接続時のフェイルオーバー」 を参照してください。

6.1.1. 最初の接続時のフェイルオーバー

クライアントは HA クラスターへの最初の接続が確立されるまですべてのブローカーに関する情報を受け取らないため、クライアントが接続 URI に含まれるブローカーにのみ接続できる期間があります。そのため、この最初の接続中に障害が発生した場合、クライアントは他のマスターブローカーにフェイルオーバーできず、最初の接続の再確立のみを試行できます。クライアントには、再接続の試行回数を設定することができます。試行回数が設定されると、例外が発生します。

再接続試行回数の設定

以下の例は、AMQ Core Protocol JMS クライアントを使用して、再接続試行回数を 3 に設定します。デフォルト値は 0 で、1 回のみ試行します。

手順

値を ServerLocator.setInitialConnectAttempts() に渡して、再接続試行数を設定します。

ConnectionFactory cf =  ActiveMQJMSClient.createConnectionFactory(...)
cf.setInitialConnectAttempts(3);
再接続試行回数のグローバル設定

また、ブローカーの設定内で再接続試行回数のグローバルな最大値を適用できます。最大値はすべてのクライアント接続に適用されます。

手順

以下の例のように、initial-connect-attempts 設定要素を追加して、time-to-live の値を提供することで <broker-instance-dir>/etc/broker.xml を編集します。

<configuration>
 <core>
  ...
  <initial-connect-attempts>3</initial-connect-attempts> 1
  ...
 </core>
</configuration>
1
ブローカーに接続するすべてのクライアントでは、最大 3 回の再接続の試行が許可されます。デフォルトは -1 で、クライアントの再試行は無制限です。

6.1.2. フェイルオーバー時のブロッキングコールの対処

フェイルオーバーが発生し、クライアントが実行を継続するためにブローカーからの応答を待っているとき、新たに作成されたセッションは、進行中のコールについて認識しません。そうでないと、最初の呼び出しは永久にハングし、来るはずのない応答を待つことになります。これを防ぐため、ブローカーは例外をスローすることで、フェイルオーバー時に進行中のブロッキングコールのブロックを解除するように設計されています。クライアントコードはこれらの例外をキャッチし、必要に応じてすべての操作を再試行できます。

AMQ Core Protocol JMS クライアントを使用する場合、ブロックされていないメソッドが commit() または prepare() への呼び出しであれば、トランザクションは自動的にロールバックされ、ブローカーによって例外がスローされます。

6.1.3. トランザクションによるフェイルオーバーの対処

AMQ Core Protocol JMS クライアントを使用する場合、セッションがトランザクションであり、メッセージが現在のトランザクションですでに送信または確認されていると、ブローカーはフェイルオーバー中にこれらのメッセージまたはその確認が失われたことを確認できません。そのため、トランザクションはロールバックのみにマークされます。その後、コミットしようとすると、javax.jms.TransactionRolledBackException がスローされます。

警告

このルールに関する注意点は、XA を使用する場合です。2 フェーズコミットが使用され、prepare() がすでに呼び出されている場合は、ロールバックすると HeuristicMixedException が発生する可能性があります。このため、コミットによって XAException.XA_RETRY 例外が発生し、トランザクションマネージャーは後でコミットを再試行するように通知します。元のコミットが発生しなかった場合、それはまだ存在し、コミットすることができます。コミットが存在しない場合は、トランザクションマネージャーが警告を記録することがありますが、コミットされたものとみなされます。この例外の副次的な影響は、非永続的なメッセージが失われることです。このような損失を避けるために、XA を使用する際には必ず永続メッセージを使用してください。確認応答は、prepare() が呼び出される前にブローカーにフラッシュされるため、問題はありません。

AMQ Core Protocol JMS クライアントコードは、例外をキャッチし、必要なクライアント側のロールバックを実行する必要があります。ただし、セッションはロールバックされているため、セッションをロールバックする必要はありません。その後、ユーザーは同じセッションでトランザクション操作を再試行できます。

コミット呼び出しの実行時にフェイルオーバーが発生すると、ブローカーは呼び出しのブロックを解除し、AMQ Core Protocol JMS クライアントが応答を永遠に待たないようにします。そのため、クライアントは、障害が発生する前に、トランザクションのコミットがマスターブローカーで実際に処理されたかどうかを判断できません。

これに対処するため、AMQ Core Protocol JMS クライアントはトランザクションで重複検出を有効にし、呼び出しがブロック解除された後にトランザクション操作を再試行できます。フェイルオーバー前にトランザクションが正常にマスターブローカーでコミットされた場合、重複検出により、再試行時にトランザクションに存在する永続メッセージがブローカー側で無視されるようにします。これにより、メッセージが複数回送信されなくなります。

セッションがトランザクションでない場合、フェイルオーバー時にメッセージまたは確認応答が失われる可能性があります。非トランザクションセッションに once and only once (1 回限り) 配信を保証する場合は、重複検出を有効にし、ブロック解除例外をキャッチします。

6.1.4. 接続の障害の通知

JMS は、接続障害が非同期に通知される標準メカニズムを提供します。これは java.jms.ExceptionListener です。

接続の障害が発生すると、接続のフェイルオーバー、再接続、または再アタッチが正常に行われたかに関わらず、ExceptionListener または SessionFailureListener インスタンスは常にブローカーによって呼び出されます。SessionFailureListenerconnectionFailed で渡された failedOver フラグを調べることで、再接続または再アタッチが発生したかどうかを確認できます。または、javax.jms.JMSException のエラーコードを確認できます。これは、以下のいずれかになります。

表6.1 JMSException エラーコード

エラーコード説明

FAILOVER

フェイルオーバーが発生し、ブローカーが正常に再アタッチまたは再接続しました。

DISCONNECT

フェイルオーバーは発生せず、ブローカーが切断されています