Windows Communication Foundation を使用した Reliable Messaging の概要

 

Clemens Vasters
Microsoft Corporation

2006 年 7 月

適用対象:
   Microsoft Windows Vista
   WS-ReliableMessaging仕様

概要: この記事では、Clemens Vasters で、信頼性の高いメッセージングとセッションのサポートが Windows Communication Foundation (WCF) とどのように連携するかについて説明します。 WS-ReliableMessaging仕様の WCF 実装、信頼できる配信とセッションが関連する方法と理由、WCF 標準バインディングが信頼できるメッセージングをサポートするかどうか、およびどの程度までについて学習します。 (14ページ印刷)

内容

(WS-) Reliable Messaging のしくみ
信頼できるメッセージング (およびセッション)
標準バインディングを使用した信頼性の高いメッセージング
要求の厳しい信頼性の高いセッション サポート
一方向、キュー、永続メッセージング

信頼性の高いメッセージングは、データの堅牢で同時処理を可能にし、スケーラビリティを大幅に向上させる強力なソフトウェア アーキテクチャを実装するための重要なイネーブラーです。 さらに、信頼できるメッセージングは、接続を取得する機会が日に日に増えるが、ネットワーク接続の品質はほとんど許容できないから非常に貧しい場所に多くの場合、世界でアプリケーションを作成するための基盤です。

ビッグ ワード。 本当でしょうか? どうしてそうなんですか。

ドイツのフランクフルトとケルンの間の新しいインターシティエクスプレス鉄道は、ライン川の東岸沿いの丘の上に掘られ、高架化され、ヨーロッパで最も重要な水路と並んで豪華な美しいルートの代わりに建設されました。 新しいトラックは30マイル短く、移動時間を1時間短縮し、18の主要な高架橋と30の新しいトンネルを備えています。 しかし、この新しいトラックは、2003年以来のみ運用されており、その点ではまだ例外的です。

モバイル 従業員が使用するスマート クライアント アプリケーションは、社内のデスクトップ アプリケーションと比較して通信要件が非常に異なります。 ユーザーは、GSM/GPRS、3G/UMTS、WiFi 接続などのモバイル データ サービス経由で中継される VPN リンクを介して企業ネットワークにダイヤルインします。多くの場合、"モバイル" は"移動" と真に同義です。また、優れた通信インフラストラクチャを備えたドイツでも、電車や車での接続性の品質は、多くの場合、風景に依存しています。ドイツの鉄道システムやドイツの通りには多くのトンネルがあり、そのうちのいくつか以上がモバイルリンクを崩壊させます。 バックエンド システムから情報をフェッチしてバックエンド システムに送信する必要があるモバイル接続アプリケーションを構築する場合、これらの実際の接続の制約は大きな課題です。 アプリケーションが単純な HTTP で "基本的な" Web サービスを使用していて、通信リンクが非常に現実的に数秒ドロップする可能性がある場合、アプリケーションのユーザーが過去 30 分間にクライアント アプリケーションに入力したデータがバックエンド システムによって実際に理解され、保存されたかどうかを判断するのは簡単ではありません。 また、ネットワーク障害の状態が見つかる場合は、いつどのように再試行しますか? さらに悪いことに、一貫して特定の順序で情報のバッチを中継する必要があり、通信リンクが断続的に失敗した場合、どうしますか?

モバイル アプリケーションでの "時折の接続" は、Web サービスでの信頼性の高いメッセージングの推進力の 1 つです。 もう 1 つは、インターネット上の任意の場所で発生するネットワークの混雑が非常に単純です。

多くの人が、HTTP ベースの Web サービスのオープン性、プラットフォームの独立性、ユビキタスを必要としますが、HTTP のトランスポート信頼性の本質的な欠如は、説明されているようなシナリオでは非常に問題になります。 標準化のために OASIS に送信され、Windows Communication Foundation によって実装されているトランスポートに依存しないWS-ReliableMessaging (または WS-RM) プロトコルを使用すると、信頼性の低い接続とプロトコルに対して信頼性の高い通信パスを作成できます。 これは、エンドツーエンドの通信セッションを確立し、メッセージの明示的な受信確認を通信フローに導入することによって行われます。

(WS-) Reliable Messaging のしくみ

Windows Communication Foundation は、アプリケーション開発者にWS-ReliableMessaging仕様のすべての複雑な詳細を便利に隠し、信頼性の高いメッセージングの実装をサービスおよびサービス クライアントの適切なバインド構成を選択するだけで済みますが、背後やネットワーク上で何が起こっているかを少し考えると便利です。

結局のところ、あなたは本当にあなたが完全に理解しているメカニズムを信頼することができますね?

