Teilen über


Parallelanfragen senden

Wenn Ihre Anwendung eine große Anzahl von Anfragen an Dataverse senden muss, können Sie einen viel höheren Gesamtdurchsatz erzielen, indem Sie Anfragen parallel mit mehreren Threads senden. Dataverse wurde entwickelt, um mehrere gleichzeitige Benutzer zu unterstützen, sodass das parallele Senden von Anforderungen diese Stärke nutzt.

Hinweis

Das Senden paralleler Anfragen innerhalb eines Plug-Ins wird nicht unterstützt. Mehr Informationen: Verwenden Sie keine parallele Ausführung in Plug-Ins und Workflow-Aktivitäten

Optimaler Grad an Parallelität (DOP)

Ein Teil des Dienstes, der Dataverse bereitstellt, ist die Verwaltung der Ressourcenzuweisung für Umgebungen. Produktionsumgebungen, die von vielen lizenzierten Benutzern stark genutzt werden, werden mehr Ressourcen zugewiesen. Die Anzahl und Fähigkeiten der zugewiesenen Server können im Laufe der Zeit variieren, daher gibt es keine feste Anzahl, die Sie verwenden sollten, um den optimalen Grad an Parallelität zu erreichen. Verwenden Sie stattdessen den ganzzahligen Wert, der vom x-ms-dop-hint Antwortheader zurückgegeben wird. Dieser Wert stellt einen empfohlenen Grad an Parallelität für die Umgebung bereit.

Bei Verwendung von Parallele Programmierung in .NET hängt der Standardgrad der Parallelität von der Anzahl der CPU-Kerne auf dem Server ab, auf dem der Client den Code ausführt. Wenn die Anzahl der CPU-Kerne die beste Übereinstimmung für die Umgebung überschreitet, senden Sie möglicherweise zu viele Anforderungen. Sie können die Eigenschaft ParallelOptions.MaxDegreeOfParallelism festlegen, um eine maximale Anzahl gleichzeitiger Aufgaben zu definieren.

Grenzwerte für den Serviceschutz

Eine der drei Facetten, die für Dienstschutzgrenzen überwacht werden, ist die Anzahl gleichzeitiger Anforderungen. Standardmäßig ist dieser Wert 52, er kann jedoch höher sein. Ein Fehler wird zurückgegeben, wenn der Grenzwert überschritten wird. Wenn Sie sich auf den x-ms-dop-hint Antwortheaderwert verlassen, um den Grad der Parallelität zu begrenzen, sollten Sie diese Grenze selten erreichen. Wenn dieser Fehler auftritt, sollten Sie die Anzahl gleichzeitiger Threads reduzieren.

Wenn dieser Grenzwert erreicht ist, wird ein bestimmter Fehler zurückgegeben:

Fehlercode Hex-Code Nachricht
-2147015898 0x80072326 Number of concurrent requests exceeded the limit of 52.

Sie können auch die Wahrscheinlichkeit verringern, dass dieser Fehler auftritt, indem Sie Ihre Anforderungen an alle Server senden, die die Umgebung unterstützen, indem Sie die Serveraffinität deaktivieren.

Serveraffinität

Wenn Sie eine Verbindung zu einem Dienst in Azure herstellen, wird ein Cookie mit der Antwort zurückgegeben, und alle Ihre nachfolgenden Anfragen werden versuchen, an denselben Server weitergeleitet zu werden, es sei denn, die Kapazitätsverwaltung erzwingt einen Wechsel zu einem anderen Server. Interaktive Client-Anwendungen, insbesondere Browser-Clients, profitieren davon, da auf dem Server zwischengespeicherte Daten wiederverwendet werden können. Bei Webbrowsern ist die Serveraffinität immer aktiviert und kann nicht deaktiviert werden.

Wenn Sie Anfragen parallel von Ihrer Client-Anwendung senden, können Sie Leistungsvorteile erzielen, indem Sie dieses Cookie deaktivieren. Jede von Ihnen gesendete Anfrage wird an einen der in Frage kommenden Server weitergeleitet. Dies erhöht nicht nur den Gesamtdurchsatz, sondern trägt auch dazu bei, die Auswirkungen von Dienstschutzgrenzen zu reduzieren, da jeder Grenzwert pro Server angewendet wird.

Im Folgenden finden Sie einige Beispiele, die zeigen, wie die Serveraffinität mit .NET deaktiviert wird.

Wenn Sie die Klassen ServiceClient oder CrmServiceClient verwenden, fügen Sie Folgendes zum Knoten AppSettings in der Datei App.config hinzu.

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

Sie können den Wert der Eigenschaft EnableAffinityCookie auch mit dem ServiceClient oder CrmServiceClient festlegen

Dies kann auch mit dem Konstruktor ServiceClient(ConnectionOptions, Boolean, ConfigurationOptions) unter Verwendung der Eigenschaft ConfigurationOptions.EnableAffinityCookie festgelegt werden.

Optimieren Sie Ihre Verbindung

Wenden Sie bei der Verwendung von .NET und dem parallelen Senden von Anforderungen Konfigurationsänderungen wie die folgenden an, damit Ihre Anforderungen nicht durch die Standardeinstellungen eingeschränkt werden:

// 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

Dadurch wird die Mindestanzahl an Threads festgelegt, die der Thread-Pool bei Bedarf erstellt, wenn neue Anforderungen gestellt werden, bevor zu einem Algorithmus zum Verwalten der Thread-Erstellung und -Vernichtung gewechselt wird.

