10 メッセージ順序単位の使用

メッセージ順序単位を使用して、WebLogic JMSの使用時に厳格なメッセージ順序を提供する方法を学習します。

メッセージ順序単位とは

メッセージ順序単位はWebLogic Serverの機能です。スタンドアロンのメッセージ・プロデューサや、単体として動作するプロデューサのグループは、この機能を使用して複数のメッセージを処理順序に応じた1つの単位にグループ化できます。

この単位を順序単位と呼び、この単位からのすべてのメッセージはその作成順に従って処理されます。

順序単位によるメッセージ処理の理解

WebLogic Serverのメッセージ順序単位機能によるメッセージ処理と、JMS仕様に記述されているメッセージ処理の相違点について説明します。

JMS仕様に準拠したメッセージ処理

Java Message Service仕様(http://www.oracle.com/technetwork/java/jms/index.html)ではメッセージ配信の順序付けが規定されていますが、この順序付けは非常に厳格に適用されます。プロデューサの単一のインスタンスとコンシューマの単一のインスタンスの間の順序が定義されますが、以下のような一般的な状況は考慮されていません。

順序単位によるメッセージ処理

メッセージ順序単位機能を使用すると、メッセージ・プロデューサや単体として動作するプロデューサのグループが、複数のメッセージを1つの単位にグループ化してメッセージを作成順に処理することが可能になります。単一のメッセージのメッセージ処理は、メッセージが確認応答、コミット、回復、またはロールバックされたときに完了します。メッセージのメッセージ処理が完了するまでは、その順序単位の残りの未処理メッセージがブロックされます。

この項では、順序単位を使用した場合のJMS確認応答モード(http://www.oracle.com/technetwork/java/jms/index.html)の規則について説明します。

  • 確認応答モードがCLIENT_ACKNOWLEDGEAUTO_ACKNOWLEDGE、またはDUPS_OK_ACKNOWLEDGEである場合、順序単位のメッセージは並行処理されません。

  • コンシューマをクローズすると、セッションの確認応答に関係なく、現在のメッセージ処理が完了します。

  • CLIENT_ACKNOWLEDGE - アプリケーションがMessage.acknowledgeおよびSession.recoverを呼び出すと、順序単位内でどのメッセージの処理が完了したかが示されます。

  • AUTO_ACKNOWLEDGE - receiveの呼出しからセッションが正常に返されたとき、または呼び出されたMessageListenerからセッションが正常に返されたときに、セッションが自動的にクライアントによるメッセージの受信を確認応答します。

    • 非同期モード: 正常な完了またはonMessage(msg)の例外は、メッセージが正常に処理されたタイミングを示します。

    • 同期モード:特定のコンシューマ(たとえばコンシューマA)では、consumerA.receiveconsumerA.setMessageListener、またはconsumerA.closeが発生したときにconsumerA.receiveが完了します。

  • DUPS_OK_ACKNOWLEDGE - receiveの呼出しからセッションが正常に返されたとき、または呼び出されたMessageListenerからセッションが正常に返されたときに、セッションが自動的にクライアントによるメッセージの受信を確認応答します。

    • 非同期モード:正常な完了またはonMessage(msg)の例外は、メッセージが正常に処理されたタイミングを示します。

    • 同期モード:特定のコンシューマ(たとえばコンシューマA)では、consumerA.receive()consumerA.setMessageListener()、またはconsumerA.close()が発生したときにconsumerA.receive()が完了します。

  • NO_ACKNOWLEDGE - セッションは、処理の順序を保証しません。メッセージは、使用可能な別のコンシューマで並行処理できます。

順序単位によるメッセージ配信

メッセージ順序単位では、以下の規則に従ってメッセージが配信されます。

  • 順序単位のメンバー・メッセージは、作成された順番でキュー・コンシューマに配信されます。順序単位内でのメッセージの順序は、ソート条件、優先度、およびフィルタには影響されません。ただし、未コミットのメッセージにRedelivery Delayまたは期限切れになっていないTimetoDeliverタイマーが設定されている場合は、それ以降のメッセージが遅延します。

  • 順序単位メッセージは、一度に1つずつ処理されます。1つのメッセージの処理が完了したら、順序単位内の次のメッセージが配信されます。

  • 分散キューに送信された順序単位メッセージは、分散キューの1つの物理メンバー上にのみ存在します。詳細については、「分散宛先で順序単位を使用する」を参照してください

  • 同じ順序単位からの未コミットまたは未応答のメッセージはすべて、同じトランザクション(トランザクション非対応の場合は同じJMSSession)に存在しなければなりません。順序単位内の1つのメッセージが未コミットまたは未応答である場合、他のメッセージは同じトランザクションまたはJMSSessionにのみ配信されます。これにより、同じ順序単位からのすべての未応答メッセージが1つの回復可能な処理内に保持され、ロールバックや回復に関係なく順序を維持できます。

  • キューに同じ順序単位からの複数のメッセージがある場合、それらがすべて処理されるまでは、そのキューに次のメッセージを配信したり、キュー・コンシューマにそれらのメッセージを配信したりすることはできません。

    たとえば、

    • メッセージM1からMnがトランザクションの一部として配信され、トランザクションはロールバックされる(処理は完了)場合、メッセージM1からMnは、任意の利用可能なコンシューマに配信されます。

    • メッセージM1からMnがトランザクション外で配信され、メッセージが回復される(処理は完了)場合、メッセージM1からMnは、任意の利用可能なコンシューマに配信されます。

    • メッセージM1からMnがトランザクション外で配信され、メッセージが確認応答される(処理は完了)場合、未配信のメッセージMn+1は、任意の利用可能なコンシューマに配信されます。

メッセージ順序単位のケース・スタディ

オンライン書店への本の注文に基づくケース・スタディを利用して、メッセージ順序単位機能を学習します。

Joeによる本の注文

XYZオンライン書店は、JMSを使用して顧客の注文を処理する単純な処理設計を実装しています。JMS処理システムは、以下から構成されます。

  • キュー(Queue1)に送信するメッセージ・プロデューサ

  • Queue1からのメッセージを処理する複数のメッセージドリブンBean (MdbX、MdbYなど)

  • 注文および注文のステータス情報を格納するデータベース(myDB)

Joeは、XYZオンライン書店の自分のアカウントにログインして、購入したい本を検索します。本を選び、会計に進んで、販売トランザクションを完了します。ここでJoeは、以前に同じ本を買っていたことに気付き、注文を取り消します。ところが1週間後、その本がJoeのもとに届いてしまいます。

Joeの注文の処理

Joeの注文シナリオでは、注文の取消しメッセージが、注文メッセージよりも前に処理されました。その結果、買いたくなかった本が届けられてしまいました。ここでは、Joeの注文が処理されたステップについて説明します。

図10-1とそれに対応する各アクションは、Joeの注文がどのように処理されたかを示します。

図10-1 Joeの注文のワークフロー

図10-1の説明が続きます
「図10-1 Joeの注文のワークフロー」の説明
  1. Joeが、ショッピング・カートから注文ボタンをクリックします。

  2. 注文メッセージ(メッセージA)がQueue1に配置されます。

  3. Joeが注文を取り消します。

  4. 注文取消しメッセージ(メッセージB)がQueue1に配置されます。

  5. MdbXQueue1からメッセージAを取得します。

  6. MdbYQueue1からメッセージBを取得します。

  7. MdbYが取消しメッセージをデータベースに書き込みます。対応する注文メッセージがないため、どの注文メッセージもデータベースから削除されません。

  8. MdbXが注文メッセージをデータベースに書き込みます。

  9. 本の発送を処理するアプリケーションがデータベースを読み取り、注文メッセージを見てJoeの家への発送を開始します。

Java Message Service仕様(http://www.oracle.com/technetwork/java/jms/index.html)にはメッセージ配信の順序付けが規定されていますが、プロデューサの単一のインスタンスとコンシューマの単一のインスタンスの間でのメッセージ配信の順序付けしか規定されていません。Joeのケースでは、Queue1のメッセージを複数のMDBが消費できるため、メッセージの処理順序はまったく保証されなくなっていました。

メッセージ順序単位による問題解決

Joeの注文に関わるすべてのメッセージが常に正しく処理されるようにするには、XYZ書店のシステム管理者がユーザー・セッションに基づいてメッセージ順序単位を構成して、ユーザー・セッションからのすべてのメッセージに順序単位名属性を持たせ、値としてセッションIDを設定します。「順序単位の作成方法」を参照してくださいWebLogic Serverでは順序単位内のメッセージが並行処理されることはないため、Joeのユーザー・セッションの間に作成されたすべてのメッセージは作成された順番どおりに処理されます。

図10-2とそれに対応する各アクションは、メッセージ順序単位を使用した場合にJoeの注文がどのように処理されるかを示します。

図10-2 順序単位を使用した場合のJoeの注文のワークフロー

図10-2の説明が続きます
「図10-2 順序単位を使用した場合のJoeの注文のワークフロー」の説明
  1. Joeが、ショッピング・カートから注文ボタンをクリックします。

  2. 注文メッセージ(メッセージA)がQueue1に配置されます。

  3. Joeが注文を取り消します。

  4. 注文取消しメッセージ(メッセージB)がQueue1に配置されます。

  5. MdbXがQueue1からメッセージAを取得します。

  6. MdbYがQueue1からメッセージBを取得します。

  7. MdbYのメッセージBは、MdbXが注文メッセージを応答確認するまではブロックされます。「処理中にメッセージが遅延した場合の処理」を参照してください。

  8. メッセージAがコミットされ、データベースに書き込まれます。

  9. メッセージBがコミットされ、データベースに書き込まれます。

    対応する注文メッセージが存在するため、Joeの注文はデータベースから削除され、本が届けられることはありません。

順序単位の作成方法

メッセージ処理単位をプログラムで、または管理機能を使用して作成する方法を学習します。

「順序単位によるメッセージ配信」および「メッセージ順序単位の高度なトピック」も参照してください

順序単位をプログラム的に作成する

WLMessageProducerインタフェースのsetUnitOfOrder()メソッドを使用して、プロデューサを順序単位名に関連付けます。

次の例では、順序単位名属性の値がmyUOOnameに設定されます。

getProducer().setUnitOfOrder("myUOOname");

プロデューサを順序単位名に関連付けると、プロデューサをクローズするか、プロデューサと順序単位の関連付けが解消されるまで、このプロデューサが送信するすべてのメッセージは順序単位として処理されます。

例10-1に、プロデューサと順序単位を関連付ける方法を示します。

例10-1 WLMessageProducerインタフェースを使用した順序単位の作成

.
.
.
queue = (Queue)(ctx.lookup(destName));
qsender = (WLMessageProducer) qs.createProducer(queue);
qsender.setUnitOfOrder();
uooname = qsender.getUnitOfOrder();
System.out.println("Using UnitOfOrder :" + uooname);
.
.
.

順序単位を管理者が作成する

ここでは、JMS接続ファクトリやJMS宛先を構成して、メッセージ順序単位を有効にする方法について説明します。

接続ファクトリと宛先の順序単位を構成する

以下のいずれかの方法で、JMS接続ファクトリと宛先を構成してメッセージ順序単位を有効にします。

従来のJMSアプリケーションと相互運用する場合には、接続ファクトリまたは宛先に管理的に順序単位を構成する必要があります。この方法は、コードを変更することなく、メッセージが作成順に処理されるようにするための単純なメカニズムを提供します。

順序単位のネーミング・ルール

順序単位は、名前属性によって特定されます。宛先内では、順序単位名属性に同じ値が設定されているメッセージが、同じ順序単位に属します。名前は、システムからでもアプリケーションからでも指定できます。同じ順序単位内のすべてのメッセージは、同じ名前を共有します。「順序単位の作成方法」を参照してください

順序単位の名前属性は、以下の規約に準拠させる必要があります。

  • 順序単位名属性の有効な値は、nullでも空でもない文字列でなければなりません。

  • システム生成の順序単位名は、タイムスタンプ・ベースで統計的に一意になります。

  • アプリケーションからは、独自の順序単位名を指定できます。たとえば、WebLogic Integrationアプリケーションではワークフロー名を使用したり、Webサービス・アプリケーションでは会話名を使用したりできます。

  • メッセージ順序単位には、独自のネームスペースがあります。順序単位は、他の名前付きオブジェクトに対して一意にする必要はありません。たとえば、Fooというキューが存在する場合でも、Fooという順序単位名は有効です。

  • メッセージ順序単位のスコープは、単一の宛先に限定されます。2つの宛先のそれぞれの順序単位を同じ名前にしても構いません。

  • 1つまたは複数のプロデューサが、同じ文字列を使用して順序単位を作成することで、同じ順序単位名のメッセージを送信できます。

    システム生成の順序単位名は、複数のプロデューサで使用できます。このパラダイムは、アプリケーションによって割り当てられた順序単位名にもそのまま適用できます。情報が一元的にシリアライズされているのが最も効率的です。したがって、順序単位名としては会話IDのようなプロパティのみを格納するようにしてください。このパラダイムは、メッセージが順序単位非対応のJMSプロバイダ(WebLogic 9.0より前のリリースやWebLogic以外のJMSプロバイダ)で送信された場合には適用されません。

現在の順序単位の取得

順序単位名は、配信されたメッセージから抽出できます。

たとえば:

msg.getStringProperty("JMS_BEA_UnitOfOrder");

メッセージ順序単位の高度なトピック

より高度で複雑な状況での順序単位によるメッセージ処理方法について説明します。

処理中にメッセージが遅延した場合の処理

メッセージ処理の間には、通常であればメッセージの処理順序が変更されるような状況が数多く発生します。以下に、メッセージの配信準備を整えることができない典型的なメッセージ処理状態を示します。

  • メッセージが、コミットされていないトランザクション内にあります。

  • メッセージのTimeToDeliver値により、TimeToDeliver間隔が経過するまでメッセージを配信できません。

  • コンシューマが回復またはロールバック処理を呼び出したため、RedeliveryDelay間隔が経過するまではメッセージを再配信できません。

たとえば、メッセージAとメッセージBが同じ順序単位に届き、前述の理由でメッセージAを配信できないとします。この場合、メッセージBの配信を遅延させる要因がなくても、順序単位内のメッセージAが配信されるまではメッセージBを配信することはできません。

フィルタのせいでメッセージを配信できない場合の処理

フィルタと順序単位を使用すると、予期しない動作が発生することがあります。たとえば、メッセージAからZが、同じキューの同じ順序単位にあるとします。Consumer1にはフィルタが設定されており、メッセージA、B、およびCがそのフィルタ条件を満たすため、これらのメッセージがConsumer1に配信されます。

  1. メッセージDからZは、メッセージA、B、およびCが確認応答されるまでは配信できません。

  2. メッセージA、B、およびCが確認応答または回復されます。

  3. メッセージDがメッセージ配信システムから利用可能な状態になります。

  4. メッセージDはフィルタ条件を満たさないため、Consumer1に配信されることはありません。

  5. メッセージEからZは、メッセージDが処理されるまでは配信できません。

  • メッセージDを含むトランザクションは、ロールバックされる必要があります。

  • メッセージDが処理されると、メッセージEからZを配信できます。

詳細については、「メッセージのフィルタ処理」を参照してください

宛先ソート・キーを使用している場合の処理

宛先ソート・キーは、メッセージが順序単位の一部でない場合や、同じ順序単位の一部でない場合に、コンシューマにメッセージを配信する順序を制御します。

たとえば、届いたメッセージAおよびBがキュー上の同じ順序単位に含まれており、優先度の降順でソートされていて優先度はメッセージAよりメッセージBのほうが高いとします。

メッセージBのほうがメッセージAよりも優先度が高くても、これらのメッセージは同じ順序単位に含まれているため、メッセージAが処理されるまではメッセージBを配信できません。次に届いたメッセージCは、順序単位が設定されていないか、メッセージAと同じ順序単位には含まれていないとします。この場合、メッセージCの優先度設定とメッセージAの優先度設定によって配信順序が決まります。『Oracle WebLogic Server JMSリソースの管理』基本JMSシステム・リソースの構成に関する項を参照してください。

分散宛先で順序単位を使用する

すでに「JMS仕様に準拠したメッセージ処理」で説明したように、アプリケーションで分散キューを使用している場合、Java Message Service仕様(http://www.oracle.com/technetwork/java/jms/index.html)のメッセージ配信の順序付けは保証されません。WebLogic JMSでは、分散宛先がターゲット指定されている複数のメッセージに同じ順序単位が設定されている場合は、それらのメッセージを同じ分散宛先メンバーに転送します。メンバーは、宛先の順序単位構成に基づいて選択されます。

パス・サービスを使用する

WebLogicパス・サービスを構成すると、順序単位に含まれるメッセージをその宛先リソース(共通分散宛先のメンバー)にルーティングするために必要な情報を格納する永続マップを提供できます。共通分散宛先のWebLogicパス・サービスが構成されていない場合、メンバー宛先へのルーティング・パスは、分散キューの実行時のロード・バランシング・ヒューリスティックに基づいて決定されます。

ハッシュ・ベースのルーティングを使用する

WebLogicパス・サービスが構成されていない場合、メンバー・キューへのデフォルトのルーティング・パスは、メッセージ順序単位名と共通分散キュー・メンバーのハッシュ・コードに基づいて選択されます。このルーティング・メカニズムの利点は、分散キュー・メンバーへのルートがすばやく計算され、クラスタ内の永続ストレージを必要としない点です。

メッセージ順序単位とハッシュ・ベースのルーティングを実装する際には、以下のことに留意してください。

  • 順序単位が関連付けられている分散キュー・メンバーが分散キューから削除されると、新しいメッセージは別の分散キュー・メンバーに送信され、古いメッセージとそのメッセージとの継続性は失われます。

  • 順序単位が関連付けられている分散キュー・メンバーにアクセスできない場合は、メッセージを送信しているプロデューサがJMSOrderExceptionをスローし、メッセージは別の分散キュー・メンバーにはルーティングされません。この例外がスローされるのは、JMSメッセージ・システムが必要なサービス品質を満たすことができないからです。特定の順序単位に対しては、1つの分散宛先メンバーだけがメッセージを消費できます。

共通分散宛先でのルーティングを構成する

メッセージ順序単位を使用して、共通分散宛先でのパス・サービスまたはハッシュ・ベースのルーティング・メカニズムを構成する場合は、次のトピックを参照してください。

トピックで順序単位を使用する

順序単位を割り当てても、同じトピック上の2つのサブスクライバによるメッセージの並行処理は可能です。トピックの個々のサブスクライバには独自の宛先とメッセージ・リストがあるため、コンシューマが1つのキューと同様に、メッセージは生成時に割り当てられた順序単位に従ってすべてのサブスクライバによって処理されます。

順序単位と分散トピック

アプリケーションが分散トピックのメンバーに直接送信を行う場合、物理的トピック間のメッセージのルーティングが、順序単位に影響を与える可能性があります。処理の順序が正しくなるようにするには、メッセージが論理分散トピックを介して送信される(つまり、宛先が分散トピックのJNDI名を使用して取得される)ことをアプリケーションで保証する必要があります。その結果、WebLogic Serverでは、同じ順序単位を持つメッセージであれば、その分散トピック・メンバーへのパスが同じであることが保証されます。

順序単位、トピック、およびメッセージドリブンBean

WebLogic ServerメッセージドリブンBeanの実装は、単一のトピック・サブスクリプションおよびJMSセッションの着信メッセージ・ストリームの並行処理を可能にするため、EJBおよびJMS仕様の要件に準拠していません。この並行処理では、非トランザクションの場合、デフォルトでは順序単位は考慮されないため、正しい処理順序が確保されるように配慮する必要があります。

トピックおよび非トランザクション・メッセージドリブンBeanで順序単位を使用する場合は、UOO順序付け規定が確実に適用されるように、次の1つまたは複数を適用します:

  • 非デフォルトのメッセージ配信ポリシーの使用: トピックのメッセージ配信ポリシーを「サーバーごとに1コピー」または「アプリケーションごとに1コピー」のいずれかに設定します。『Oracle WebLogic ServerメッセージドリブンBeanの開発』メッセージ分散チューニングの設定に関する項を参照してください。

  • コンテナ管理トランザクションの有効化: 『Oracle WebLogic ServerメッセージドリブンBeanの開発』「MDBのトランザクション管理戦略の構成」を参照してください。パフォーマンスが懸念される場合は、追加でトランザクションのバッチ処理を有効化することを検討してください。そのようにすることで、パフォーマンスの影響が軽減され、一般的に、非トランザクションの場合よりパフォーマンスが向上する可能性があります。『Oracle WebLogic Serverのパフォーマンスのチューニング』トランザクションのバッチ処理の使用に関する項を参照してください。

  • プール・サイズを1に設定: プール・サイズを1に設定すると、並列性に重大な影響がもたらされます。『Oracle WebLogic ServerメッセージドリブンBeanの開発』「MDBのデプロイメント要素とアノテーション」で、max-beans-in-free-pool要素の説明を参照してください。

JMSメッセージ管理で順序単位を使用する

JMSメッセージ管理を使用すると、JMSの管理者は実行中のJMSサーバー内のほとんどのメッセージを移動したり削除したりできます。つまり、管理者は「順序単位によるメッセージ配信」に示した配信規則を侵害することが可能です。

たとえば、順序単位fooに属すメッセージA、B、C、およびDが生成されて宛先D1に送信された場合、以下の点に留意してください。

  • メッセージCおよびDを宛先D2に移動すると、両方の宛先からのメッセージが並行して処理される可能性があります。

  • メッセージBおよびCを宛先D2に移動すると、メッセージAとメッセージBおよびCが並行して処理される可能性があります。メッセージAが処理された後に、メッセージDが配信可能になります。

メッセージ順序の維持に依存するアプリケーションでは、1つの順序単位内のすべてのメッセージを単一のグループとして移動するのがベスト・プラクティスです。

順序単位の配信規則が維持されるようにするには、次のステップを使用します:

  1. ソース宛先とターゲット宛先を休止させます。

  2. 移動する順序単位内のすべてのメッセージを選択します。

  3. 選択したメッセージをターゲット宛先に移動します。必要に応じて、メッセージを処理したい順序にソートします。

  4. ソース宛先とターゲット宛先を再開します。

詳細は、『Oracle WebLogic Server JMSリソースの管理』WebLogic JMSのトラブルシューティングに関する項を参照してください。

WebLogicストア・アンド・フォワードで順序単位を使用する

WebLogicストア・アンド・フォワードでは、メッセージ順序単位がサポートされます。たとえば、Fooという順序単位のメッセージを送信するストア・アンド・フォワード・プロデューサがあるとします。このプロデューサは、切断して別の接続で再接続すると、Fooという順序単位を作成してメッセージの送信を継続します。再接続の前と後に送信されたすべてのメッセージは、同じストア・アンド・フォワード・エージェントを介して転送されます。『Oracle WebLogic Serverストア・アンド・フォワード・サービスの管理』を参照してください。

WebLogicメッセージング・ブリッジで順序単位を使用する

ソース宛先とターゲット宛先の両方がWebLogic Server 9.0以降のメッセージング・ブリッジ・インスタンスである場合は、メッセージング・ブリッジのPreserveMsgPropertyを有効にすると、順序単位名を維持してプロデューサの順序単位を設定できます。『Oracle WebLogic Server WebLogic Tuxedo Connectorの管理』を参照してください。

メッセージ順序単位の制限事項

メッセージ順序単位を使用する際の制限事項について説明します。

  • ブラウザの列挙値には、現在のキュー・メッセージがブラウザによって受信されるべき順序で格納されます。ここでいう「現在」とは、配信可能になっているメッセージを指します。通常は、順序単位内の最初のメッセージが配信可能になっています。同じ順序単位内の後続のメッセージは配信可能にはなっていません。

  • 順序単位機能の組み合わせによっては、競合する順序単位メッセージ・ストリームが不足することがあります。これには、順序単位名が異なる処理中メッセージの数よりコンシューマの数が多くなったために、リソースが十分に利用されなくなった場合も含まれます。システムのパフォーマンスを最適化し、リソースが十分に利用されない状態を防ぐには、最大の負荷でアプリケーションをテストする必要があります。

  • このリリースのWebLogic Serverメッセージ順序単位では、順序単位非対応のJMSプロバイダ(WebLogic 9.0より前のリリースやWebLogic以外のJMSプロバイダ)に接続されているクライアントはサポートされません。