信頼できるメッセージングは一般的に次のように機能します。クライアントは、通信リンクを介して一連のメッセージ (シーケンスが 1 つのメッセージと同じ短さになる可能性があります) を送信し、受信者にメッセージを受信したことを確認するように求めます。

受信確認は、メッセージごとに個別に、または一連のメッセージに対して 1 回の受信確認でクライアントに送り返されます。 クライアントは、受信確認を受信すると、メッセージが正常に転送されたことを認識します。

TCP (TCP/IP のように伝送制御プロトコル) は受信確認メッセージと連携して、シーケンスのすべてのデータ パケットが 2 つのエンドポイント間で確実に転送されるようにします。 WS-ReliableMessagingは、通信スタック上で少し上がり、基になるトランスポートから独立して、非常に同じように動作します。 具体的には、WS-RM は、これらのエンドポイントの接続方法に関係なく、2 つのエンドポイント間で単一の SOAP メッセージまたは SOAP メッセージのシーケンスの信頼できる配信を制御するように設計されています。たとえば、メッセージがホップごとに異なるトランスポート プロトコルを使用してメッセージ ルーターやその他の中継局を通過する場合でも。

2 つのエンドポイント間で信頼できるメッセージング リンクを確立するには、まず接続または "セッション" という概念が必要です。 そのセッションのコンテキストで送信された各メッセージには、シーケンス内の順序を示す一意の番号が割り当てられます。 送信側 (または "イニシエーター") は、送信されたメッセージを追跡し、受信確認と一致させる一時キャッシュを確立します。 特定の時間 ("再試行タイムアウト") 後にメッセージが確認されない場合、メッセージはキャッシュから自動的に再送信されます。 受信確認を受信すると、メッセージをキャッシュから削除できます。

受信側 (または "アクセプター") は、アプリケーションに配信する前にメッセージを格納するために、受け入れたメッセージを保持するためのキャッシュを確立します。 これは、受信インフラストラクチャとアプリケーションに "プルリレーションシップ" がある可能性があるためです。

WS-RM チャネルがトランスポート チャネルの上に積み重ねられ、場合によってはセキュリティ チャネルなどの追加チャネルが追加される WCF のチャネル アーキテクチャを詳しく説明します。到着したメッセージは、受信時にトランスポート チャネルでキューに入れられます。

したがって、これは実際に、それがどのように機能するかについての簡単な説明です。ワーカー スレッドがメッセージを処理できるようになるたびに、サービス モデルはそのトランスポート キューからチャネル スタックを通じてメッセージをプルし (各チャネルは基になるチャネルからプルします)、作成するサービスにメッセージをディスパッチします。 すべてのメッセージが、書き込むサービスにすぐに同期的にプッシュされているように見えるかもしれませんが、実際には常にこのようなプルプッシュ変換が行われます。

サービスのビジー状態に応じて、メッセージの到着とメッセージディスパッチの間に遅延が生じる可能性があるため、RM チャネルは到着したメッセージの承認をかなり迅速に行う必要があるため、RM チャネルは、メッセージがトランスポートからサービス モデルにバブルアップする際に、メッセージのフローを待機しません。 代わりに、基になるトランスポート キューから事前にプルし、必要な受信確認を送信し (可能な場合は後で受信します)、サービス モデル レイヤーによる受け取りのためにメッセージを独自のキューに保持します。

このキャッシュ (またはキュー) は、受信したメッセージを一時的に非順序で保持して、メッセージが送信された順序でアプリケーションに配信されるようにすることもできます。 シーケンスのメッセージ 3 と 4 がメッセージ 2 の前に到着した場合、これらの "後の" メッセージは、メッセージ 2 が到着するまでキャッシュに保持されるため、シーケンスが適切な順序になったらアプリケーションにのみ配信されます。 これは、アプリケーションで順序指定された配信が必要で、メッセージ注文の適用が有効になっている場合に発生します (これが既定の動作です)。

順序指定された配信のサポートに加えて、メッセージ番号を使用すると、受信側は重複するメッセージを検出して破棄できます。 メッセージは、送信者から受信側へのパスで複製することも、受信確認が失われたり遅延したりした場合は送信者側から 2 回送信することもできます。

通信パスの両端は両方の役割を果たすことができるため、"client" と "server" の代わりに "イニシエーター" と "acceptor" という用語が使用されることに注意してください。 "クライアント" と "サーバー" の用語は、双方向通信について考え始めると、わかりにくくなります。

