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