並行要求を送信する

アプリケーションが Dataverse に大量のリクエストを送信する必要がある場合、複数のスレッドを使用してリクエストを並行して送信することで、合計スループットを大幅に向上させることができます。 Dataverse は複数の同時ユーザーをサポートするように設計されているため、リクエストを並行して送信すると、この強みが活かされます。

注意

プラグイン内での並列リクエストの送信はサポートされていません。 詳細: プラグインおよびワークフロー アクティビティ内でパラレル実行を使用しないでください

並列処理の最適度 (DOP)

Dataverse は、提供するサービスの一部は、環境のリソース割り当ての管理です。 多くのライセンス ユーザーが頻繁に使用する実稼働環境には、より多くのリソースが割り当てられます。 割り当てられるサーバーの数と機能は、時間の経過とともに変化する可能性があるため、最適な並列度を得るために適用する固定数はありません。 代わりに、x-ms-dop-hint 応答ヘッダーから返された整数値を使用してください。 この値は、環境に推奨される並列度を示します。

.NET における並列プログラミング を使用する場合、デフォルトの並列度は、コードを実行しているクライアントの CPU コアの数によって異なります。 CPU コアの数が環境に最適な数を超えている場合は、送信する要求が多すぎる可能性があります。 ParallelOptions.MaxDegreeOfParallelism プロパティ を同時実行タスクの最大数を定義するように設定できます。

サービス保護の制限

サービス保護の制限について監視される 3 つのファセットの 1 つは、同時要求の数です。 デフォルトでは、この値は 52 ですが、それより高い場合もあります。 時間制限を超えた場合、エラーが返されます。 x-ms-dop-hint 応答ヘッダーの値に依存して並列度を制限している場合、この制限に達することはほとんどありません。 このエラーが発生した場合は、同時スレッドの数を減らす必要があります。

この制限に達すると、特定のエラーが返されます。

エラー コード 16 進コード Message
-2147015898 0x80072326 Number of concurrent requests exceeded the limit of 52.

サーバー アフィニティを無効にして、環境をサポートするすべてのサーバーに要求を送信することで、このエラーが発生する可能性を軽減することもできます。

サーバー アフィニティ

Azure 上のサービスに接続すると、応答とともに Cookie が返され、容量管理により別のサーバーに移動するよう強制されない限り、後続のすべての要求は同じサーバーにルーティングされます。 サーバーにキャッシュされたデータを再利用できるため、対話型のクライアント アプリケーション、特にブラウザー クライアントはこの利点を享受できます。 Web ブラウザでは常にサーバー アフィニティが有効になっており、無効にすることはできません。

クライアント アプリケーションからリクエストを並行して送信する場合、この Cookie を無効にするとパフォーマンスが向上します。 送信する各要求は、適格なサーバーのいずれかにルーティングされます。 これにより、合計スループットが向上するだけでなく、各制限がサーバーごとに適用されるため、サービス保護制限の影響を軽減するのにも役立ちます。

次に、.NETとのサーバー アフィニティを無効にする方法を示すいくつかの例を示します。

ServiceClient クラスまたは CrmServiceClient クラスをご利用の場合は、App.config ファイルの AppSettings ノードに以下を追加します。

<add key="PreferConnectionAffinity" value="false" />

EnableAffinityCookie プロパティを ServiceClient または CrmServiceClient のいずれかでプロパティの値を設定することもできます

これは、ConfigurationOptions.EnableAffinityCookie プロパティを使用して、ServiceClient(ConnectionOptions、Boolean、ConfigurationOptions) コンストラクタを使用して設定することもできます。

接続の最適化

.NET を使用して要求を並行して送信する場合は、次のような構成変更を適用して、要求が既定の設定によって制限されないようにします。

// Bump up the min threads reserved for this app to ramp connections faster - minWorkerThreads defaults to 4, minIOCP defaults to 4 
ThreadPool.SetMinThreads(100, 100);
// Change max connections from .NET to a remote service default: 2
System.Net.ServicePointManager.DefaultConnectionLimit = 65000;
// Turn off the Expect 100 to continue message - 'true' will cause the caller to wait until it round-trip confirms a connection to the server 
System.Net.ServicePointManager.Expect100Continue = false;
// Can decrease overall transmission overhead but can cause delay in data packet arrival
System.Net.ServicePointManager.UseNagleAlgorithm = false;

ThreadPool.SetMinThreads

これにより、スレッドの作成と破棄を管理するアルゴリズムに切り替える前に、新しい要求が行われると、スレッド プールがオンデマンドで作成するスレッドの最小数が設定されます。

デフォルトでは、スレッドの最小数はプロセッサ数に設定されています。 SetMinThreads を使用して、スレッドの最小数を増やすことができます。たとえば、キューに入れられた作業項目またはタスクがスレッド プール スレッドをブロックする問題を一時的に回避できます。 これらのブロックにより、すべてのワーカーまたはI/O完了スレッドがブロックされる (枯渇) 状況が発生することがあります。 ただし、スレッドの最小数を増やすと、他の方法でパフォーマンスが低下する可能性があります。

使用する数値は、ハードウェアによって異なります。 使用する数値は、ハイエンド ハードウェアを備えた専用ホストで実行されるコードよりも消費ベースの Azure 関数の方が少なくなります。

詳細: System.Threading.ThreadPool.SetMinThreads

System.Net.ServicePointManager の設定