要求/応答通信パターンがあると仮定した場合、応答は要求と同じように確実に配信される必要があるため、応答側は、要求元の要求に対して要求側が実装するのと非常によく似たイニシエーター メカニズムを実装する必要があります。 要求側は、応答の受け入れ側の役割を果たします。 応答が失われた場合は、応答側から再送信する必要があるため、キャッシュ (および確認済み) も行う必要があります。 したがって、信頼できるメッセージング セッションの両端は、送信メッセージと受信メッセージ用に個別のキャッシュを保持します。

通信相手が双方向 (デュアル) 通信リンクを持っている場合、応答側は、要求を配信できない場合に要求側が送信を再試行するのと同じように、単にメッセージの送信を再試行できます。

ただし、通信リンクで応答側がクライアント要求とは無関係にメッセージを配信できない場合は、もう少し複雑になります。 具体的には、応答側が別の要求を受け取ったときに、応答側が要求側に何かを返す機会しかない HTTP の場合です。

HTTP を使用するときに要求側が強制的に応答を受け取り、未確認の応答を取得するために、応答側は単純なトリックを使用します。要求メッセージの受信確認は、常に応答でピギーバックされます。 そのため、応答が失われた場合、元の要求が実際に応答側に到着し、要求が既に処理されている可能性がある場合でも、要求側は確認を受け取らず、要求を再送信します。 応答側は、メッセージのシーケンス番号を調べることでこのような再送信要求を検出し、メッセージを再処理する代わりに、メッセージ キャッシュからの元の要求に起因するキャッシュされた応答を処理します。

受信した応答の受信確認は、同じ信頼できるセッションで行われた後続の要求でピギーバックされるため、応答側は応答キャッシュをクリーンできます。 応答確認を行う要求は、それによって完全に無関係です。そのメッセージは、単に川に沿って渡って渡る次の便利なフェリーボートとして機能します。

WS-ReliableMessaging セッションのスコープは "シーケンス" と呼ばれ、通信エンドポイント間で帯域外で送信される "CreateSequence" Web サービス要求によって確立されます。 帯域外とは、この特定の要求がインフラストラクチャによって送信および処理され、サービス モデル レベルのどこにも Web サービス呼び出しとして表示されないことを意味します。 シーケンスを開始するパーティが作業を行い、未処理のすべての受信確認を収集すると、チャネルが閉じられると、"TerminateSequence" 要求 (帯域外および "バックグラウンド" も送信されます) が送信されます。

実際にチャネル アーキテクチャの下を突っ込む場合は、"CreateSequence" 要求を受信すると、新しいチャネルが使用可能になり、それぞれのシーケンスのすべてのメッセージが配信されることがわかります。 "TerminateSequence" メッセージは、受信者に null メッセージを配信することによって、そのチャネルにシーケンスの末尾を示します。

信頼できるメッセージング (およびセッション)

ここまでの説明では、Windows Communication Foundation が "reliable session" という名前のバインド要素 (具体的には ReliableSessionBindingElement クラスと reliableSession 構成セクション) を通じてサポートを WS-ReliableMessaging提供し、セッションのサポートと信頼性の高いメッセージング サポートが手をつないで行くことはあまり驚くべきことではありません。

また、信頼できるメッセージングでは受信確認を中継するために双方向の情報フローが必要であるため、UDP (WCF では直接サポートされていませんが、トランスポート チャネル サンプルが WinFX SDK に存在する) や Microsoft メッセージ キュー (MSMQ) などの一方向データグラム トランスポートとは互換性がありません。これにより、後者は、この記事の最後に進んで説明する信頼性の高いトランスポート オプションが若干異なります。

<customBinding>
   <binding configurationName="customReliableHttpBinding">
      <textMessageEncoding messageVersion="Default" encoding="utf-8" />
      <httpTransport />
   </binding>
<customBinding>

上記のバインド構成スニペットは、HTTP トランスポートをサポートし、既定の (SOAP 1.2 および 2004 年 10 月時点のWS-Addressing) メッセージ形式バージョンを使用して UTF-8 テキストとしてメッセージをエンコードする、非常に単純なカスタム バインドです。

このバインディングに信頼性の高いメッセージング サポートを追加することは、別のバインド要素 (下線付き) を追加するのと同じくらい簡単です。

<customBinding>
   <binding configurationName="customReliableHttpBinding">
      <reliableSession ordered="true" />
      <textMessageEncoding messageVersion="Default" encoding="utf-8" />
      <httpTransport />
   </binding>
</customBinding>

構成とコードで追加オプションを構成する方法を示すためだけに (以下を参照)、ここで追加するバインド要素では、順序付けされたメッセージ配信も明示的に必要です。これは既定でオンになっています。 コード内の同等のバインド構成は次のようになります。

// create and configure transport
HttpTransportBindingElement httpTransport = 
      new HttpTransportBindingElement();

