Sun Java System Message Queue 3 2005Q4 技術の概要 |
第 2 章
クライアントプログラミングモデルこの章では、Message Queue クライアントプログラミングの基本について説明します。次のトピックが含まれます。
この章では、Java クライアントの設計と実装を中心に説明します。概して、C クライアントの設計は、Java クライアントの設計とほぼ同じです。この章の最終節では、Java クライアントと C クライアントの相違点をまとめています。Message Queue クライアントのプログラミングの詳細は、『Message Queue Developer's Guide for Java Clients』および『Message Queue Developer's Guide for C Clients』を参照してください。
第 3 章「Message Queue サービス」では、Message Queue サービスを使用して、メッセージングパフォーマンスのサポート、管理、および調整を行う方法について説明します。
設計とパフォーマンスMessage Queue アプリケーションの動作は、クライアント設計、コネクション設定、ブローカ設定、ブローカの調整、リソース管理など、多くの要因に左右されます。一部の要因は開発者の扱う範囲ですが、ほかの要因は管理者の問題になります。ただし、理想的には、開発者は Message Queue サービスでのアプリケーション設計のサポートと拡張について意識し、管理者はアプリケーションを調整するときに設計目標を意識することが望まれます。メッセージングの動作は、再設計によっても、注意深い監視および調整によっても最適化できます。したがって、優れた Message Queue アプリケーションの作成における重要な点は、開発者と管理者が、アプリケーションのライフサイクルの各段階で実現できることを理解し、所期の動作と実際の動作に関する情報を共有することです。
メッセージングドメインメッセージングミドルウェアは、メッセージのプロデュースとコンシュームを行うことにより、コンポーネントおよびアプリケーションの通信を実現します。JMS API では、この通信を制御するパターン、すなわちメッセージングドメインとして、ポイントツーポイントメッセージングとパブリッシュ / サブスクライブメッセージングの 2 つを規定しています。JMS API は、これらのパターンをサポートするように構成されています。コネクション、セッション、プロデューサ、コンシューマ、送信先、メッセージという基本的な JMS オブジェクトが、両方のドメインでメッセージング動作を指定するために使用されます。
ポイントツーポイントメッセージング
ポイントツーポイントドメインでは、メッセージプロデューサは送信側と呼ばれ、コンシューマは受信側と呼ばれます。これらは、キューと呼ばれる送信先を使用してメッセージを交換します。送信側は、キューへメッセージをプロデュースし、受信側はキューからメッセージをコンシュームします。
図 2-1 に、ポイントツーポイントドメインでの最も単純なメッセージング操作を示します。MyQueueSender は、Msg1 をキュー送信先 MyQueue1 に送信します。続いて、MyQueueReceiver は、MyQueue1 からメッセージを取得します。
図 2-1 単純なポイントツーポイントメッセージング
図 2-2 に、このドメインでの可能性を表すために、より複雑なポイントツーポイントメッセージングのイメージを示します。2 つの送信側、MyQSender1 と MyQSender2 は、同じコネクションを使用して、メッセージを MyQueue1 に送信します。MyQSender3 は、別のコネクションを使用して、メッセージを MyQueue1 に送信します。受信側では、MyQReceiver1 が MyQueue1 からメッセージをコンシュームし、MyQReceiver2 と MyQReceiver3 は、コネクションを共有して、MyQueue1 からメッセージをコンシュームします。
図 2-2 複雑なポイントツーポイントメッセージング
この複雑な図では、ポイントツーポイントメッセージングに関するその他の要点が多数示されています。
- 複数のプロデューサから 1 つのキューにメッセージを送信できる。プロデューサは、1 つのコネクションを共有することも、別々のコネクションを使用することもできますが、すべてが同じキューにアクセスできます。
- 複数の受信側がキューからメッセージをコンシュームできるが、それぞれのメッセージは、単一の受信側でしかコンシュームできない。このため、Msg1、Msg2、および Msg3 は、別々の受信側にコンシュームされます。これは、Message Queue の拡張機能です。
- 受信側は、1 つのコネクションを共有することも、別々のコネクションを使用することもできるが、すべてが同じキューにアクセスできる。これは、Message Queue の拡張機能です。
- 送信側と受信側はタイミング依存性がない。受信側は、クライアントがメッセージを送信したときに稼働していてもしていなくても、メッセージを取り出せます。
- 送信側と受信側は、実行時に、動的に追加および削除できるので、必要に応じて、メッセージングシステムを拡張したり縮小したりできる。
- メッセージは、送信順にキューに入れられるが、コンシュームされる順番は、メッセージの有効期限、メッセージの優先度、メッセージのコンシュームでセレクタを使用するかどうかなどの要因によって決まる。
ポイントツーポイントモデルには、次のような多くのメリットがあります。
- 複数の受信側が同じキューからメッセージをコンシュームできることにより、メッセージを受信する順序が重要でない場合は、メッセージコンシュームをロードバランスできる。これは、Message Queue の拡張機能です。
- 受信側がない場合でも、キューに送られるメッセージは常に保持される。
- Java クライアントは、キューブラウザオブジェクトを使用して、キューの内容を調べることができる。続いてクライアントは、この調査から得られた情報に基づいて、メッセージをコンシュームできます。つまり、コンシュームモデルは通常 FIFO (先入れ先出し) ですが、メッセージセレクタを使用することにより、どのメッセージが必要であるかがわかれば、コンシューマはキューの先頭にはないメッセージでもコンシュームできます。管理クライアントも、キューブラウザを使用して、キューの内容を監視できます。
パブリッシュ / サブスクライブメッセージング
パブリッシュ / サブスクライブドメインでは、メッセージプロデューサは、パブリッシャーと呼ばれ、メッセージコンシューマは、サブスクライバと呼ばれます。これらは、トピックと呼ばれる送信先を使用してメッセージを交換します。パブリッシャーは、トピックへメッセージをプロデュースし、サブスクライバはトピックへサブスクライブして、トピックからメッセージをコンシュームします。
図 2-3 に、パブリッシュ / サブスクライブドメインの単純なメッセージング操作を示します。MyTopicPublisher は、Msg1 を送信先 MyTopic へパブリッシュします。続いて、MyTopicSubscriber1 と MyTopicSubscriber2 はそれぞれ、MyTopic から Msg1のコピーを受信します。
図 2-3 単純なパブリッシュ / サブスクライブメッセージング
パブリッシュ / サブスクライブモデルでは、複数のサブスクライバが必要になるわけではありませんが、このドメインが複数のメッセージをブロードキャストできることを強調するために、図では 2 つのサブスクライバを示しています。トピックに対応するすべてのサブスクライバが、このトピックへパブリッシュされた任意のメッセージのコピーを取得します。
サブスクライバは、非永続でも永続でもかまいません。ブローカは、すべてのアクティブなサブスクライバのメッセージを保持しますが、非アクティブなサブスクライバのメッセージは、これらのサブスクライバが永続である場合にのみ保持します。
図 2-4 に、このパターンによって実現する可能性を表すために、より複雑なパブリッシュ / サブスクライブメッセージングのイメージを示します。複数のプロデューサがメッセージを Topic1 送信先にパブリッシュします。複数のサブスクライバが、Topic1 送信先からメッセージをコンシュームします。サブスクライバがセレクタを使用してメッセージをフィルタ処理しないかぎり、各サブスクライバは、選択したトピックへパブリッシュされたすべてのメッセージを取得します。図 2-4 では、MyTSubscriber2 は、Msg2 をフィルタで除外しています。
図 2-4 複雑なパブリッシュ / サブスクライブメッセージング
この複雑な図では、パブリッシュ / サブスクライブメッセージングに関するその他の要点が多数示されています。
- 複数のプロデューサから 1 つのトピックにメッセージをパブリッシュできる。プロデューサは、1 つのコネクションを共有することも、別々のコネクションを使用することもできますが、すべてが同じトピックにアクセスできます。
- 複数のサブスクライバが 1 つのトピックからメッセージをコンシュームできる。サブスクライバは、セレクタを使用してメッセージをフィルタで除外したり、コンシューム前にメッセージの有効期限が切れないかぎり、トピックへパブリッシュされたすべてのメッセージを取得します。
- サブスクライバは、1 つのコネクションを共有することも、別々のコネクションを使用することもできるが、すべてが同じトピックにアクセスできる。
- 永続サブスクライバは、アクティブでも非アクティブでもかまわない。非アクティブの間、サブスクライバへのメッセージはブローカが保持します。
- パブリッシャーとサブスクライバは、実行時に、動的に追加および削除できるので、必要に応じて、メッセージングシステムを拡張したり縮小したりできる。
- メッセージは、送信順にトピックへパブリッシュされるが、コンシュームされる順番は、メッセージの有効期限、メッセージの優先度、メッセージのコンシュームでセレクタを使用するかどうかなどの要因によって決まる。
- パブリッシャーとサブスクライバはタイミング依存性がある。トピックサブスクライバは、サブスクリプションの作成後にパブリッシュされたメッセージだけをコンシュームできます。
パブリッシュ / サブスクライブモデルの主要なメリットは、複数のサブスクライバへメッセージをブロードキャストできるという点です。
ドメイン固有 API と統合 API
JMS API では、ポイントツーポイントドメインまたはパブリッシュ / サブスクライブドメインのいずれかの実装に使用できるインタフェースとクラスを規定しています。これらは、表 2-1 の 2 列目と 3 列目に示したドメイン固有 API です。JMS API では、そのほかに統合ドメインを規定しており、これを使用すれば、汎用メッセージングクライアントをプログラムできます。このようなクライアントの動作は、メッセージのプロデュース先でありメッセージのコンシューム元である送信先のタイプによって決定されます。送信先がキューの場合、メッセージングはポイントツーポイントのパターンに従って動作します。送信先がトピックの場合、メッセージングはパブリッシュ / サブスクライブパターンに従って動作します。
表 2-1 JMS プログラミングドメインとオブジェクト
基本タイプ
(統合ドメイン)ポイントツーポイントドメイン
パブリッシュ / サブスクライブドメイン
Destination (Queue または Topic)1
Queue
Topic
ConnectionFactory
QueueConnectionFactory
TopicConnectionFactory
Connection
QueueConnection
TopicConnection
Session
QueueSession
TopicSession
MessageProducer
QueueSender
TopicPublisher
MessageConsumer
QueueReceiver
TopicSubscriber
1プログラミングの手法によっては、特定の送信先タイプを指定する必要があります。
統合ドメインは、JMS バージョン 1.1 から導入されています。以前の 1.02b 仕様に適合する必要がある場合は、ドメイン固有 API を使用できます。ドメイン固有 API を使用すると、たとえばキュー送信先に対する永続サブスクライバの作成など、特定のプログラミングエラーを防止するクリーンなプログラムインタフェースが得られます。ただしドメイン固有 API には、同じトランザクションまたは同じセッションにおいて、ポイントツーポイント操作とパブリッシュ / サブスクライブ操作を組み合わせることができないというマイナス面もあります。両方の操作を組み合わせる必要がある場合は、統合ドメイン API を選択してください。2 つのドメインの組み合わせ例については、「要求 / 応答パターン」を参照してください。
プログラミングオブジェクトJMS メッセージングの実装に使用されるオブジェクトは、基本的にプログラミングドメイン全体で同じです (コネクションファクトリ、コネクション、セッション、プロデューサ、コンシューマ、メッセージ、および送信先)。図 2-5 に、これらのオブジェクトを示します。図の上から下に向かい、コネクションファクトリオブジェクトからどのようにオブジェクトが生成されるかを示しています。
これらのオブジェクトのうち、コネクションファクトリと送信先の 2 つは、1 つのオブジェクトストア内にあるように示されています。これは、これらのオブジェクトが通常、管理対象オブジェクトとして作成、設定、管理されるという点を強調するためです。この章を通じて、コネクションファクトリと送信先は、プログラムではなく管理操作によって作成されると想定しています。
図 2-5 JMS プログラミングオブジェクト
表 2-2 は、メッセージの送受信に必要な手順をまとめています。手順 1、および 3 から 6 は、送信側と受信側で同じであることに注意してください。
以降の節では、プロデューサとコンシューマが使用するオブジェクト (コネクション、セッション、メッセージ、および送信先) について説明します。続いて、メッセージのプロデュースとコンシュームについて説明し、JMS オブジェクトの説明を締めくくります。
コネクションファクトリとコネクション
クライアントは、コネクションファクトリ (connection factory) オブジェクト (ConnectionFactory) を使用して、コネクション (connection) を作成します。コネクションオブジェクト (Connection) は、ブローカへのクライアントのアクティブなコネクションを表します。デフォルトで起動されるか、このクライアントの管理者が明示的に起動する基礎となるコネクションサービスを使用します。
通信リソースの割り当てとクライアントの認証は、コネクションが作成されるときに行われます。このオブジェクトは比較的重いため、ほとんどのクライアントはメッセージングのすべてを 1 つのコネクションだけで行います。コネクションは同時使用をサポートするため、複数のプロデューサとコンシューマが 1 つのコネクションを共有できます。
コネクションファクトリを作成するときに、そのプロパティーを設定しておくことによって、コネクションファクトリから生成されるすべてのコネクションの動作を設定できます。Message Queue の場合、次の情報を指定します。
- ブローカが存在するホストの名前、必要なコネクションサービス、およびそのサービスへアクセスするためにクライアントが使用するポート。
- コネクションに障害が生じた場合に、ブローカへの自動再接続を処理する方法。この機能は、コネクションが失われた場合に、クライアントを同じ (または別の) ブローカに接続し直します。データのフェイルオーバーは保証されません。別のブローカへ再接続した場合、持続メッセージと他の状態情報が失われる可能性があります。
- 永続サブスクリプションを追跡するためにブローカが必要とするクライアントの ID。
- 接続を試行するユーザーのデフォルト名とパスワード。接続時にパスワードが指定されない場合、この情報がユーザーの認証と操作の承認に使用されます。
- 信頼性に関係のないクライアントに対して、ブローカ通知を抑制すべきかどうか。
- ブローカとクライアントランタイムとの間で、コントロールメッセージおよびペイロードメッセージのフローを制御する方法。
- キューのブラウズの処理方法。(Java クライアントのみ)
- 特定のメッセージヘッダーフィールドをオーバーライドすべきかどうか。
クライアントアプリケーションの起動に使用するコマンド行から、コネクションファクトリのプロパティーをオーバーライドできます。また、どのコネクションのプロパティーも、そのコネクションのプロパティーを設定することによってオーバーライドできます。
コネクションオブジェクトを使用して、セッション (session) オブジェクトの作成、例外リスナーの設定、または JMS バージョンおよびプロバイダ情報の取得を行えます。
セッション
コネクションがクライアントとブローカ間の通信チャネルである場合、セッションは、クライアントとブローカ間の単一のやり取りをマークします。セッションオブジェクトは、主にメッセージ、メッセージプロデューサ、およびメッセージコンシューマの作成に使用します。セッションを作成するときには、多数の 通知 (acknowledgement) オプションまたはトランザクションを使用して、信頼性の高い配信を設定します。詳細は、「信頼性の高いメッセージング」を参照してください。
JMS 仕様によれば、セッションは、シングルスレッドコンテキストで、メッセージのプロデュースとコンシュームを実行します。単一のセッションに対して複数のメッセージプロデューサとコンシューマを作成できますが、順番に使用するという制限があります。スレッド処理の実装は、Java クライアントと C クライアントでは少し異なります。スレッド処理の実装および制限の詳細は、該当する開発者ガイドを参照してください。
また、セッションオブジェクトを使用して、次の処理も行えます。
- 管理対象オブジェクトを使用せずに送信先を定義するクライアントの送信先の作成および設定。
- 一時トピックおよびキューの作成および設定。これらは、要求 / 応答パターンの一部として使用されます。「要求 / 応答パターン」を参照してください。
- トランザクション処理のサポート。
- メッセージのプロデュースまたはコンシュームの順番の定義。
- 非同期コンシューマに対するメッセージリスナーの実行のシリアライズ。
- キューブラウザの作成。(Java クライアントのみ)
メッセージ
メッセージは、ヘッダー、プロパティー、および本体の 3 つの部分で構成されています。メッセージを正しく作成し、特定のメッセージング動作を設定するために、この構造を理解する必要があります。
メッセージヘッダー
すべての JMS メッセージにはヘッダーが必要です。ヘッダーには、あらかじめ定義された 10 のフィールドがあります。これらについて、表 2-3 で説明します。
この表からわかるように、メッセージヘッダーフィールドは、メッセージの識別、メッセージのルーティングの設定、メッセージ処理に関する情報の提供など、さまざまな目的に使用されます。
最も重要なフィールドの 1 つである JMSDeliveryMode によって、メッセージ配信の信頼性が決まります。このフィールドは、メッセージが持続かどうかを示します。
メッセージヘッダーフィールドにはプロバイダ (ブローカまたはクライアントランタイム) が設定するものも、クライアントが設定するものもあります。メッセージプロデューサは、特定のメッセージング動作を得るために、ヘッダー値を設定する必要が生じる場合があります。メッセージコンシューマは、メッセージがどのようにルーティングされ、どのような追加処理が必要かを認識するために、ヘッダー値を読み込む必要が生じる場合があります。
ヘッダーフィールド (JMSDeliveryMode、JMSExpiration、および JMSPriority) は、次の 3 つの異なるレベルに設定できます。
これらのフィールドを複数のレベルに設定した場合、コネクションファクトリに対して設定された値は、個々のメッセージに対して設定された値をオーバーライドします。特定のメッセージに対して設定された値は、メッセージのプロデューサに対して設定された値をオーバーライドします。
メッセージヘッダーフィールドに使用する定数名は、実装されている言語によって異なります。詳細は、『Message Queue Developer's Guide for Java Clients』または『Message Queue Developer's Guide for C Clients』を参照してください。
メッセージプロパティー
メッセージは、プロパティーと呼ばれるオプションのヘッダーフィールドも含めることができます。このフィールドは、プロパティー名とプロパティー値のペアとして指定されます。クライアントとプロバイダはプロパティーを使用して、メッセージヘッダーを拡張し、メッセージの識別と処理に役立つすべての情報を含めることができます。受信側クライアントは、メッセージプロパティーを使用して、指定された基準に適合したメッセージだけを配信するように要求できます。たとえば、コンシューミングクライアントは、ニュージャージーで働くパートタイム従業員の給与に関するメッセージが必要であることを示すことができます。プロバイダは、指定された基準に適合しないメッセージを配信しません。
JMS 仕様では、9 つの標準プロパティーが規定されています。クライアントが設定するプロパティーもあれば、プロバイダが設定するプロパティーもあります。その名前は予約文字「JMSX」で始まります。クライアントまたはプロバイダは、これらのプロパティーを使用して、メッセージの送信者、メッセージの状態、メッセージが配信された回数および時間を判断できます。これらのプロパティーは、プロバイダがメッセージをルーティングしたり、診断情報を提供したりする際に役立ちます。
Message Queue でもメッセージプロパティーが定義されています。これらのプロパティーは、圧縮されたメッセージを識別し、そのメッセージを配信できない場合の処理方法を識別するために使用されます。詳細は、『Message Queue Developer's Guide for Java Clients』を参照してください。
メッセージ本体
メッセージ本体には、クライアントが交換しようとするデータが含まれます。
表 2-4 に示すように、JMS メッセージのタイプによって、本体に含まれる内容と、コンシューマによる処理方法が決まります。セッションオブジェクトには、メッセージ本体の各タイプに応じた作成メソッドが含まれます。
Java クライアントは、送信するメッセージの本体をクライアントランタイムで圧縮するように、プロパティーを設定することができます。コンシューマ側の Message Queue ランタイムは、メッセージを解凍してから配信します。
メッセージのプロデュースメッセージは、コネクションおよびセッションのコンテキスト内でメッセージプロデューサによって送信またはパブリッシュされます。メッセージのプロデュースは、とても簡単です。クライアントは、メッセージプロデューサオブジェクト (MessageProducer) を使用して、送信先オブジェクトにより API 内に示される物理的な送信先 (destination) にメッセージを送信します。
プロデューサを作成するときに、すべてのプロデューサのメッセージが送信されるデフォルトの送信先を指定できます。また、持続性、優先度、および有効期間を制御するメッセージヘッダーフィールドのデフォルト値も指定できます。したがって、メッセージの送信時に代わりの送信先を指定したり、指定されたメッセージのヘッダーフィールドに代わりの値を設定したりすることによってオーバーライドしないかぎり、これらのデフォルト値は、そのプロデューサから出されるすべてのメッセージによって使用されます。
メッセージプロデューサは、JMSReplyTo メッセージヘッダーフィールドを設定することにより、要求 / 応答パターンも実装できます。詳細は、「要求 / 応答パターン」を参照してください。
メッセージのコンシュームメッセージは、コネクションおよびセッションのコンテキスト内でメッセージコンシューマによって受信されます。クライアントは、メッセージコンシューマオブジェクト (MessageConsumer) を使用して、送信先オブジェクトとして API 内に示される指定された物理的な送信先からメッセージを受信します。
次の 3 つの要因は、ブローカがメッセージをコンシューマに配信する方法に影響します。
メッセージの配信およびクライアント設計に影響するその他の主要な要因は、コンシューマで必要となる信頼性の度合いです。「信頼性の高いメッセージング」を参照してください。
同期コンシューマと非同期コンシューマ
メッセージコンシューマは、同期または非同期のどちらかのメッセージのコンシュームをサポートしています。
セレクタを使用したメッセージのフィルタ処理
メッセージコンシューマは、メッセージセレクタを使用して、プロパティが特定の選択条件に一致するメッセージだけをメッセージサービスによって配信させることができます。コンシューマを作成するときに、この基準を指定します。
セレクタは SQL に似た構文を使用してメッセージプロパティーを照合します。たとえば次のようになります。
color = 'red'
size > 10
Java クライアントも、キューをブラウズしているときに、セレクタを指定できます。これにより、選択したメッセージのうちコンシュームされるのを待機しているメッセージを確認できます。
永続サブスクライバの使用
セッションオブジェクトを使用して、トピックへの永続サブスクライバを作成できます。ブローカは、このようなサブスクライバに対するメッセージを、このサブスクライバが非アクティブになった場合でも保持します。
ブローカは、サブスクライバの状態を保持し、サブスクライバが再度アクティブになったときにメッセージの配信を再開する必要があるので、サブスクライバの送受信全体から指定されたサブスクライバを識別できる必要があります。サブスクライバの識別情報は、サブスクライバを作成したコネクションの ClientID プロパティーと、サブスクライバを作成するときに指定したサブスクライバ名から構成されています。
要求 / 応答パターン同じコネクション内で、または統合 API を使用しているときはセッション内でも、プロデューサとコンシューマを組み合わせることができます。さらに、JMS API では、一時送信先を使用することにより、メッセージング操作用の要求 / 応答パターンを実装できます。
要求 / 応答パターンを設定するために、メッセージプロデューサは次のタスクを実行する必要があります。
メッセージコンシューマは、メッセージを処理するときに、メッセージの JMSReplyTo フィールドを調べ、応答が要求されているかどうかを判断し、指定された送信先へ応答を送信します。
要求応答メカニズムにより、プロデューサは、応答送信先用の管理対象オブジェクトを設定する必要がなくなり、コンシューマは、要求に対して簡単に応答できるようになります。このパターンは、プロデューサが、続行する前に要求が処理されていることを確認する必要があるときに役立ちます。
図 2-6 に、トピックへメッセージを送信し、一時キュー内の応答を受信する要求 / 応答パターンを示します。
図 2-6 要求 / 応答パターン
図に示すように、 MyTopicPublisher は、Msg1 を送信先 MyTopic へプロデュースします。MyTopicSubsriber1 と MyTopicSubscriber2 はメッセージを受信し、MyTempQueue へ応答を送信します。そこから MyTQReceiver が応答を取り出します。このパターンは、たとえば、多数のクライアントへ価格情報をパブリッシュし、順次処理を行うためにその (応答) 命令をキューに入れるアプリケーションに役立ちます。
一時送信先は、一時送信先を作成したコネクションが存在する間だけしか存続しません。どのプロデューサも一時送信先に送信できますが、一時送信先にアクセスできる唯一のコンシューマは、送信先を作成したコネクションと同じコネクションによって作成されたコンシューマです。
要求 / 応答パターンは一時送信先の作成によって決まるので、次の場合にはこのパターンを使用しないでください。
信頼性の高いメッセージングメッセージング配信は 2 つのステップで行われます。最初のステップでは、プロデューサからブローカ上の物理的な送信先へメッセージが送られます。次のステップでは、その送信先からコンシューマへメッセージが送られます。このように、メッセージは、ブローカへの移動、ブローカに突然障害が発生した場合にブローカのメモリーに格納されている間、ブローカからコンシューマへの移動という 3 つのいずれかの段階で消失する可能性があります。信頼性の高い配信は、これらのどの段階でも配信が失敗しないように保証します。ブローカに障害が発生した場合、非持続メッセージは常に消失する可能性があるので、信頼性の高い配信は持続メッセージにのみ該当します。
信頼性の高い配信を確保するために、次の 2 つのメカニズムが使用されます。
- クライアントは、通知 (acknowledgement) またはトランザクション (transaction) を使用して、メッセージのプロデュースおよびコンシュームが成功したことを確認できる。
- メッセージがコンシュームされる前にブローカに障害が発生した場合に、保存されたメッセージのコピーを取得して操作を再試行できるように、ブローカは持続ストアにメッセージを保存できる。
次の節では、信頼性を確保する場合の 2 つの側面について説明します。
通知
通知は、信頼性の高いメッセージの配信を確実に行うために、クライアントとメッセージサービスの間で送信されるメッセージです。通知は、プロデューサとコンシューマとでは使用方法が異なります。
メッセージがプロデュースされる場合、ブローカは、メッセージを受信し、送信先に保管し、持続的に保存したことを通知します。プロデューサの send() メソッドは、通知を受信するまでブロックします。持続メッセージが送信されるとき、これらの通知はクライアントからは見えません。
メッセージがコンシュームされる場合、クライアントは、ブローカが送信先からメッセージを削除する前に、送信先から配信されたメッセージを受信し、コンシュームしたことを通知します。JMS では、違うレベルの信頼性を表す別の通知モードを規定しています。
- AUTO_ACKNOWLEDGE モードでは、クライアントによってコンシュームされる各メッセージについてセッションが自動的に通知します。セッションスレッドはブロックし、コンシュームされたメッセージそれぞれのクライアント通知をセッションが処理したことをブローカが確認するまで待ちます。
- CLIENT_ACKNOWLEDGE モードでは、クライアントは、1 つ以上のメッセージがコンシュームされたあとに、メッセージオブジェクトの acknowledge() メソッドを呼び出すことによって明示的に通知します。このため、セッションは、このメソッドを最後に呼び出してからセッションによってコンシュームされたすべてのメッセージに対して通知します。セッションスレッドはブロックし、クライアント通知をセッションが処理したことをブローカが確認するまで待ちます。
信頼性よりもパフォーマンスを重視するクライアントの場合、Message Queue サービスでは、NO_ACKNOWLEDGE モードを用意することにより、JMS API を拡張しています。このモードでは、ブローカはクライアント通知を追跡しないので、メッセージがコンシューミングクライアントによって正常に処理されたかどうか保証されません。このモードを選択した場合、非永続サブスクライバへ送信される非持続メッセージのパフォーマンスが向上します。
トランザクション
トランザクション とは、1 つ以上のメッセージのプロデュースまたはコンシューム、あるいはその両方を 1 つの極小の単位にグループ化する方法です。前述のクライアントとブローカの通知プロセスは、トランザクションにも適用されます。この場合、クライアントランタイムおよびブローカ通知は、トランザクションのレベルで自動的に処理されます。トランザクションがコミットされると、ブローカの通知が自動的に送信されます。
セッションは処理済みとして設定でき、JMS API には、トランザクションの開始、コミット、またはロールバックを行うメソッドが用意されています。
メッセージがトランザクション内でプロデュースまたはコンシュームされるに従って、メッセージサービスがさまざまな送受信を追跡し、JMS クライアントが呼び出しを実行してトランザクションを確定したときにだけ、送受信の操作を完了させます。トランザクション内での特定の送信や受信の操作が失敗すると、例外が発生します。クライアントコードは、これを無視するか、操作を試行し直すか、またはトランザクション全体をロールバックして、例外を処理できます。トランザクションがコミットされると、すべての操作が完了します。トランザクションがロールバックされると、正常に行われたすべての操作が取り消されます。
トランザクションの範囲は、常に単一セッションです。つまり、単一セッションのコンテキストで実行された、1 つ以上のプロデューサまたはコンシューマの操作は、単一のトランザクションにグループ化されます。トランザクションは 1 つのセッション内で行われるので、1 つの終端間トランザクションでメッセージのプロデュースとコンシュームの両方を行うことはできません。
JMS 仕様では、分散トランザクションもサポートしています。つまり、メッセージのプロデュースとコンシュームは、データベースシステムなど、ほかのリソースマネージャーに関連した操作を含む大容量の分散トランザクションの一部となります。分散トランザクションをサポートするには、Java Systems Application Server が提供するトランザクションマネージャーなどを入手する必要があります。
分散トランザクションでは、Java Transaction API (JTA)、XA Resource API の仕様で定義された 2 フェーズコミットプロトコルを使用して、メッセージサービスやデータベースマネージャーといった複数のリソースマネージャーによって実行される操作を、分散トランザクションマネージャーが追跡および管理します。Java の世界では、リソースマネージャーと分散トランザクションマネージャー間の対話は、JTA の仕様で記述されます。
分散トランザクションのサポートとは、メッセージングクライアントが、JTA で定義される XAResource インタフェースを介して、分散トランザクションに加わることができるということです。このインタフェースでは、2 フェーズコミットを実装するための、数多くのメソッドが定義されます。API の呼び出しがクライアント側で行われている間、JMS メッセージサービスは分散トランザクション内のさまざまな送受信操作やトランザクションの状態を追跡し、Java Transaction Service (JTS) で提供される分散トランザクションマネージャーと一致したときにだけ、メッセージング操作を完了します。
ローカルトランザクションに関しては、無視したり、操作を試行し直したり、分散トランザクション全体をロールバックしたりして、クライアントは例外を処理できます。
持続ストレージ
信頼性のもう 1 つの側面は、ブローカが持続メッセージをコンシューマに配信する前に、その持続メッセージを失うことがないようにすることです。つまり、メッセージが物理的な送信先に到達したら、ブローカはそのメッセージを持続データストア (data store) に保管する必要があります。何かの理由でブローカが停止した場合、持続データストアは後からメッセージを復元し、適切なコンシューマに配信します。
ブローカは、永続サブスクリプションも持続的に保存する必要があります。持続的に保存しないと、障害が発生した場合、ブローカは、メッセージがトピック送信先に届いたあとにアクティブになった永続サブスクライバにメッセージを配信できなくなります。
メッセージ配信を保証するメッセージングアプリケーションは、メッセージを持続的として指定し、永続サブスクリプション状態のトピック送信先またはキュー送信先のいずれかにメッセージを配信する必要があります。
第 3 章「Message Queue サービス」では、Message Queue サービスで用意されているデフォルトのメッセージストアと、管理者による代替ストアのセットアップおよび設定方法について説明します。
システム全体でのメッセージの流れこれまで示してきた説明のまとめとして、ここでは、Message Queue サービスで、どのようにメッセージがプロデューサからコンシューマへ配信されているかついて説明します。全体像を理解するため、さらに説明する必要があります。配信の過程でシステムが処理するメッセージは、次の 2 つのカテゴリに分類されます。
図 2-7 に、メッセージ配信を示します。
図 2-7 メッセージ配信手順
信頼性の高い方法で、持続的に配信されるメッセージのメッセージ配信手順は次のとおりです。
メッセージのプロデュース
1. クライアントランタイムが、コネクションを使用して、メッセージプロデューサからブローカにメッセージを配信します。
メッセージの処理とルーティング
2. ブローカが、コネクションからメッセージを読み込み、適切な送信先に保管します。
3. ブローカが (持続) メッセージをデータストアに保管します。
4. ブローカが、メッセージを受信したことについて、メッセージプロデューサのクライアントランタイムに通知します。
5. ブローカが、メッセージのルーティングを決定します。
6. ブローカは、コンシューマの一意の識別子をメッセージに付けて、メッセージをその送信先から適切なコネクションへ書き出します。
メッセージのコンシューム
7. メッセージコンシューマのクライアントランタイムが、コネクションからメッセージコンシューマにメッセージを配信します。
8. メッセージコンシューマのクライアントランタイムが、メッセージをコンシュームしたことについて、ブローカに通知します。
メッセージの存続終了
9. ブローカはクライアント通知を処理し、すべての通知を受信したときに、(持続) メッセージを削除します。
10. ブローカは、コンシューマのクライアントランタイムに対して、クライアント通知が処理されたかどうかを確認します。
管理者がメッセージを送信先から削除した場合、または管理者が永続サブスクリプションを削除または再定義し、その結果、トピック送信先内のメッセージが配信されずに削除された場合、ブローカはメッセージがコンシュームされる前にメッセージを破棄できます。その他の状況では、ブローカにメッセージを破棄させるのではなく、デッドメッセージキューと呼ばれる特殊な送信先に保存させることができます。メッセージの有効期限が切れたとき、メモリーの制限のために削除されたとき、またはクライアントが例外をスローしたために配信が失敗したとき、メッセージはデッドメッセージキューに保管されます。メッセージをデッドメッセージキューに保存しておくと、システムの問題を解決し、特定の状況でメッセージを復元することができます。
SOAP メッセージの処理SOAP (「Java クライアントでの SOAP サポート」を参照) を使用すると、分散環境にある 2 つのピア間で構造化データ (XML 方式で指定) を交換できます。Sun の SOAP の実装では、現在、信頼性の高い SOAP メッセージングをサポートしておらず、SOAP メッセージのパブリッシングもサポートしていません。ただし、Message Queue サービスを使用して、信頼性の高い SOAP メッセージングを取得し、必要な場合は、SOAP メッセージをパブリッシュできます。Message Queue サービスは、直接 SOAP メッセージを配信しませんが、SOAP メッセージを JMS メッセージにラップし、通常の JMS メッセージのようにこれらのメッセージをプロデュースおよびコンシュームして、JMS メッセージから SOAP メッセージを抽出できます。
Message Queue では、javax.xml.messaging と com.sun.messaging.xml の 2 つのパッケージを使用して、SOAP サポートを提供します。これらのライブラリに実装されたクラスを使用して、SOAP メッセージを受信し、SOAP メッセージを JMS メッセージにラップし、JMS メッセージから SOAP メッセージを抽出できます。J2EE プラットフォームには、パッケージ java.xml.soap が用意されており、このパッケージを使用して、SOAP メッセージをアセンブルまたは逆アセンブルできます。
信頼性の高い SOAP メッセージングを取得するには、次の手順を行う必要があります。
- java.xml.soap パッケージで定義されたオブジェクトを使用して SOAP メッセージを作成するか、javax.xml.messaging パッケージで定義されたサーブレットを使用して SOAP メッセージを受信するか、または JAX-RPC などの Web サービスを使用して SOAP メッセージを受信します。
- MessageTransformer ユーティリティーを使用して、SOAP メッセージを JMS メッセージに変換します。
- 目的の送信先に JMS メッセージを送信します。
- JMS メッセージを非同期的または同期的にコンシュームします。
- JMS メッセージをコンシュームしたあと、MessageTransformer ユーティリティーを使用して、SOAP メッセージに変換します。
- SAAJ API (java.xml.soap パッケージで定義) を使用して、SOAP メッセージを逆アセンブルします。
SOAP メッセージとその処理に関する詳細な情報については、『Message Queue Developer's Guide for Java Clients』を参照してください。
Java クライアントと C クライアントMessage Queue では、そのメッセージングサービス用の C API を備えているため、旧バージョンの C アプリケーションと C++ アプリケーションを、JMS ベースのメッセージングに加えることができます。
JMS プログラミングモデルは、Message Queue C クライアントの設計の基盤です。『Message Queue Developer's Guide for C Clients』では、このモデルが C データタイプや関数によってどのように実装されているかについて説明しています。
Java インタフェースと同様に、C インタフェースは次の機能をサポートします。
ただし、Java Message Service 仕様は、Java クライアントに限定した標準であることに注意する必要があります。したがって、C Message Queue API は、Message Queue プロバイダ固有の機能であり、他の JMS プロバイダでは使用できません。C クライアントを含んだメッセージングアプリケーションは、別の JMS プロバイダでは処理できません。
C インタフェースでは、次の機能がサポートされません。