Freigeben über


Parallelanfragen senden

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

Anmerkung

Das Senden paralleler Anforderungen innerhalb eines Plug-Ins wird nicht unterstützt. Weitere Informationen finden Sie unter "Nicht parallele Ausführung innerhalb von Plug-Ins und Workflowaktivitäten verwenden".

Optimaler Grad an Parallelität (DOP)

Dataverse verwaltet die Ressourcenzuordnung für Umgebungen. Produktionsumgebungen, die viele lizenzierte Benutzer stark verwenden, verfügen über mehr zugeordnete Ressourcen. Die Anzahl und die Funktionen der zugeordneten Server können im Laufe der Zeit variieren, daher gibt es keine feste Zahl für den optimalen Grad an Parallelität. 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.

Wenn Sie parallele Programmierung in .NET verwenden, hängt der Standardgrad der Parallelität von der Anzahl der CPU-Kerne auf dem Client ab, auf dem der Code ausgeführt wird. Wenn die Anzahl der CPU-Kerne die beste Übereinstimmung für die Umgebung überschreitet, senden Sie möglicherweise zu viele Anforderungen. Legen Sie die ParallelOptions.MaxDegreeOfParallelism-Eigenschaft fest, um eine maximale Anzahl gleichzeitiger Vorgänge zu definieren.

Grenzwerte für den Serviceschutz

Eine der drei Facetten, die für Dienstschutzgrenzen überwacht werden, ist die Anzahl gleichzeitiger Anforderungen. Dieser Wert ist standardmäßig 52, kann aber höher sein. Wenn der Grenzwert überschritten wird, wird ein Fehler zurückgegeben. Wenn Sie vom x-ms-dop-hint Antwortheaderwert abhängig sind, um den Grad der Parallelität zu begrenzen, sollten Sie diesen Grenzwert selten erreichen. Wenn dieser Fehler auftritt, verringern Sie die Anzahl der gleichzeitigen Threads.

Ein bestimmter Fehler wird zurückgegeben, wenn dieser Grenzwert erreicht wird:

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

Sie können auch die Wahrscheinlichkeit dieses Fehlers verringern, 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 mit einem Dienst in Azure herstellen, gibt der Dienst ein Cookie mit der Antwort zurück. Alle nachfolgenden Anforderungen versuchen, zum gleichen Server zu wechseln, es sei denn, die Kapazitätsverwaltung erzwingt die Anforderung, zu einem anderen Server zu wechseln. Interaktive Clientanwendungen, insbesondere Browserclients, profitieren von diesem Cookie, da sie es der Anwendung ermöglicht, auf dem Server zwischengespeicherte Daten wiederzuverwenden. Webbrowser verfügen immer über aktivierte Serveraffinität, und Sie können sie nicht deaktivieren.

Wenn Sie Anforderungen parallel von Ihrer Clientanwendung senden, können Sie leistungsvorteile erzielen, indem Sie dieses Cookie deaktivieren. Jede Anforderung, die Sie senden, wird an einen der berechtigten Server geroutet. Diese Änderung erhöht nicht nur den Gesamtdurchsatz, sondern trägt auch dazu bei, die Auswirkungen von Dienstschutzgrenzwerten zu verringern, da jeder Grenzwert pro Server gilt.

Die folgenden Beispiele zeigen, wie Sie die Serveraffinität mithilfe von .NET deaktivieren.

Wenn Sie die Klassen ServiceClient oder CrmServiceClient verwenden, fügen Sie dem AppSettings Knoten in der App.config Datei den folgenden Code hinzu.

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

Sie können den Wert der Eigenschaft auch mithilfe der EnableAffinityCookieKlassen ServiceClient oder CrmServiceClient festlegen.

Sie können diese Eigenschaft auch mithilfe des ServiceClient(ConnectionOptions,Boolean, ConfigurationOptions) -Konstruktors und der ConfigurationOptions.EnableAffinityCookie-Eigenschaft festlegen.

Optimieren Sie Ihre Verbindung