// create and configure encoder
TextMessageEncodingBindingElement textMessageEncoding = 
      new TextMessageEncodingBindingElement();
textMessageEncoding.Encoding = System.Text.Encoding.UTF8;
textMessageEncoding.MessageVersion = MessageVersion.Default;

// create and configure reliable session
ReliableSessionBindingElement reliableSession = 
      new ReliableSessionBindingElement();
reliableSession.Ordered = true;

// compose into binding
CustomBinding reliableHttpBinding = 
      new CustomBinding(
            reliableSession,
            textMessageEncoding,
            httpTransport);

バインディング要素が存在する場合、WCF は、サービスの ServiceHost が開かれてエンドポイントにバインドされると、信頼できるセッション リスナー インフラストラクチャを HTTP トランスポート リスナーの上にスタックします。 同様に、 ChannelFactory を開いてリモート エンドポイント アドレスにバインドすると、クライアント側の HTTP トランスポート チャネルの上に信頼性の高いセッション チャネル インフラストラクチャがスタックされます。 ProxyBaseProxyBase<T> は、 ChannelFactory と生成されたクライアント チャネルの作成、構成、および開きに関する便利なラッパーにすぎません。

Aa480191.introtowcfreliablemessaging1(en-us,MSDN.10).gif

図 1. WCF での信頼できるセッションの確立

この非常に簡略化された図は、WCF で信頼性の高いセッションがどのように確立されるかを示しています。 最初のアプリケーション レベル のメッセージ (1) がプロキシを介して送信されるか、または信頼できるセッションが有効なバインドを使用してトランスポート アドレスにバインドされた型指定されたチャネルまたは型指定されていないチャネルが送信されるたびに、メッセージは信頼できるセッション出力チャネルを経由します。

最初はセッションがないため、送信側 (1a) に新しいセッションが作成され、セッション オブジェクト自体が (2,3) 帯域外メッセージ "CreateSequence" をリモート エンドポイントに送信します。 リモート エンドポイントでは、メッセージはトランスポート リスナーによって受け入れられ、新しいトランスポート チャネルが確立されます。 その後、メッセージは (5) 信頼できるセッション リスナーに転送されます。 新しいセッション (5a) を作成して処理された要求と、適切な応答 (7) が要求元に送信され、そこでセッション オブジェクト (8) にディスパッチされ、シーケンス作成ラウンドトリップが完了します。 その後 (9)、アプリケーション メッセージは、リモート エンドポイントに送信される出力トランスポート (10) に転送されます。 リモート エンドポイントでは、メッセージはセッションに関連付けられた入力チャネルによって処理され、(11) を信頼できるセッション入力チャネルに転送し、最後にサービス インスタンスにディスパッチ (12) します。 その後、サービス インスタンスの可能な応答は、信頼できるセッション出力チャネル (13) と応答側のトランスポート出力チャネル (14) を走査し、リクエスター (15) でトランスポート入力チャネルに送信され、信頼できるセッション入力チャネル (16) にバブルアップし、最後にプロキシ (17) に到達します。

転送確認 ("acks") を送信する方法は、トランスポート チャネルの特定の選択によって異なります。 トランスポート チャネルが "デュアル" の場合、メッセージ トラフィックを双方向に中継するために 2 つのエンドポイント間に双方向トランスポート接続があることを意味し、受信確認は特定のメッセージを介して帯域外で送信され、通常はバッチで送信されます。 トランスポート チャネルが要求/応答の種類の場合、次のメッセージ (応答に対する要求の確認、要求に対する応答の確認) で受信確認がピギーバックされます。

セッションと HTTP

コネクションレス HTTP トランスポート バインドの場合、信頼できるセッション バインド要素は、サービス コントラクトのセッション サポートを追加するための所定の方法です。

HTTP はコネクションレスであり、要求は 1 つのパーティによってのみ開始されるため、通常、論理接続 (つまりセッション) は、各要求と応答と共に通信側間で共有される参照トークン (Cookie) を使用して構築されます。

HTTP レベルで必要なメカニズムは、コア HTTP 仕様 RFC2616 ではなく RFC2965 で説明されており、両当事者がサポートすることは厳密に省略可能です。 このような Cookie ベースのセッションを一連の呼び出しに対して Web メソッドごとに有効にできる ASP.NET Web サービスとは異なり、WCF では、現時点では HttpTransportBindingElement の構成スイッチを通じてエンドポイントごとにのみこの動作がサポートされます。

Cookie ベースのセッションサポートを有効にするには、構成またはコードでカスタム バインドを構築し、 AllowCookies プロパティまたは同等の allowCookies 構成属性を true に設定する必要があります。 ベータ 2 に続くコミュニティ テクノロジ プレビュー (CTP) と最終的な WCF 製品では、このオプションは標準の BasicHttpBindingWSHttpBinding のコードと構成のバインドでも簡単にアクセスでき、このようなカスタム バインドを構築する必要がなくなります。

