次の方法で共有


トランザクション内のメッセージのバッチ処理

キューに登録されたアプリケーションは、トランザクションを使用して、メッセージの正確性と信頼性の高い配信を保証します。 ただし、トランザクションは負荷の高い操作であり、メッセージのスループットを大幅に削減できます。 メッセージのスループットを向上させる 1 つの方法は、アプリケーションが 1 つのトランザクション内で複数のメッセージを読み取って処理することです。 パフォーマンスと復旧のトレードオフは、バッチ内のメッセージの数が増えるにつれて、トランザクションがロールバックされた場合に必要な回復作業の量も増えます。 トランザクションとセッションでのメッセージのバッチ処理の違いに注意することが重要です。 セッションは、1 つのアプリケーションによって処理され、1 つのユニットとしてコミットされる関連メッセージのグループです。 セッションは、通常、関連するメッセージのグループを一緒に処理する必要がある場合に使用されます。 その例として、オンライン ショッピング Web サイトがあります。 バッチ は、メッセージのスループットを向上させる方法で、関連のない複数のメッセージを処理するために使用されます。 セッションの詳細については、「セッション 内のキューに入ったメッセージのグループ化」を参照してください。 バッチ内のメッセージも 1 つのアプリケーションによって処理され、1 つのユニットとしてコミットされますが、バッチ内のメッセージ間に関係がない可能性があります。 トランザクション内のメッセージのバッチ処理は、アプリケーションの実行方法を変更しない最適化です。

バッチ処理モードに入る

TransactedBatchingBehavior エンドポイントの動作によってバッチ処理が制御されます。 このエンドポイントの動作をサービス エンドポイントに追加すると、トランザクション内のメッセージをバッチ処理するように Windows Communication Foundation (WCF) に指示されます。 すべてのメッセージにトランザクションが必要なわけではないため、トランザクションを必要とするメッセージのみがバッチに配置され、 TransactionScopeRequired = true および TransactionAutoComplete = true でマークされた操作から送信されたメッセージのみがバッチに対して考慮されます。 サービス コントラクトに対するすべての操作が TransactionScopeRequired = false および TransactionAutoComplete = falseでマークされている場合、バッチ処理モードは開始されません。

トランザクションのコミット

バッチ処理されたトランザクションは、次に基づいてコミットされます。

  • MaxBatchSizeTransactedBatchingBehavior動作のプロパティ。 このプロパティは、バッチに配置されるメッセージの最大数を決定します。 この数に達すると、バッチがコミットされます。 これは値が厳密な制限ではなく、この数のメッセージを受信する前にバッチをコミットすることができます。

  • Transaction Timeout。 トランザクションのタイムアウトの 80% が経過すると、バッチがコミットされ、新しいバッチが作成されます。 つまり、トランザクションが完了するまでの時間の 20% 以下が残っている場合、バッチはコミットされます。

  • TransactionScopeRequired。 メッセージのバッチを処理するときに、falseを持つメッセージが見つかると、WCF はバッチをコミットし、とで最初のメッセージを受信したときに新しいバッチを再度開きます。

  • キューにメッセージがこれ以上存在しない場合、 MaxBatchSize に達していない場合やトランザクションのタイムアウトの 80% が経過していない場合でも、現在のバッチがコミットされます。

バッチ 処理モードを終了する

バッチ内のメッセージによってトランザクションが中止された場合、次の手順が実行されます。

  1. メッセージのバッチ全体がロールバックされます。

  2. メッセージは、読み取られたメッセージの数が最大バッチ サイズの 2 倍を超えるまで、一度に 1 つずつ読み取られます。

  3. バッチ モードが再入力されます。

バッチ サイズの選択

バッチのサイズはアプリケーションによって異なります。 経験的方法は、アプリケーションに最適なバッチ サイズに到達するための最良の方法です。 バッチ サイズを選択して、アプリケーションの実際のデプロイ モデルに従ってサイズを選択する場合は、注意が必要です。 たとえば、アプリケーションをデプロイするときに、リモート コンピューター上に SQL サーバーが必要で、キューと SQL サーバーにまたがるトランザクションが必要な場合、バッチ サイズは、この正確な構成を実行することによって最適に決定されます。

コンカレンシーとバッチ処理

スループットを向上させるために、多数のバッチを同時に実行することもできます。 ServiceBehaviorAttributeConcurrencyMode.Multipleを設定すると、同時バッチ処理が有効になります。

サービスの調整 は、サービスで実行できる最大同時呼び出しの数を示すために使用されるサービス動作です。 バッチ処理で使用する場合、これは実行できる同時実行バッチの数として解釈されます。 サービスの調整が設定されていない場合、WCF は既定で最大同時呼び出し数を 16 に設定します。 したがって、バッチ処理の動作が既定で追加された場合、同時に最大 16 個のバッチをアクティブにすることができます。 容量に基づいてサービスの調整とバッチ処理を調整することをお勧めします。 たとえば、キューに 100 個のメッセージがあり、20 個のバッチが必要な場合、最大同時呼び出しを 16 に設定しても役に立ちません。これは、バッチ処理を有効にしていない場合と同様に、スループットによっては 16 個のトランザクションがアクティブになる可能性があるためです。 そのため、パフォーマンスを微調整する場合は、同時バッチ処理を行わないか、適切なサービス スロットル サイズで同時バッチ処理を実行します。

バッチ処理と複数のエンドポイント

エンドポイントは、アドレスとコントラクトで構成されます。 同じバインディングを共有するエンドポイントが複数存在する場合があります。 2 つのエンドポイントで同じバインディングを共有し、Uri (Uniform Resource Identifier) またはキュー アドレスをリッスンできます。 2 つのエンドポイントが同じキューから読み取り、トランザクションバッチ処理動作が両方のエンドポイントに追加されると、指定されたバッチ サイズの競合が発生する可能性があります。 これは、2 つのトランザクションバッチ処理動作の間で指定された最小バッチ サイズを使用してバッチ処理を実装することで解決されます。 このシナリオでは、いずれかのエンドポイントでトランザクション バッチ処理が指定されていない場合、両方のエンドポイントでバッチ処理が使用されません。

次の例は、構成ファイルで TransactedBatchingBehavior を指定する方法を示しています。

<behaviors>
  <endpointBehaviors>
    <behavior name="TransactedBatchingBehavior"
              maxBatchSize="100" />
  </endpointBehaviors>
</behaviors>

次の例は、コードで TransactedBatchingBehavior を指定する方法を示しています。

using (ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService)))
{
     ServiceEndpoint sep = ServiceHost.AddServiceEndpoint(typeof(IOrderProcessor), new NetMsmqBinding(), "net.msmq://localhost/private/ServiceModelSamplesTransacted");
     sep.Behaviors.Add(new TransactedBatchingBehavior(100));

     // Open the ServiceHost to create listeners and start listening for messages.
    serviceHost.Open();
  
    // The service can now be accessed.
    Console.WriteLine("The service is ready.");
    Console.WriteLine("Press <ENTER> to terminate service.");
    Console.WriteLine();
    Console.ReadLine();
  
    // Close the ServiceHostB to shut down the service.
    serviceHost.Close();
}  

こちらも参照ください