Sun Java System Message Queue 3 2005Q1 技術の概要 |
第 3 章
信頼性の高いメッセージ配信この章では、Message Queue サービスによって実現される信頼性の高いメッセージ配信の仕組みについて説明します。説明では、システム内のメッセージの送信経路を追跡し、適切なコンシューマまでのメッセージのルーティングと配信、およびメッセージの配信を保証するために利用されているさまざまなメカニズムを取り上げます。
章には次のトピックが含まれます。
この章には、開発者と管理者にとって有用な資料が含まれており、第 2 章「Message Queue の紹介」の内容を補完するものとなっています。
システム全体でのメッセージの流れメッセージプロデューサから始まり、メッセージコンシューマで終わる、Message Queue メッセージサービスによるメッセージ配信の流れを図 3-1 に示します。以下の項では、配信プロセスの各段階について詳しく説明します。
図 3-1 メッセージ配信手順
信頼性の高い方法で、持続的に配信されるメッセージのメッセージ配信手順は次のとおりです。
メッセージのプロデュース
1. クライアントランタイムが、コネクションを使用して、メッセージプロデューサからメッセージサーバーにメッセージを配信します。
メッセージの処理とルーティング
2. メッセージサーバーが、コネクションからメッセージの内容を読み込み、適切な送信先に保管します。
3. メッセージサーバーが (持続) メッセージをデータストアに保管します。
4. メッセージサーバーが、メッセージを受信したことについて、メッセージプロデューサのクライアントランタイムに通知します。
5. メッセージサーバーが、メッセージのルーティングを決定します。
6. メッセージサーバーは、送信先から適切なコネクションに、メッセージを書き出します。
メッセージのコンシューム
7. メッセージコンシューマのクライアントランタイムが、コネクションからメッセージコンシューマにメッセージを配信します。
8. メッセージコンシューマのクライアントランタイムが、メッセージをコンシュームしたことについて、メッセージサーバーに通知します。
メッセージの存続終了
9. メッセージサーバーはクライアント通知を処理し、送信先とデータストアの両方から (持続) メッセージを削除します。
10. メッセージサーバーは、コンシューマのクライアントランタイムに対して、クライアント通知が処理されたのでメッセージを再び配信することはできないことを確認します。
これらの一連の配信手順でシステムによって処理されるメッセージは、次の 2 つのカテゴリに分類されます。
メッセージ配信処理Message Queue サービスによるメッセージの処理は、図 3-1 に続く手順の説明にあるように、プロデューサからコンシューマまでの配信の流れを数段階に分けて実行されます。
配信の段階は次のとおりです。
次の項で、これらの段階について説明します。
メッセージのプロデュース
メッセージのプロデュースでは、メッセージはクライアントによって作成され、クライアントランタイムによりブローカの送信先へのコネクションを介して送信されます。
メッセージの配信モードが持続 (ブローカで障害が発生しても、必ず 1 回の配信を保証) に設定されている場合、ブローカはデフォルトでコントロールメッセージとしてブローカ通知をクライアントランタイムに返信します。このブローカ通知により、ブローカが送信先にメッセージを配信し、ブローカのデータストアに保管したことを示します。クライアントスレッドは、ブローカ通知を受け取るまでブロックします。
メッセージの配信モードが非持続に設定されている場合、ブローカはデフォルトでクライアントランタイムにブローカ通知を返信せず、クライアントスレッドはブロックしません。ただし、ブローカが非持続メッセージを受信するかどうかを知る必要がある場合は、ブローカ通知を有効にできます。実際、送信先メモリーが限界に達した場合は、ブローカ通知を有効にしてメッセージのプロデュース速度を落とす必要があります (「送信先のメッセージ制限」を参照)。
メッセージの処理とルーティング
ブローカは、着信 JMS ペイロードメッセージを受信すると、その送信先に格納し、適切な 1 つまたは複数のコンシューマにルーティングします。
一般に、すべてのメッセージは、配信されるか期限切れになるまで物理的な送信先 (メモリー内) に残ります。ブローカで障害が発生すると、これらのメッセージは失われます。メッセージが持続的である場合、ブローカはメッセージをデータベースかファイルシステムに保管し、障害のあとに復元します。
メッセージの処理方法は、次の節で説明されるとおり、送信先のタイプ (キューまたはトピック) によって決まります。また、管理者が物理的な送信先を作成したときに、その送信先に設定された送信先プロパティによっても異なります。
キューの送信先
キューの送信先は、メッセージが配信され、1 つだけのコンシューマによってコンシュームされることになっている、ポイントツーポイントメッセージングで使用されます。
1 つのキュー送信先内のメッセージは 1 つのコンシューマにのみ配信されますが、Message Queue では、複数のコンシューマを 1 つのキューに登録できます。それからブローカは、登録された異なるコンシューマにメッセージを分配し、コンシューマ間で負荷を分散させることができます。
基本的なルーティングメカニズム
メッセージは、プロデューサから到着するとキューに入れられます。それぞれのメッセージは、キューの先頭になると、キューに登録された 1 つのコンシューマに向けてルーティングされます。メッセージがキューの先頭に来る順番は、メッセージの到着順序と優先度によって決まります。
セレクタのプロパティ値がメッセージに設定されていると、ブローカは、登録済みコンシューマによって指定されているいずれかのセレクタ値とそのプロパティ値を比較し、メッセージをコンシューマに向けてルーティングする前にセレクタ値が一致することを確認します。
複数のコンシューマへのキューの配信
複数のコンシューマへのキュー配信の実装では、多くのキュー送信先プロパティに基づいて設定可能なロードバランス方式を使用します。
コンシューマの数がこの 2 つのプロパティの合計値を超えた場合、新しいコンシューマは拒否されます。Message Queue Platform Edition はキューあたり最大 3 つのコンシューマ (2 つはアクティブ、1 つはバックアップ) をサポートします。Message Queue Enterprise Edition がサポートするコンシューマの数は無制限です。
ロードバランスメカニズムでは、さまざまなコンシューマがメッセージをコンシュームする度合いを考慮します。キュー送信先内のメッセージは、設定可能なサイズ (キュー送信先のコンシューマフロー制限プロパティ) にまとめられ、新たに使用可能になったアクティブコンシューマにキューに登録された順序でルートされます。これらのメッセージが配信されると、キューに到着する追加メッセージは、コンシューマが使用可能になると同時にバッチ処理によってコンシューマにルーティングされます。コンシューマは、前に配信された設定可能な割合のメッセージをコンシュームすると使用可能になります。言い換えると、各コンシューマへのディスパッチ速度は、コンシューマの現在の容量とメッセージの処理速度によって異なります。
アクティブコンシューマに障害が生じると、1 番目のバックアップコンシューマがアクティブになり、障害の生じたコンシューマの動作を引き継ぎます。こうしたメカニズムであるため、キュー送信先に複数のアクティブコンシューマがある場合は、メッセージがコンシュームされる順序は保証されません。
メッセージの生成速度が遅い場合は、ブローカがアクティブコンシューマ間で不均等にメッセージをディスパッチしている可能性があります。必要な数以上のアクティブコンシューマが存在すると、一部のコンシューマはメッセージを受信しないことがあります。
ブローカクラスタ環境では、複数のコンシューマへの配信を設定し、ローカルコンシューマの優先度を設定できます。キュー送信先のプロパティを使用すると、プロデューサのホームブローカ、つまりプロデューサのメッセージ送信先となるブローカ (ローカルブローカ) にコンシューマが存在しない場合にのみ、メッセージがリモートコンシューマへ配信されるように指定できます。これにより、リモートコンシューマへ向けてルーティング (コンシューマのホームブローカを経由) するとスループットが低下する可能性がある状況で、パフォーマンスを向上させることができます。
トピックの送信先
トピックの送信先は、パブリッシュ / サブスクライバメッセージングで使用されます。メッセージは、送信先で配信対象を登録しているすべてのコンシューマに配信されるようになっています。
基本的なルーティングメカニズム
メッセージは、プロデューサから送信されてくると、トピックをサブスクライブするすべてのコンシューマに向けてルーティングされます。永続サブスクリプションをトピックに登録している場合、コンシューマは、トピックにメッセージが配信されたとき、アクティブ状態になってそのメッセージを受信する必要はありません。これは、コンシューマが再びアクティブになるまでブローカがメッセージを保存し、それから配信するからです。
セレクタのプロパティ値がメッセージに設定されていると、ブローカは、登録済みコンシューマによって指定されているいずれかのセレクタ値とそのプロパティ値を比較し、メッセージをコンシューマに向けてルーティングする前にセレクタ値が一致することを確認します。
永続サブスクリプションとクライアント ID
トピックへの永続サブスクリプションを持つことが可能なのは 1 人のユーザーだけです。そのユーザーがメッセージサーバーへのコネクションをオープンおよびクローズするときには、ユーザー ID が同じままになっている必要があります。クライアント識別子 (client identifier) は、それぞれの永続サブスクリプションが 1 人のユーザーにのみ対応していることを確認するために使用します。
クライアント ID により、メッセージサーバーへのクライアントのコネクションと、クライアントに代わってメッセージサーバーが保持する状態情報を関連付けます。定義により、クライアント ID は一意の値になります。
永続サブスクリプションを作成するには、クライアントがプログラムで JMS API メソッド呼び出しを使用して、またはクライアントが使用するコネクションファクトリオブジェクトでの管理操作によって、クライアント ID を設定する必要があります。
メッセージのコンシューム
ルーティングが済んだメッセージは、それぞれのコンシューマに配信されます。コンシューマがペイロードメッセージを受信すると、コンシューミングクライアントランタイムは、クライアントがメッセージを受信して処理したことを伝える通知をブローカに送信します。ブローカは、その送信先からメッセージを削除する前に、このクライアント通知が送信されてくるのを待ちます。クライアント通知は、個々のメッセージ、メッセージグループ、またはトランザクションに適用可能です。
クライアント通知
JMS 仕様に従い、クライアントでは、セッションを作成する場合に 3 つの基本通知モードのいずれかを指定できます。選択するモードは、必要なメッセージ配信の信頼性によって決まります。
Message Queue は、NO_ACKNOWLDEGE モードを追加してクライアント通知モードのセットを拡張します。以下の項では、基本モードと拡張モードについて説明します。
AUTO_ACKNOWLEDGE モード
AUTO_ACKNOWLEDGE モードでは、クライアントによってコンシュームされる各メッセージについてセッションが自動的に通知します。また、セッションスレッドがブロックし、コンシュームされたメッセージそれぞれのクライアント通知をセッションが処理したことをブローカが確認するまで待ちます。この確認動作は、ブローカ通知と呼ばれます。
CLIENT_ACKNOWLEDGE モード
CLIENT_ACKNOWLEDGE モードでは、クライアントがほとんどの制御を行うことができます。このモードでは、1 つ以上のメッセージがコンシュームされたあとで、クライアントが明示的に通知します。通知は、クライアントがメッセージオブジェクトの acknowledge() メソッドを呼び出したときに発生します。ここでセッションは、最後に acknowledge() メソッドが呼び出されたあとにそのセッションによってコンシュームされるすべてのメッセージに対して通知します。これには、コンシュームされた順序に依存せずに、セッション内の多くのメッセージリスナーによって非同期にコンシュームされたメッセージが含まれます。
また、セッションスレッドがブロックして、コンシュームされたメッセージのバッチに対する戻りブローカ通知を待ちます。戻りブローカ通知は、ブローカがクライアント通知を処理したことを確認します。
一般に、クライアント通知とブローカ通知は 1 つずつ送信されずにバッチ処理されるので、通常 CLIENT_ACKNOWLEDGE モードでは、AUTO_ACKNOWLEDGE モードに比べてコネクション帯域幅が節約され、ブローカ通知のオーバーヘッドが低減されます。当然ながら、このモードではクライアントが各メッセージを通知し、バッチ処理は行われません。また、通知は 1 つずつ送信されます。
DUPS_OK_ACKNOWLEDGE モード
DUPS_OK_ACKNOWLEDGE モードでは、10 個のメッセージがコンシュームされてからセッションが通知します。この値は、現在設定できません。AUTO_ACKNOWLEDGE モードや CLIENT_ACKNOWLEDGE モードとは異なり、DUPS_OK_ACKNOWLEDGE モードではブローカ通知が要求されないので、ブローカ通知を待ってセッションスレッドがブロックされることはありません。
つまり、メッセージが配信されて 1 回だけコンシュームされるという保証はありません。一般に、メッセージが頻繁に配信されることはなく、配信したメッセージに対するクライアント通知をブローカが受信しておらず、障害が発生した場合にのみ再配信されます。重複して配信しても構わない場合、クライアントでは DUPS_OK_ACKNOWLEDGE モードを使用してください。
クライアント通知はバッチ処理され、クライアントスレッドはブロックしないので、一般にメッセージのスループットは他のモードの場合よりも一段と高くなります。
NO_ACKNOWLEDGE モード
NO_ACKNOWLEDGE モードでは、ブローカがクライアントに代わってクライアント通知を実行するので、メッセージがコンシューミングクライアントによって正常に処理されたという保証はありません。
メッセージのスループットが重要で、信頼性の高い配信が重要ではない場合は、このモードを使用してください。このモードを使用する場合としては、たとえば、短い間隔でメッセージが定期的に送信されるので、メッセージ負荷が高く、メッセージが消失してもそれほど問題にならない場合などがあります。
このモードは、JMS 仕様を拡張したものであり、他の JMS プロバイダと連携する必要のないクライアントでのみ使用してください。
トランザクション
前述のクライアントとブローカの通知プロセスは、トランザクションに分類される JMS メッセージの配信にも適用されます。そのような場合、クライアント通知とブローカ通知は、トランザクションに関係するすべてのメッセージを含むトランザクションレベルで作動します。トランザクションがコミットされると、ブローカの通知が自動的に送信されます。
ブローカはトランザクションを追跡し、トランザクションがコミットされるか、あるいは障害が発生した場合にロールバックされるようにします。このトランザクション管理は、大規模な分散トランザクションの一部であるローカルトランザクションもサポートします (「分散トランザクション」を参照)。ブローカは、これらのトランザクションがコミットされるまで、トランザクションの状態を追跡します。ブローカは、起動するとコミットされていないすべてのトランザクションを調べ、手動で解決する必要のある PREPARED 状態のトランザクションを除いてデフォルトではトランザクションをすべてロールバックします。
Message Queue では、XA コネクションファクトリを介した分散トランザクションのサポートが実装されています。この XA コネクションファクトリでは、次に XA セッションを作成する XA コネクションを確立できます。さらに、分散トランザクションへのサポートには、サードパーティの JTS (Java Transaction Service)、または JTS を提供する J2EE 準拠の Application Server のいずれかが必要です。
メッセージの存続終了
ブローカは、正常に配信されたあとで送信先メモリーからメッセージを削除します。一方、正常に配信されていないのにメッセージが廃棄される場合もあります。次の項では、メッセージが廃棄されるときの条件について説明します。
通常のメッセージ削除
通常の条件では、メッセージが正常に配信され、クライアント通知によって確認されたときに、ブローカが送信先メモリーからメッセージを削除します。
ブローカは、コンシューマにメッセージを配信する場合、配信済みのマークをメッセージに付けますが、メッセージが受信されてコンシュームされたかどうかを実際には把握していません。そのためブローカは、その物理的な送信先と持続ストアからメッセージを削除する前に、クライアント通知が送信されてくるのを待ちます。
メッセージがトピックに送信された場合、ブローカは、メッセージを送信した先の各メッセージコンシューマからクライアント通知を受信するまで、メッセージを削除しません。トピックのサブスクリプションが永続的な場合、ブローカは、各メッセージをその送信先で保持し、各永続サブスクライバがアクティブなコンシューマになるとそのメッセージを配信します。ブローカは、クライアントの通知を受信するたびにそれを記録し、メッセージの有効期限が切れていない場合に限り、すべての通知を受信したあとにのみメッセージを削除します。ブローカは、クライアント通知モードに応じて、ブローカ通知をクライアントに返信することにより、クライアント通知を受信したことを確認する場合があります。
ブローカまたはコネクションで障害が発生すると、ブローカクライアント通知を受信せず、以前に配信しても通知されなかったメッセージすべてを、Redelivered フラグでマークを付けて再配信します。たとえば、メッセージを受信したことを通知する前にキューコンシューマがオフラインになり、別のコンシューマ (場合によっては同じコンシューマ) がその後キューに登録された場合、ブローカは Redelivered フラグを付けて通知されていないメッセージを新しいコンシューマに再配信します。このような条件下でのメッセージの再配信が関係するクライアントアプリケーションでは、このフラグが設定されていないかどうかメッセージを確認する必要があります。
注
受信されてもクライアントによって通知されなかったメッセージを、クライアントが明示的に再配信を要求することができる、JMS API (recover Session) があります。そのようなメッセージを再配信する場合、ブローカは Redelivered フラグによってメッセージにマークを付けます。
異常なメッセージ削除
メッセージは、配信することができない場合、配信を阻んだ条件に応じて、破棄されるかデッドメッセージキューに送られます。
以下の条件の下では、正常に配信およびコンシュームされる前に、メッセージはブローカによって廃棄されます。
ただし、上述の条件では、メッセージはデッドメッセージと見なされ、設定された動作に応じて、廃棄されるかデッドメッセージキューに送られます。
上述のようなメッセージについては、保持するように選択し、デッドメッセージキューに入れることができます。メッセージをデッドメッセージキューに入れると、ブローカは Message Queue 固有のプロパティ値をそのメッセージに書き込み、キューに入れた時刻と理由を指定します。
その後は、デッドメッセージキューからメッセージを取り出し、診断することができます。詳細は、「デッドメッセージキュー」を参照してください。
パフォーマンス問題メッセージ配信の信頼性が高くなればなるほど、その信頼性を実現するために、より多くのオーバーヘッドや帯域幅が必要となります。したがって、信頼性とパフォーマンスの兼ね合いは、設計上の重要な考慮事項です。パフォーマンスは、非持続メッセージをプロデュースおよびコンシュームするように設定すれば最大限に高めることができます。一方信頼性は、持続メッセージをプロデュースおよびコンシュームし、処理済みのセッションを使用することで最大限に高めることができます。この両極の間に、各アプリケーションの必要に応じて、多くのオプションが存在しています。
たとえば、メッセージを処理可能な速度は、メッセージングアプリケーションの設計、メッセージサーバーの設定、クライアントランタイムの設定などの数多くの要因が組み合わされて決まる数値です。これらの要因は非常にはっきりしていますが、それぞれの要因の相互作用がパフォーマンスを最大化するタスクを複雑にしている場合があります。
この節では、信頼性とパフォーマンスの兼ね合いを決める際に関与する要因のいくつかについて検討します。
配信モード 配信モードは、メッセージを多くても 1 回 (非持続) または 1 回だけ (持続) 配信するかどうかを指定します。持続メッセージを管理するには、コネクション全体を流れるブローカ通知メッセージや、ブローカ通知の受信を待ってブロックするクライアント通知モードを使用する必要があります。スループットを増大させるには、クライアントランタイムがブローカ通知を抑制するように設定できますが、この設定にすると、持続メッセージが必ず 1 回だけ配信されるという保証が取り消されます。
クライアント通知モード 4 つの各クライアント通知モードは、異なる処理レベルと帯域幅のオーバーヘッドを必要とします。AUTO_ACKNOWLEDGE モードはほとんどのオーバーヘッドを消費し、メッセージ単位での信頼性を保証します。CLIENT_ACKNOWLEDGE モードは、通知をバッチ処理するので必要とする帯域幅が少なくて済み、DUPS_OK_ACKNOWLEDGE モードでは消費するオーバーヘッドは少ないものの、メッセージを重複して配信する可能性があります。NO_ACKNOWLEDGE モードでは最善のパフォーマンスが得られますが、メッセージが消失する可能性があります。
クライアントアプリケーションの設計 1 つのセッションでキューに入るメッセージの数は、そのセッションを使用するメッセージコンシューマの数と、各コンシューマのメッセージ負荷によって決まります。クライアント側のメッセージのプロデュースまたはメッセージのコンシュームに時間がかかる場合は、通常は、アプリケーションを再設計し、より多くのセッションにメッセージプロデューサとメッセージコンシューマを分散し、またはより多くのコネクションにセッションを分散してパフォーマンスを改善できます。パフォーマンスに影響を与える設計上の問題については、『Message Queue Developer's Guide for Java Clients』および『Message Queue Developer's Guide for C Clients』を参照してください。
メッセージフロー測定 コネクションの帯域幅をめぐるコントロールメッセージとペイロードメッセージの競合は、クライアントランタイムによって管理できます。クライアントランタイムを適切に設定すれば、ブローカ通知の配信速度を上げ、ブロックされたセッションスレッドを解放し、メッセージのコンシューム速度を高めることができます。詳細は、『Message Queue 管理ガイド』を参照してください。
メッセージフロー制限 メッセージのコンシュームは、クライアントランタイムのリソース限度に到達すると速度が低下する可能性があります。1 つ以上のコンシューマによってコンシュームされるのを待ってクライアントランタイムに保持されるメッセージの数を制限することにより、これらのリソース制限を回避できます。詳細は、『Message Queue 管理ガイド』を参照してください。