ただし、HTTP ベースの Web サービスに Cookie ベースのセッションを使用しない理由は多数あります。

  • 両方の当事者は常に(RFC2965に従って正当に)クッキーを削除することによってクッキーベースのセッションメカニズムをオプトアウトすることができ、したがってメカニズムはあまり信頼できない
  • WSDL または WS-Policy を使用して、サービスがクライアントへの Cookie ベースのセッション サポートの要件を表現するための標準的な方法はありません。
  • HTTP レベルの Cookie は、メッセージ ヘッダーのようにデジタル署名することはできません (SSL が使用されている場合を除き、常にオプションであるとは限りません)。そのため、セキュリティ上の脅威が発生する可能性があるため、セッションが盗まれ、サード パーティによってなりすましを受ける可能性があります。

例として、次の仮想的なセッション対応コントラクトを考えてみましょう。これにより、複数のローンを含む融資パッケージのサーバー側の構成が可能になり、全体的な平均利息、手数料、月払いの組み合わせなどの状態が取得され、最後に構成されたパッケージが銀行の内部ローン申請処理に送信されます。

[ServiceContract(Session = true)]
public interface IFinancingPackageBuilder
{
   [OperationContract(IsInitiating=true)]
   LoanId AddLoan(LoanInfo loanInfo);
   [OperationContract(OneWay=true,IsInitiating = false)]
   void RemoveLoan(LoanId loanId);
   [OperationContract(IsInitiating = false)]
   PackageStatusInfo GetFinancePackageStatus();
   [OperationContract(OneWay=true,IsTerminating = true)]
   void SubmitApplication(PersonalInfo personalInfo); 
}

上記のサービス コントラクトの例から派生できるように、セッションサポートが必要なサービスは 、べき等ではないアクションを持つ可能性があるため、信頼できるメッセージ配信の利点をすぐに得られるのは非常に一般的です。

"べき等" とは、同じアクションを 1 回または 2 回、または任意の回数呼び出すかどうかに関係なく、サービスの結果の状態が同じであることを意味します。

これは、サービス状態との間でデータを増分的に追加および削除する、上記の AddLoan 操作または RemoveLoan 操作では必ずしも当てはまらない。 べき等でないアクションは、メッセージの損失や重複の場合にかなりの頭痛を引き起こす可能性があります。 そのため、セッションと信頼性の高いメッセージングを組み合わせることは、前に説明したようにインフラストラクチャ レベルで技術的な推論を行うだけでなく、アプリケーション レベルでも多くのアーキテクチャ上の意味を持ちます。

HTTP とは対照的に、接続指向の TCP トランスポートと名前付きパイプ トランスポートは本質的にセッションをサポートします。 どちらの場合も、エンドポイント間で接続が維持されている限り、暗黙的なセッションが自動的に存在します。 信頼できるセッション メカニズムを使用してトランスポートに依存しない信頼性を追加することは、多くの場合役立ちますが、HTTP と同様にセッションサポートには必要ありません。

これらのトランスポート固有のセッション機能の上に信頼できるセッションを使用するメインの利点は、ルーティング シナリオでのエンドツーエンドの信頼できるメッセージ配信と、一時的な接続エラーに対する回復性の向上です。

Reliable Messaging Session Options

信頼できるセッション バインド要素とその基になるインフラストラクチャには、次の表に示すいくつかの構成プロパティがあります。 これらの各設定は、構成された通信エンドポイントのローカル動作にのみ影響します。つまり、要求/応答通信のクライアントには、それぞれのサービス側とは異なる設定が存在する可能性があります。

記載されているすべての既定値はベータ 2 の準備段階であり、最終製品で変更される可能性があることに注意してください。

プロパティ 説明
AcknowledgementInterval
(TimeSpan)
受信者がメッセージの受信確認を送信するまで待機する間隔。 既定は 2 秒です。 構成された間隔の期間内に受信されたメッセージは、ネットワーク トラフィックを減らすことを目的として、1 つのバッチで確認されます。 セッションの最初のメッセージは常にすぐに確認されます。 この設定は、ハード制限ではなく、インフラストラクチャに対する推奨事項です。

注: この設定は双方向双方向トランスポート バインドにのみ適用され、各要求メッセージがそれぞれの応答で確認され、応答が次の要求で確認される要求/応答スタイル バインドには影響しません。

