30.7. フェイルオーバーモード
JBoss EAP のメッセージングは、2 つのタイプのクライアントフェイルオーバーを定義します。
- 自動クライアントフェイルオーバー
- アプリケーションレベルのクライアントフェイルオーバー
また、JBoss EAP メッセージングでは、同じサーバーに対して 100% 透過的な自動再割り当てを提供します (一時的なネットワークの問題の場合など)。これは、同じサーバーに再接続される点を除くと、フェイルオーバーと似ています。詳細は、クライアントの再接続とセッションの再割り当て を参照してください。
フェイルオーバー中に、クライアントのコンシューマーが非永続的または一時的なキューにある場合、これらのキューはバックアップノード上でフェイルオーバー中に自動的に再作成されます。これは、バックアップノードが非永続キューを認識しないためです。
30.7.1. 自動クライアントフェイルオーバー
JBoss EAP メッセージングクライアントは、すべてのライブサーバーとバックアップサーバーの情報を受け取るように設定できます。そのため、クライアントで接続 (ライブサーバー接続) に失敗すると、クライアントが障害を検出し、バックアップサーバーに再接続します。次に、バックアップサーバーはフェイルオーバーの前に各接続に存在したセッションおよびコンシューマーを自動的に再作成します。そのため、ユーザーは再接続ロジックを手動でコーディングする必要がなくなります。
JBoss EAP メッセージングクライアントは、使用済みの接続の検出 で説明されているように、client-failure-check-period
で指定した時間内にサーバーからパケットを受信しないと、接続障害を検出します。
割り当てられた時間内にクライアントがデータを受信しない場合、接続が失敗したと見なし、フェイルオーバーを試みます。ソケットがオペレーティングシステムによって閉じられているとします。たとえば、サーバーハードウェア自体がクラッシュしたのではなく、サーバープロセスが強制終了され可能性がり、クライアントはすぐにフェイルオーバーします。
JBoss EAP メッセージングクライアントは、さまざまな方法でライブサーバーとバックアップサーバーのペアのリストを検出できるように設定できます。たとえば、明示的なエンドポイントを使用して設定できますが、最も一般的な方法は、クライアントが初めてクラスターに接続するときにクラスタートポロジーについての情報を受け取ることです。詳細は、サーバー検出 を参照してください。
デフォルトの HA 設定には、クラスター通信に推奨される http-connector
を使用する cluster-connection
が含まれます。これは、リモートクライアントがデフォルトの RemoteConnectionFactory
を使用してサーバーに接続するときに使用する http-connector
と同じです。推奨されていませんが、別のコネクターを使用することもできます。独自のコネクターを使用する場合は、リモートクライアントが使用する connection-factory
とクラスターノードが使用する cluster-connection
の両方の設定の一部に含まれていることを確認してください。コネクターとクラスター接続に関する詳細は、メッセージングトランスポートの設定 と クラスター接続 を参照してください。
JMS クライアントにより使用される connection-factory
に定義する connector
は、クラスターにより使用される cluster-connection
に定義されているものと同じである必要があります。同じでない場合、クライアントはベースとなるライブ/バックアップのペアのトポロジーを更新できないため、バックアップサーバーの場所を認識できません。
CLI コマンドを使用して、connection-factory
と cluster-connection
の両方の設定を確認します。たとえば、RemoteConnectionFactory
という名前の connection-factory
の現在の設定を読み取るには、以下のコマンドを使用します。
/subsystem=messaging-activemq/server=default/connection-factory=RemoteConnectionFactory:read-resource
/subsystem=messaging-activemq/server=default/connection-factory=RemoteConnectionFactory:read-resource
同様に、以下のコマンドは my-cluster
という名前の cluster-connection
の設定を読み込みます。
/subsystem=messaging-activemq/server=default/cluster-connection=my-cluster:read-resource
/subsystem=messaging-activemq/server=default/cluster-connection=my-cluster:read-resource
自動クライアントフェイルオーバーを有効にするには、ゼロでない再接続試行を許可するようにクライアントを設定する必要があります。詳細は、クライアントの再接続とセッションの再割り当て を参照してください。デフォルトでは、フェイルオーバーは、ライブサーバーへの接続が少なくとも 1 つ確立された後にのみ発生します。つまり、クライアントが、ライブサーバーへの最初の接続を確立できないと、フェイルオーバーは発生しません。クライアントは、最初の試行に失敗すると、reconnect-attempts
プロパティーに従ってライブサーバーへ接続を再試行し、設定された試行回数の後に失敗します。
/subsystem=messaging-activemq/server=default/connection-factory=RemoteConnectionFactory:write-attribute(name=reconnect-attempts,value=<NEW_VALUE>)
/subsystem=messaging-activemq/server=default/connection-factory=RemoteConnectionFactory:write-attribute(name=reconnect-attempts,value=<NEW_VALUE>)
このルールの例外は、ライブ/バックアップサーバーのペアが 1 つのみで、他のライブサーバーはなく、リモート MDB が正常にシャットダウンされたときにライブサーバーに接続される場合です。MDB が @ActivationConfigProperty(propertyName = "rebalanceConnections", propertyValue = "true")
を設定している場合、別のライブサーバーへの接続を再度調整し、バックアップにフェイルオーバーしません。
初期接続時のフェイルオーバー
クライアントは最初の接続が確立されるまで完全なトポロジーについてわからないため、バックアップについて不明な時間枠があります。この時点で失敗した場合、クライアントは元のライブサーバーにのみ再接続を試みます。クライアントが試行する回数を設定するには、ClientSessionFactoryImpl
または ActiveMQConnectionFactory
でプロパティー initialConnectAttempts
を設定します。
または、サーバー設定で、クライアントが使用する接続ファクトリーの initial-connect-attempts
属性を設定できます。これのデフォルトは 0
で、つまり、1 回のみ試行します。試行がその回数行われると、例外が出力されます。
/subsystem=messaging-activemq/server=default/connection-factory=RemoteConnectionFactory:write-attribute(name=initial-connect-attempts,value=<NEW_VALUE>)
/subsystem=messaging-activemq/server=default/connection-factory=RemoteConnectionFactory:write-attribute(name=initial-connect-attempts,value=<NEW_VALUE>)
サーバーレプリケーションについて
JBoss EAP メッセージングは、ライブサーバーとバックアップサーバーの間で完全なサーバー状態を複製しません。新しいセッションがバックアップ上に自動的に再作成される場合、そのセッション中に送信済みまたは確認応答済みのメッセージについては認識されません。フェイルオーバー時の in-flight の送信と確認応答も失われる可能性があります。
完全なサーバー状態を複製することで、JBoss EAP メッセージングは、理論的に 100% 透過的なシームレスなフェイルオーバーを提供して、メッセージや確認応答を失うことを防ぐことができます。ただし、これには、キューやセッションを含め、完全なサーバー状態を複製するため、多大なコストがかかります。これには、サーバー状態マシン全体のレプリケーションが必要です。つまり、ライブサーバー上のすべての操作は、一貫したレプリカ状態にするためにまったく同じグローバル順序でレプリカサーバーに複製される必要があります。これは、特に複数のスレッドがライブサーバー状態を同時に変更していることを考慮すると、パフォーマンスの優れたスケーラブルな方法で行うことは非常に困難です。
仮想同期などの手法を使用して完全な状態マシンのレプリケーションを提供することは可能です。しかし、これは拡張性が低く、すべての操作を単一スレッドに効果的にシリアライズするため、同時実行性が大幅に低下します。ロック状態の複製やスレッドスケジューリングの複製など、マルチスレッドのアクティブなレプリケーションには他の手法が存在しますが、これを Java レベルで達成することは非常に困難です。
したがって、100% 透過的なフェイルオーバーのために、パフォーマンスと同時実行性を低下させる価値はありませんでした。100% 透過的なフェイルオーバーがなくても、トランザクションの重複検出と再試行の組み合わせを使用することで、障害が発生した場合でも、一度だけの配信を保証するのは簡単です。ただし、これは、クライアントコードに対して 100% 透過的ということではありません。
30.7.1.1. フェイルオーバー中のブロック呼び出しの処理
クライアントコードがサーバーへのブロック呼び出しの中にある場合 (フェイルオーバー中に実行を継続する応答を待機している場合)、新しいセッションでは、進行中の呼び出しに関する情報がありません。ブロックされた呼び出しは、それ以外では、決して受け取ることのない応答を待機してハングする可能性があります。
これを防ぐため、JBoss EAP メッセージングは、JMS を使用する場合は javax.jms.JMSException
を出力し、コア API を使用する場合はエラーコード ActiveMQException.UNBLOCKED
を設定して ActiveMQException
を出力することにより、フェイルオーバー時に進行中のブロッキング呼び出しのブロックを解除します。この例外をキャッチし、必要に応じて操作を再試行するかどうかはクライアントコード次第です。
ブロック解除されるメソッドが commit() または prepare() の呼び出しである場合、トランザクションは自動的にロールバックされ、JBoss EAP メッセージングは、JMS を使用する場合は javax.jms.TransactionRolledBackException
を出力し、コア API を使用する場合はエラーコード ActiveMQException.TRANSACTION_ROLLED_BACK
を設定して ActiveMQException
を出力します。
30.7.1.2. トランザクションによるフェイルオーバーの処理
セッションがトランザクションであり、現在のトランザクションでメッセージがすでに送信または確認応答されている場合、サーバーはフェイルオーバー中にメッセージまたは確認応答が失われたかどうかがわかりません。
その結果、トランザクションはロールバック専用としてマークされ、その後コミットしようとすると、JMS を使用する場合は javax.jms.TransactionRolledBackException
を出力し、コア API を使用する場合はエラーコード ActiveMQException.TRANSACTION_ROLLED_BACK
を設定して ActiveMQException
を出力します。
このルールに関する注意点は、XA が JMS またはコア API を介して使用される場合です。2 フェーズコミットが使用され、prepare()
がすでに呼び出されている場合、ロールバックによって HeuristicMixedException
が発生する可能性があります。このため、コミットは XAException.XA_RETRY
例外を出力します。これは、後のある時点でコミットを再試行する必要があることをトランザクションマネージャーに通知します。これの副作用は、非永続メッセージが失われることです。これを回避するには、XA の使用時に永続メッセージを使用するようにしてください。確認応答では、prepare()
が呼び出される前にサーバーにフラッシュされるため、これは問題ではありません。
例外をキャッチし、必要に応じてクライアント側のローカルロールバックコードを実行するのはユーザー次第です。すでにロールバックされているため、セッションを手動でロールバックする必要はありません。ユーザーは、同じセッションに対してトランザクション操作を再試行できます。
コミット呼び出しの実行中にフェイルオーバーが発生すると、サーバーは、前述したように応答を返さないため、ハングを防ぐために呼び出しのブロックを解除します。この場合、障害が発生する前にトランザクションのコミットがライブサーバーで実際に処理されたかどうかをクライアントが判断するのは容易ではありません。
XA が JMS またはコア API を介して使用されている場合、XAException.XA_RETRY
が出力されます。これは、ある時点で再試行が必要であることをトランザクションマネージャーに通知するためです。後のある時点で、トランザクションマネージャーはコミットを再試行します。元のコミットが発生していない場合、それはまだ存在し、コミットされます。存在しない場合、コミットされたと見なされますが、トランザクションマネージャーが警告を記録する可能性があります。
これを修正するには、クライアントはトランザクションで重複検出を有効にし、呼び出しがブロック解除された後にトランザクション操作を再試行します。検出をサーバーに設定する方法は、重複メッセージ検出 を参照してください。フェイルオーバー前にトランザクションが実際にライブサーバーで正常にコミットされた場合、重複検出により、トランザクションで再送信される永続メッセージがサーバーで無視され、トランザクションの再試行時にメッセージが複数回送信されないようにします。
30.7.1.3. 接続失敗の通知
JMS は、接続障害の非同期通知を送信する標準メカニズムである java.jms.ExceptionListener
を提供します。このクラスに関する詳細は、JMS javadoc を参照してください。また、コア API は、org.apache.activemq.artemis.core.client.SessionFailureListener
クラスの形式で同様の機能を提供します。
ExceptionListener
または SessionFailureListener
インスタンスは、接続が正常にフェイルオーバー、再接続、または再割り当てされたかどうかに関係なく、接続障害が発生した場合に JBoss EAP によって常に呼び出されます。ただし、SessionfailureListener
の connectionFailed()
に渡される failedOver
フラグの値、または javax.jms.JMSException
のエラーコードを調べると、再接続または再割り当てが発生したかどうかを確認できます。エラーコードは次のいずれかになります。
JMSException エラーコード
エラーコード | 説明 |
---|---|
FAILOVER | フェイルオーバーが発生し、正常に再割り当てまたは再接続しました。 |
DISCONNECT | フェイルオーバーは発生せず、切断されています。 |
30.7.2. アプリケーションレベルのフェイルオーバー
場合によっては、自動クライアントフェイルオーバーは行わず、接続障害を自分で処理し、障害ハンドラーに再接続ロジックを手動でコーディングすることもできます。フェイルオーバーはユーザーアプリケーションレベルで処理されるため、これをアプリケーションレベルのフェイルオーバーとして定義します。
JMS を使用する場合にアプリケーションレベルのフェイルオーバーを実装するには、JMS 接続で ExceptionListener
クラスを設定します。ExceptionListener
は、接続障害が検出された場合に JBoss EAP メッセージングによって呼び出されます。ExceptionListener
では、古い JMS 接続を閉じ、場合によっては、JNDI から新しい接続ファクトリーインスタンスを検索し、新しい接続を作成します。
コア API を使用している場合、手順は非常に似ています。コア ClientSession
インスタンスで FailureListener
を設定します。