Wenn Sie .NET verwenden und Anforderungen parallel senden, ändern Sie die Standardeinstellungen, sodass Ihre Anforderungen nicht durch sie eingeschränkt werden. Nehmen Sie die folgenden Änderungen vor:

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

Diese Einstellung steuert die Mindestanzahl von Threads, die der Threadpool bei Bedarf erstellt, wenn neue Anforderungen eingehen. Nach Erreichen dieser Zahl wechselt der Threadpool zu einem Algorithmus, der die Threaderstellung und -zerstörung verwaltet.

Standardmäßig ist die Mindestanzahl von Threads auf die Prozessoranzahl festgelegt. Verwenden Sie SetMinThreads, um die minimale Anzahl von Threads zu erhöhen. Beispielsweise können Sie die Anzahl vorübergehend erhöhen, um Probleme zu umgehen, bei denen einige in die Warteschlange eingereihte Aufgaben 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 verwendeten Zahlen können je nach Hardware variieren. Die von Ihnen verwendeten Zahlen sind 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

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

DefaultConnectionLimit

Die Hardware schränkt diesen Wert letztendlich ein. Wenn Sie den Wert zu hoch festlegen, drosseln ihn andere Mechanismen. Heben Sie ihn über den Standardwert an, und legen Sie ihn mindestens gleich der Anzahl der gleichzeitigen Anforderungen fest, die Sie senden möchten.

Wenn Sie .NET Core mit HttpClientverwenden, steuert die HttpClientHandler.MaxConnectionsPerServer-Eigenschaft diese Einstellung. Der Standardwert ist int. MaxValue.

Weitere Informationen findest du unter:

Expect100Continue

Wenn Sie diese Eigenschaft auf „true“ festlegen, wartet der Client auf eine Roundtripbestätigung einer Verbindung mit dem Server. Für HttpClient ist der Standardwert von HttpRequestHeaders.ExpectContinue false.

Weitere Informationen findest du unter:

VerwendenSieNagleAlgorithmus

Der Nagle-Algorithmus reduziert den Netzwerkdatenverkehr, indem kleine Datenpakete gepuffert und als einzelnes Paket übertragen werden. Dieser Prozess wird auch als "nagling" bezeichnet. Er wird häufig verwendet, da er die Anzahl der übertragenen Pakete reduziert und den Mehraufwand pro Paket verringert. Das Festlegen dieses Werts auf "false" kann den gesamten Übertragungsaufwand verringern, kann jedoch zu einer Verzögerung bei der Ankunft von Datenpaketen führen.

Weitere Informationen finden Sie unter System.Net.ServicePointManager.UseNagleAlgorithm.

Beispiele

Die folgenden .NET-Beispiele zeigen, wie Sie die Task Parallel Library (TPL) mit Dataverse verwenden.

Sie können auf den x-ms-dop-hint Antwortwert über die RecommendedDegreesOfParallelism-Eigenschaft in entweder ServiceClient oder CrmServiceClient zugreifen. Verwenden Sie diesen Wert beim Festlegen von ParallelOptions.MaxDegreeOfParallelism , wenn Sie Parallel.ForEach verwenden.

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

Fügen Sie in den folgenden Beispielen die ID-Werte der Antworten zu einem ConcurrentBag von GUIDs hinzu. ConcurrentBag stellt eine Thread-sichere, ungeordnete Sammlung von Objekten bereit, wenn die Reihenfolge keine Rolle spielt. Sie können nicht davon ausgehen, dass die von dieser Methode zurückgegebenen GUIDs mit der Reihenfolge der im entityList Parameter gesendeten Elemente übereinstimmen.

Verwenden von ServiceClient mit .NET 6 oder höher

Mit .NET 6 oder höher können Sie die Parallel.ForEachAsync-Methode mit den asynchronen Methoden verwenden, die in ServiceClient enthalten sind, z. B. 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

Wenn Sie .NET Framework verwenden, dupliziert die in CrmServiceClient verfügbare Clone-Methode eine vorhandene Verbindung mit 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