Standardmäßig ist die Mindestanzahl von Threads auf die Prozessoranzahl festgelegt. Sie können SetMinThreads verwenden, um die Mindestanzahl an Threads zu erhöhen, um beispielsweise vorübergehend Probleme zu umgehen, bei denen einige Arbeitsaufgaben oder Aufgaben in der Warteschlange Thread-Pool-Threads blockieren. Diese Blockaden führen manchmal zu einer Situation, in der alle Worker- oder I/O-Completion-Threads blockiert sind (Hunger). Das Erhöhen der Mindestanzahl von Threads kann jedoch die Leistung auf andere Weise beeinträchtigen.

Die zu verwendenden Nummern können je nach Hardware variieren. Die von Ihnen verwendeten Zahlen wären für eine verbrauchsbasierte Azure-Funktion niedriger als für Code, der auf einem dedizierten Host mit High-End-Hardware ausgeführt wird.

Weitere Informationen: System.Threading.ThreadPool.SetMinThreads

System.Net.ServicePointManager-Einstellungen

Bei .NET Framework ist ServicePointManager eine statische Klasse, die zum Erstellen, Verwalten und Löschen von Instanzen von ServicePoint Klassen verwendet wird. Verwenden Sie diese Einstellungen mit den Klassen ServiceClient oder CrmServiceClient . Diese Einstellungen sollten auch gelten, wenn HttpClient mit der Web-API in .NET Framework verwendet wird, aber mit .NET Core empfiehlt Microsoft stattdessen Einstellungen in HttpClient .

DefaultConnectionLimit

Dieser Wert wird letztlich durch die Hardware begrenzt. Ist er zu hoch eingestellt, wird er anderweitig gedrosselt. Der entscheidende Punkt ist, dass es über den Standardwert angehoben werden sollte und mindestens gleich der Anzahl gleichzeitiger Anfragen ist, die Sie senden möchten.

Wenn .NET Core HttpClient verwendet, wird dies durch den HttpClientHandler.MaxConnectionsPerServer gesteuert, und der Standardwert ist int.MaxValue.

Weitere Informationen:

Expect100Continue

Wenn diese Eigenschaft auf „true“ gesetzt ist, wartet der Client auf eine Roundtrip-Bestätigung einer Verbindung zum Server. Für HttpClient ist der Standardwert von HttpRequestHeaders.ExpectContinue false.

Weitere Informationen:

UseNagleAlgorithm

Der Nagle-Algorithmus wird verwendet, um den Netzwerkverkehr zu reduzieren, indem kleine Datenpakete gepuffert und als einzelnes Paket übertragen werden. Dieser Vorgang wird auch als Nageln bezeichnet; er ist weit verbreitet, da es die Anzahl der übertragenen Pakete reduziert und den Overhead pro Paket senkt. Wenn Sie dies auf „false“ setzen, kann dies den Gesamtaufwand für die Übertragung verringern, aber es kann zu Verzögerungen bei der Ankunft von Datenpaketen kommen.

Weitere Informationen: System.Net.ServicePointManager.UseNagleAlgorithm

Beispiele

Die folgenden .NET-Beispiele zeigen die Verwendung von Task Parallel Library (TPL) mit Dataverse.

Der x-ms-dop-hint Antwortwert ist über die Eigenschaft RecommendedDegreesOfParallelism in ServiceClient oder CrmServiceClient verfügbar. Sie sollten diesen Wert verwenden, wenn Sie ParallelOptions.MaxDegreeOfParallelism festlegen, wenn Sie Parallel.ForEach verwenden.

Diese Beispiele zeigen auch, wie die Eigenschaft EnableAffinityCookie auf „false“ gesetzt wird.

In den folgenden Beispielen werden die ID-Werte der Antworten zu einem ConcurrentBag von GUIDs hinzugefügt. ConcurrentBag stellt eine Thread-sichere, ungeordnete Sammlung von Objekten bereit, wenn die Reihenfolge keine Rolle spielt. Es kann nicht erwartet werden, dass die Reihenfolge der von dieser Methode zurückgegebenen GUIDs mit der Reihenfolge der im Parameter entityList gesendeten Elemente übereinstimmt.

Verwenden von ServiceClient mit .NET 6 oder höher

Mit .NET 6 oder höher können Sie die Parallel.ForEachAsync -Methode mit den im ServiceClient enthaltenen asynchronen Methoden verwenden, wie CreateAsync.

/// <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();
}

Verwenden von CrmServiceClient mit .NET Framework

Bei Verwendung von .NET Framework ermöglicht die in CrmServiceClient verfügbare Methode Clone das Duplizieren einer vorhandenen Verbindung zu Dataverse , sodass Sie die Parallel.ForEach Methode verwenden können.

/// <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();
}

Siehe auch

API-Grenzwerte für den Serviceschutz
Web-API WebApiService-Beispiel für parallele Operationen (C#)
Beispiel für parallele Web-API-Vorgänge mit TPL Dataflow-Komponenten (C#)
Beispiel: Task Parallel Library mit CrmServiceClient

Hinweis

Können Sie uns Ihre Präferenzen für die Dokumentationssprache mitteilen? Nehmen Sie an einer kurzen Umfrage teil. (Beachten Sie, dass diese Umfrage auf Englisch ist.)

Die Umfrage dauert etwa sieben Minuten. Es werden keine personenbezogenen Daten erhoben. (Datenschutzbestimmungen).