EnableFlowControl
(Boolean)
フロー制御機能をオンまたはオフにします (この機能は既定でオンになっています)。 この機能は、受信メッセージの受信側バッファーがいっぱいになったときにメッセージの送信を停止することで、送信者がネットワーク リソースを無駄にしないようにするのに役立ちます。 バッファーがいっぱいになったときに送信されるメッセージは破棄され、再送信が必要になるため、これらのメッセージを送信しないようにすると、ネットワーク リソースが節約されます。 このネットワーク リソースの最適化された使用は、受信側のバッファーで使用可能な容量を送信者に報告することで有効になります。これにより、バッファーがいっぱいの場合、送信者はメッセージを送信しません。
MaxTransferWindowSize
(Int32)
この値は、信頼できる各セッションのローカル メッセージ バッファーに保持できるメッセージの数を指定します。 送信側では、このバッファーはまだ受信確認されていないメッセージを保持し、受信側では、このバッファーはアプリケーションによってまだ処理されていないメッセージを保持します。 この値の既定値は 32、最小値は 1、最大値は 4096 です。 送信側バッファー・サイズがセッションで構成された制限を超えると、送信側はブロックされます。 受信側バッファー・サイズがセッションの上限を超えると、受信メッセージはドロップされます。
InactivityTimeout
(TimeSpan)
非アクティブ タイムアウト (既定値は 10 分) は、相手側からメッセージを受信せずに経過する可能性がある時間の長さを定義します (アプリケーション メッセージ、受信確認、またはその他のインフラストラクチャ メッセージなど)。 アプリケーション レベルのメッセージが送信されていない場合、インフラストラクチャは接続がまだ有効であることを確認するために"キープアライブ" メッセージの送信を開始します。 その制限時間内にメッセージが受信されない場合、セッションエラーが発生します。
MaxPendingChannels
(Int32)
この設定では、新しいクライアント開始セッションに対する保留中の要求を "保留中のチャネル" リストに保持する数を制御します。 クライアントが新しいセッションを確立しようとするたびに、チャネルはサービス側で作成され、セッションを確立するために信頼できるセッション リスナーによって受け入れられ、開かれる必要があります。 負荷の下で、インフラストラクチャが処理できるよりも多くの新しいセッションの要求が積み重なっている可能性があります。

保留中の、まだ受け取られていないチャネルの既定値は 128 です。 このしきい値に達すると、受信側インフラストラクチャは新しいセッションの要求を拒否します。

MaxRetryCount
(Int32)
この値は、既定値は 8 (最小 1、最大 20) で、送信エラーが発生した場合にインフラストラクチャがメッセージの再送信を再試行する回数を指定します。 構成された再試行回数に対してメッセージが正常に再送信されなかった場合、エラーは回復不能と見なされ、チャネルに障害が発生します。
注文済み
(Boolean)
この構成プロパティが true に設定されている場合 (既定ではそうです)、受信側インフラストラクチャは、送信された正確な順序ですべてのメッセージをディスパッチします。 メッセージが順に到着した場合、シーケンスの欠落メッセージが到着するまでバッファーされます。 これが false に設定されている場合、メッセージは送信された順序に関係なく、すぐにサービスにディスパッチされます。

この構成プロパティの一覧について本当に驚くべきことは、再試行回数 (MaxRetryCount) は構成可能ですが、再試行が試行される間隔が構成可能な値の一覧に表示されないということです。

これは、WCF が単純な再試行タイムアウトをはるかに超える信頼性の高い送信操作に高度な輻輳制御アルゴリズムを適用するためです。 ここで使用するアルゴリズムは、ほとんどの TCP 実装で採用されている実証済みの輻輳制御メカニズムに似ています。 一般に、再試行タイムアウト値は最初はかなり寛大であり、送信者が追加のメッセージを送信し続けている間、未確認のままで残すことができるメッセージの数は、通常は 1 から非常に少なくなっています。 通信パスが迅速で信頼性が高く、メッセージの損失が発生しない場合、タイムアウトが短縮され、送信者は確認されていないメッセージの数が増えるのを許容し、最終的に攻撃が発生することを期待します。 メッセージの損失が発生した場合、タイムアウトが短いほど再送信が速くなります。 より優れた受信確認を許可すると、スループットが向上します。 通信パスの品質が低下し、非常に低速になったり、場合によっては切断されたりした場合、アルゴリズムによってタイムアウトが指数関数的に増加し、許容される受信確認の数が大幅に減り、スループットが調整され、障害許容度が向上します。

標準バインディングを使用した信頼性の高いメッセージング

WCF の標準バインディングがセッションと信頼できるメッセージングをサポートするかどうかと方法は、基になるトランスポート固有の機能と、その機能をサポートするためにバインディングによって信頼できるメッセージングが暗黙的に必要かどうかに大きく依存します。