.NET Framework では、ServicePointManager は、ServicePoint のインスタンスを作成、維持、および削除するために使用される静的クラスです。クラス。 これらの設定は、ServiceClient クラスまたは CrmServiceClient クラスで使用します。 これらの設定は、.NET Framework の Web API で HttpClient を使用する場合にも適用する必要がありますが、.NET Core では Microsoft は代わりに HttpClient での設定を推奨しています。

DefaultConnectionLimit

この値は、最終的にハードウェアによって制限されます。 設定が高すぎると、他の手段によって抑制されます。 重要な点は、デフォルト値よりも大きくする必要があり、少なくとも送信する予定の同時要求の数と同じにする必要があるということです。

HttpClient を使用する .NET Core では、これは HttpClientHandler.MaxConnectionsPerServer によって制御され、デフォルト値は int.MaxValue です。

詳細情報:

Expect100Continue

このプロパティが true に設定されている場合、クライアントはサーバーへの接続を確認するラウンドトリップを待機します。 HttpClient HttpRequestHeaders.ExpectContinue のデフォルト値は false です。

詳細情報:

UseNagleAlgorithm

Nagle アルゴリズムは、データの小さなパケットをバッファリングして単一のパケットとして送信することにより、ネットワーク トラフィックを削減するために使用されます。 このプロセスは "ナグリング" とも呼ばれます。送信されるパケットの数を減らし、パケットごとのオーバーヘッドを下げるため、広く使用されています。 これを false に設定すると、全体的な送信オーバーヘッドを減らすことができますが、データ パケットの到着に遅延が生じる可能性があります。

詳細: System.Net.ServicePointManager.UseNagleAlgorithm

使用例

次の .NETの例は、Task Parallel Library (TPL) と Dataverse の使用を示しています。

x-ms-dop-hint 応答値は、RecommendedDegreesOfParallelism プロパティを介して、ServiceClient または CrmServiceClient で取得できます。 Parallel.ForEach を使用するときに、ParallelOptions.MaxDegreeOfParallelism を設定するときに、この値を使用する必要があります。

これらの例では、EnableAffinityCookie プロパティを false に設定することも示しています。

以下の例では、応答の id 値が Guid の ConcurrentBag に追加されます。 ConcurrentBag 順序が問題にならない場合に、オブジェクトのスレッドセーフな順序付けされていないコレクションを提供します。 このメソッドによって返される Guid の順序は、entityList パラメータで送信される項目の順序と一致するとは期待できません。

.NET 6 以降で ServiceClient を使用する

.NET 6 以降では、Parallel.ForEachAsync メソッドを、CreateAsync などの ServiceClient に含まれる非同期メソッドと共に使用できます。

/// <summary>
/// Creates records in parallel
/// </summary>
/// <param name="serviceClient">The authenticated ServiceClient instance.</param>
/// <param name="entityList">The list of entities to create.</param>
/// <returns>The id values of the created records.</returns>
static async Task<Guid[]> CreateRecordsInParallel(
    ServiceClient serviceClient, 
    List<Entity> entityList)
{
    ConcurrentBag<Guid> ids = new();

    // Disable affinity cookie
    serviceClient.EnableAffinityCookie = false;

    var parallelOptions = new ParallelOptions()
    { MaxDegreeOfParallelism = 
        serviceClient.RecommendedDegreesOfParallelism };

    await Parallel.ForEachAsync(
        source: entityList,
        parallelOptions: parallelOptions,
        async (entity, token) =>
        {
            ids.Add(await serviceClient.CreateAsync(entity, token));
        });

    return ids.ToArray();
}

.NET Framework での CrmServiceClient の使用

.NET Framework 使用する場合、CrmServiceClient で使用できる クローン メソッドは、Dataverse への既存の接続の複製を許可するので、Parallel.ForEach メソッドを使用できます。

/// <summary>
/// Creates records in parallel
/// </summary>
/// <param name="crmServiceClient">The authenticated CrmServiceClient instance.</param>
/// <param name="entityList">The list of entities to create.</param>
/// <returns>The id values of the created records.</returns>
static Guid[] CreateRecordsInParallel(
    CrmServiceClient crmServiceClient, 
    List<Entity> entityList)
{
   ConcurrentBag<Guid> ids = new ConcurrentBag<Guid>();

    // Disable affinity cookie
    crmServiceClient.EnableAffinityCookie = false;

   Parallel.ForEach(entityList,
      new ParallelOptions()
      {
            MaxDegreeOfParallelism = crmServiceClient.RecommendedDegreesOfParallelism
      },
      () =>
      {
            //Clone the CrmServiceClient for each thread
            return crmServiceClient.Clone();
      },
      (entity, loopState, index, threadLocalSvc) =>
      {
            ids.Add(threadLocalSvc.Create(entity));

            return threadLocalSvc;
      },
      (threadLocalSvc) =>
      {
            //Dispose the cloned crmServiceClient instance
            threadLocalSvc?.Dispose();
      }
   );
   return ids.ToArray();
}

参照

サービス保護の API 制限
Web API WebApiService の並列演算のサンプル (C#)
TPL データフロー コンポーネントを使用した Web API 並列演算のサンプル (C#)
サンプル: CrmServiceClient を使用したタスク並列ライブラリ

注意

ドキュメントの言語設定についてお聞かせください。 簡単な調査を行います。 (この調査は英語です)

この調査には約 7 分かかります。 個人データは収集されません (プライバシー ステートメント)。