バインド WS-RM のサポート セッション サポート
BasicHttpBinding なし いいえ
WSHttpBinding はい。バインド要素または構成で ReliableSession.Enabled プロパティが true に設定されている場合。 RM が有効な場合ははい。
WSDualHttpBinding Always、Implicit はい、暗黙的
NetTcpBinding はい。バインド要素または構成で ReliableSession.Enabled プロパティが true に設定されている場合 はい、暗黙的
NetNamedPipeBinding なし、基になるトランスポートによって保証される信頼性の高い配信 はい、暗黙的
NetMsmqBinding なし、基になるトランスポートによって保証される信頼性の高い配信 トランザクション キューが使用されている場合ははい。
MsmqIntegrationBinding なし、基になるトランスポートによって保証される信頼性の高い配信 いいえ

BasicHttpBinding では、基本的な WS-Security プロファイルを除き、WS-* ヘッダーはサポートされず、単純な HTTP ベースの SOAP メッセージングのみをサポートすることを目的としています。 そのため、このバインディングで信頼できるメッセージングとセッションを有効にすることはできません。

WSHttpBindingNetTcpBinding は、送信者から受信者にメッセージ (および場合によっては応答) を要求する WS-* 対応バインディングです。 どちらのバインドでも、 ReliableSession.Enabled 構成プロパティを true に設定することで、信頼できるメッセージングを有効にすることができます。

セッションは、接続指向 の NetTcpBinding の基になるトランスポートによって暗黙的にサポートされ、この設定には依存しませんが、 WSHttpBinding でのセッションサポートには信頼できるセッションを有効にする必要があります。

2 つの HTTP エンドポイント間の双方向の会話リンクを確立する明示的な二重バインディング WSDualHttpBinding では、信頼できるメッセージングとセッションが機能する必要があります。 したがって、RM は暗黙的に、このバインディングに対して常に有効になります。

前述の信頼できるセッション対応バインディングでは、メッセージの順序は常に適用されます。つまり、メッセージは送信された正確な順序で受信サービスに配信されます。 これをオフにする可能性が低い場合は、前述のようにカスタム バインディングを作成し、ReliableSessionBindingElementOrdered プロパティ (または同等の構成属性) でこのメカニズムを無効にする必要があります。

NetNamedPipeBinding は、名前付きパイプを介した信頼性の高いメッセージ配信と信頼できるストリームに対する Windows オペレーティング システムのサポートの上に配置されます。 名前付きパイプは接続指向であり、セッションを容易にサポートし、設計上信頼性が高く、通常はブリッジされないため、このバインディングでは WS-RM サポートは必要ありません。

Microsoft Message Queue (MSMQ) は、信頼性の高いメッセージ配信を実装するために WS-RM サポートを必要としないオペレーティング システム レベルの信頼できるトランスポートです。 代わりに、 NetMsmqBinding には、MSMQ がメッセージの配信に提供できるトランスポート保証を反映した特別な構成プロパティのセットがあります。

MSMQ は厳密には一方向トランスポートですが、トランザクションサポートを通じてセッションもサポートします。 基になるキューがトランザクションであり、一連のメッセージがトランザクション スコープ内から受信者サービスに送信されると、トランザクション内でキューに登録されたすべてのメッセージがセッション スコープ内の受信者サービスに配信されます。 トランザクション メッセージ バッチからの最後のメッセージが配信されると、セッションは閉じられます。

要求の厳しい信頼性の高いセッション サポート

アプリケーションのコーディング時に、信頼性の高いメッセージングとセッション サポートの可用性に基づいていくつかの想定を行う場合があります。 これにより、これらの機能がアプリケーションの適切な機能にインストルメント化され、適切なバインドを選択して構成することは純粋に問題です。 これにより、アプリケーションの適切な機能は、システムを構成しているユーザーのなすがままになり、診断とデバッグが非常に困難な問題につながる可能性があります。

適切な機能が信頼できるメッセージングに依存し、特にメッセージの順序付き配信に依存するサービスが必要に応じて動作することを確認するには、 DeliveryRequirementsAttribute を使用して、アプリケーション コードで使用されるバインディングから順序付けられた配信サポートを明示的に要求できます。

[DeliveryRequirements(RequireOrderedDelivery=true)]
public class FinancingPackageBuilder : IFinancingPackageBuilder
{
   ...
}

構成されたバインディングでこの属性に必要な機能がサポートされていない場合、サービス ホストはサービスのホストを拒否し、例外をスローします。 バインディングからの要求の厳しいセッションサポートは、コントラクト宣言の ServiceContractAttribute でセッション要件を宣言することによって暗黙的に行われます。

[ServiceContract(Session = true)]
public interface IFinancingPackageBuilder
{
...
}   

一方向、キュー、持続性のあるメッセージング

"信頼性の高いメッセージングは、データの堅牢な同時処理を可能にし、スケーラビリティを大幅に向上させる強力なソフトウェア アーキテクチャを実装するための重要なイネーブラーです。"これはこの記事の最初の文の 1 つですが、牛はどこにありますか?

信頼性の高い配信サポートが WS-RM で実装されているか、トランスポートに固有であるかに関係なく、テクノロジの一部として選択したトランスポートで信頼性の高いメッセージ配信を一貫して利用できるようになったら、必要なプラミング コードの複雑さまたはコストが原因で、WCF の前にほとんどのソフトウェア開発者に手の届かない実装パターンを使用する、より強力なアプリケーションを構築できます。 以前はこのようなことができなかったのではなく、顧客にビジネス機能を実装することが主な関心事である人にとっては非常に困難でした。

"金額に相当する" ドキュメントを準備してバックエンド アプリケーションに送信するクライアント アプリケーションを作成するとします。 これは、発注書、会計記録、または誰かの旅行の払い戻しのファイリングです。 通常、ロジックはこのようなレコードを準備し、一貫性を保つよう検証してから、バックエンド システムに送信してさらに処理します。 また、非常に一般的に、アプリケーションは、処理チェーンの一部を準備した後に "完了" され、処理の結果に関する通知は、はるかに後で、おそらく電子メールの方法によって異なるチャネルを介してのみあなたに戻ります。

信頼性の高いメッセージングを使用すると、クライアント アプリケーションは、主にネットワークの状態に関係なく、送信先にメッセージを取得するインフラストラクチャを委託できます。 これを送信するジョブのローカルの送信側の永続キューと組み合わせると ("Queue" は MSMQ と同義ではありません。MSMQ がすぐにサポートされているのは WCF だけです。独自のキュー チャネルを作成する場合は、ローカル SQL サービス インスタンスがこれとファイル システムに適しています。 分離ストレージを含め、優れている場合もあります)。信頼性の高いメッセージング接続が永続的に失敗したり、アプリケーションやコンピューターがクラッシュしたりするまれなケースでも、合理的に安全です。 受信側では、キューはメッセージ転送を処理から切り離すのに最適です。 最後に "安全" というメッセージが表示されたら、ジョブをローカルの永続キューに格納し、そのキューから実際の処理を読み取ることができます。 WCF の NetMsmqBinding for MSMQ ではこれを行います。ただし、他のすべてのバインディングでは、このような機能 ("永続的なメッセージング") を実装する必要があります。 これは明らかに明らかな「持っている必要がある」機能の省略のように見えるかもしれませんが、他のどのバインディングでも永続的なメッセージングが容易に利用できない理由は確かに十分な理由があります。

実際のところ、WCF の WS-ReliableMessaging ベースの実装の信頼性は、標準で表現されているものを除いて、それぞれのリモート パートナーに関する仮定を行うことができない揮発性の信頼性の高いメッセージング メカニズムの場合と同じくらい"のみ"優れているということです。 WS-RM 標準では、WS-ReliableMessagingは転送プロトコルであり、メッセージがもう一方の側で正常に受信された後に何が起こるかについて何も言わないので、ネットワーク上で何が起こっているのかのみをカバーします。 WCF がメッセージ配信、晴天、雹、または地震の接続の終わりに対してハード デリバリーの保証を与え、リモート パーティが標準に準拠しているが、実装では特に強固でない場合は、WCF が提供するレベル以下の全体的なサービス品質が得られます。

トランザクション I/O を完全にサポートするエンドツーエンドの永続的な信頼性の高いメッセージングが必要な場合は、通信パスの両端を制御するインフラストラクチャが必要です。このようなインフラストラクチャは Windows オペレーティング システム ファミリの一部です。 これらが要件である場合は、選択した WCF バインディングが NetMsmqBinding である可能性があります。 最適ではないネットワーク条件下でメッセージを失わないか、セッション サポートが必要な場合 (より一般的なユース ケース) は、WCF での信頼性の高いセッション サポートが適切な選択肢であり、前の Web サービス スタックと比較して大きく前進します。

 

筆者について

Clemens Vasters は、Microsoft の Windows Communication Foundation チームのコミュニティ プログラム マネージャーであり、開発者およびアーキテクト コミュニティと製品グループを結び付けます。 2006 年初頭に Microsoft に入社する前は、Microsoft 認定アーキテクトである Clemens は、newtelligence AG の CTO でした。 クレメンスは世界中のソフトウェア開発者会議で頻繁に講演していました。