Leistungstipps für Azure Cosmos DB und .NET SDK v2

GILT FÜR: NoSQL

Azure Cosmos DB ist eine schnelle und flexible verteilte Datenbank mit nahtloser Skalierung, garantierter Latenz und garantiertem Durchsatz. Die Skalierung Ihrer Datenbank mit Azure Cosmos DB erfordert weder aufwendige Änderungen an der Architektur noch das Schreiben von komplexem Code. Zentrales Hoch- und Herunterskalieren ist ebenso problemlos möglich wie ein einzelner API-Aufruf. Weitere Informationen finden Sie unter Bereitstellen von Containerdurchsatz und Bereitstellen von Datenbankdurchsatz. Da der Zugriff auf Azure Cosmos DB jedoch über Netzwerkaufrufe erfolgt, können Sie clientseitige Optimierungen vornehmen, um bei Verwendung des SQL .NET SDK eine optimale Leistung zu erzielen.

Wenn Sie versuchen möchten, die Datenbankleistung zu verbessern, sollten Sie die folgenden Optionen beachten:

Upgrade auf das .NET v3 SDK

Das .NET v3 SDK wurde veröffentlicht. Wenn Sie das .NET v3 SDK verwenden, finden Sie im Leitfaden zur Leistung von .NET v3 die folgenden Informationen:

  • Standardwerte für den direkten TCP-Modus
  • Stream-API-Unterstützung
  • Unterstützung eines benutzerdefinierten Serialisierungsmoduls zur Verwendung von System.Text.JSON
  • Integrierte Unterstützung von Batch- und Massenvorgängen

Hostingempfehlungen

Aktivieren der serverseitigen Garbage Collection (GC)

In einigen Fällen kann es hilfreich sein, die Häufigkeit zu verringern, mit der die Garbage Collection ausgeführt wird. Legen Sie gcServer in .NET auf true fest.

Erweitern Ihrer Clientworkload

Wenn Sie auf einem hohen Durchsatzniveau testen (> 50.000 RU/s), kann sich die Clientanwendung als Engpass erweisen, da der Computer die CPU- oder Netzwerkauslastung deckelt. Wenn dieser Punkt erreicht wird, können Sie das Azure Cosmos DB-Konto weiter auslasten, indem Sie Ihre Clientanwendungen auf mehrere Server horizontal hochskalieren.

Hinweis

Eine hohe CPU-Auslastung kann zu erhöhter Latenz und Ausnahmen des Typs „Anforderungstimeout“ führen.

Metadatenvorgänge

Überprüfen Sie das Vorhandensein einer Datenbank und/oder einer Sammlung nicht durch den Aufruf von Create...IfNotExistsAsync und/oder Read...Async im langsamsten Pfad und/oder vor der Durchführung eines Elementvorgangs. Die Überprüfung sollte nur beim Start der Anwendung durchgeführt werden, wenn dies erforderlich ist und Sie eine Löschung erwarten (andernfalls ist keine Überprüfung erforderlich). Diese Metadatenvorgänge verursachen eine zusätzliche End-to-End-Latenz, unterliegen keiner SLA und separaten Einschränkungen und sind nicht wie Datenvorgänge skalierbar.

Protokollierung und Nachverfolgung

In einigen Umgebungen ist .NET DefaultTraceListener aktiviert. DefaultTraceListener führt in Produktionsumgebungen zu Leistungsproblemen, die eine hohe CPU-Auslastung und E/A-Engpässe bewirken. Stellen Sie sicher, dass DefaultTraceListener für Ihre Anwendung deaktiviert ist, indem Sie ihn in Produktionsumgebungen aus TraceListeners entfernen.

Bei den neuesten SDK-Versionen (höher als 2.16.2) wird er bei Erkennung automatisch entfernt. Bei älteren Versionen können Sie ihn wie folgt entfernen:

if (!Debugger.IsAttached)
{
    Type defaultTrace = Type.GetType("Microsoft.Azure.Documents.DefaultTrace,Microsoft.Azure.DocumentDB.Core");
    TraceSource traceSource = (TraceSource)defaultTrace.GetProperty("TraceSource").GetValue(null);
    traceSource.Listeners.Remove("Default");
    // Add your own trace listeners
}

Netzwerk

Verbindungsrichtlinie: Verwenden des direkten Verbindungsmodus

Als Standardverbindungsmodus des .NET V3 SDK wird der Gatewaymodus verwendet. Sie konfigurieren den Verbindungsmodus während der Erstellung der DocumentClient-Instanz mithilfe des Parameters ConnectionPolicy. Wenn Sie den direkten Modus verwenden, müssen Sie Protocol ebenfalls mithilfe des Parameters ConnectionPolicy festlegen. Weitere Informationen zu verschiedenen Konnektivitätsoptionen finden Sie im Artikel zu den Konnektivitätsmodi.

Uri serviceEndpoint = new Uri("https://contoso.documents.net");
string authKey = "your authKey from the Azure portal";
DocumentClient client = new DocumentClient(serviceEndpoint, authKey,
new ConnectionPolicy
{
   ConnectionMode = ConnectionMode.Direct, // ConnectionMode.Gateway is the default
   ConnectionProtocol = Protocol.Tcp
});

Kurzfristige Portauslastung

Wenn Sie ein hohes Verbindungsaufkommen oder eine hohe Portauslastung Ihrer Instanzen feststellen, überprüfen Sie zunächst, ob die Clientinstanzen Singletons sind. Anders ausgedrückt: Die Clientinstanzen müssen für die Lebensdauer der Anwendung eindeutig sein.

Bei der Ausführung über das TCP-Protokoll optimiert der Client die Latenz mithilfe langlebiger Verbindungen. Im Gegensatz dazu werden beim HTTPS-Protokoll Verbindungen nach 2 Minuten Inaktivität getrennt.

Wenn Sie in Szenarien mit geringem Zugriff eine im Vergleich zum Zugriff im Gatewaymodus höhere Anzahl von Verbindungen feststellen, haben Sie folgende Möglichkeiten:

  • Konfigurieren Sie die Eigenschaft ConnectionPolicy.PortReuseMode auf PrivatePortPool (wirksam mit Framework Version>= 4.6.1 und .NET Core Version >= 2.0): Diese Eigenschaft ermöglicht es dem SDK, einen kleinen Pool von einmaligen Ports für verschiedene Azure Cosmos DB-Zielendpunkte zu verwenden.
  • Konfigurieren Sie die Eigenschaft ConnectionPolicy.IdleConnectionTimeout auf mindestens 10 Minuten. Die empfohlenen Werte liegen zwischen 20 Minuten und 24 Stunden.

Aufrufen von OpenAsync, um die Startlatenz bei der ersten Anforderung zu vermeiden

Aufgrund des erforderlichen Abrufs der Adressroutingtabelle tritt bei der ersten Anforderung standardmäßig eine höhere Latenz auf. Um diese Startlatenz bei der ersten Anforderung zu vermeiden, rufen Sie bei Verwendung des SDK V2 während der Initialisierung einmal OpenAsync() auf. Der Aufruf sieht wie folgt aus: await client.OpenAsync();.

Hinweis

Mit OpenAsync werden Anforderungen zum Abrufen der Adressroutingtabelle für alle Container im Konto generiert. Für Konten, die über viele Container verfügen, deren Anwendung jedoch auf eine Teilmenge der Container zugreift, würde OpenAsync eine unnötige Menge an Datenverkehr generieren, durch die die Initialisierung verlangsamt wird. Daher ist die Verwendung von OpenAsync in diesem Szenario möglicherweise nicht sinnvoll, da damit der Anwendungsstart verlangsamt wird.

Platzieren von Clients in derselben Azure-Region, um die Leistung zu verbessern

Platzieren Sie nach Möglichkeit sämtliche Anwendungen, die Azure Cosmos DB aufrufen, in der gleichen Region wie die Azure Cosmos DB-Datenbank. Damit Sie einen ungefähren Vergleich haben: Azure Cosmos DB-Aufrufe aus derselben Region werden normalerweise innerhalb von ca. 1 bis 2 ms abgeschlossen, während die Latenz zwischen West- und Ostküste der USA mehr als 50 ms beträgt. Diese Latenz variiert ggf. von Anforderung zu Anforderung und ist abhängig von der Route, die die Anforderung zwischen dem Client und der Grenze des Azure-Rechenzentrums nimmt. Die geringste Latenz erzielen Sie, wenn sich die aufrufende Anwendung in der gleichen Azure-Region wie der bereitgestellte Azure Cosmos DB-Endpunkt befindet. Eine Liste mit den verfügbaren Regionen finden Sie unter Azure-Regionen.

Azure Cosmos DB-Verbindungsrichtlinie

Erhöhen der Anzahl von Threads/Aufgaben

Da Azure Cosmos DB-Aufrufe über das Netzwerk erfolgen, müssen Sie eventuell den Parallelitätsgrad Ihrer Anforderungen variieren, um die Wartezeit für die Clientanwendung zwischen Anforderungen auf ein Minimum zu reduzieren. Erstellen Sie beispielsweise bei Verwendung der Task Parallel Library von .NET mehrere Hundert Aufgaben für Lese- und Schreibvorgänge in Azure Cosmos DB.

Aktivieren des beschleunigten Netzwerkbetriebs

Um Latenzen und CPU-Jitter zu reduzieren, wird empfohlen, auf den virtuellen Clientcomputern den beschleunigten Netzwerkbetrieb zu aktivieren. Weitere Informationen finden Sie unter Erstellen eines virtuellen Windows-Computers mit beschleunigtem Netzwerkbetrieb oder Erstellen eines virtuellen Linux-Computers mit beschleunigtem Netzwerkbetrieb.

SDK-Verwendung

Installieren des neuesten SDKs

Azure Cosmos DB-SDKs werden ständig verbessert, um eine optimale Leistung zu ermöglichen. Informationen zum neuesten SDK und zu den Verbesserungen finden Sie auf den Seiten unter Azure Cosmos DB SDK.

Verwenden eines Singleton-Azure Cosmos DB-Clients für die Lebensdauer der Anwendung

Bei Verwendung des direkten Modus ist jede Instanz von DocumentClient threadsicher und verfügt über eine effiziente Verbindungsverwaltung und Adressenzwischenspeicherung. Zur Ermöglichung einer effizienten Verbindungsverwaltung und einer besseren Leistung des SDK-Clients empfiehlt es sich, für die Lebensdauer der Anwendung pro AppDomain eine einzelne Instanz zu verwenden.

Vermeiden von blockierenden Aufrufen

Das Azure Cosmos DB SDK sollte so konzipiert werden, dass es viele Anforderungen gleichzeitig verarbeiten kann. Asynchrone APIs ermöglichen die parallele Verarbeitung Tausender Anforderungen in einem kleinen Pool von Threads, indem nicht auf blockierende Aufrufe gewartet wird. Anstatt darauf zu warten, dass eine synchrone Aufgabe mit langer Laufzeit abgeschlossen wird, kann der Thread eine andere Anforderung bearbeiten.

Ein häufiges Leistungsproblem in Apps, die das Azure Cosmos DB SDK verwenden, sind blockierende Aufrufe, die asynchron sein könnten. Viele synchrone blockierende Aufrufe führen zu einem Threadmangel im Pool und zu längeren Antwortzeiten.

Vermeiden Sie Folgendes:

  • Blockieren der asynchronen Ausführung durch Aufrufen von Task.Wait oder Task.Result.
  • Verwenden von Task.Run, um eine synchrone API als asynchron festzulegen.
  • Abrufen von Sperren in allgemeinen Codepfaden. Das Azure Cosmos DB .NET SDK liefert die beste Leistung, wenn der Code parallel ausgeführt wird.
  • Aufrufen von Task.Run und sofortiges Warten darauf. ASP.NET Core führt App-Code bereits in normalen Threads im Threadpool aus, daher führt ein Aufruf von „Task.Run“ nur zu einer unnötigen zusätzlichen Reservierung des Threadpools. Auch wenn der geplante Code einen Thread blockieren würde, wird dies durch „Task.Run“ nicht verhindert.
  • Verwenden Sie „ToList()“ für DocumentClient.CreateDocumentQuery(...). Es nutzt blockierende Aufrufe, um die Abfrage synchron zu entladen. Verwenden Sie AsDocumentQuery(), um die Abfrage asynchron zu entladen.

Empfohlene Vorgehensweise:

  • Rufen Sie die .NET-APIs von Azure Cosmos DB asynchron auf.
  • Die gesamte Aufrufliste ist asynchron, um von async/await-Mustern zu profitieren.

Über einen Profiler wie z. B. PerfView können Threads ermittelt werden, die dem Threadpool häufig hinzugefügt werden. Das Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start-Ereignis gibt einen Thread an, der dem Threadpool hinzugefügt wurde.

Erhöhen von System.Net MaxConnections pro Host bei Verwendung des Gatewaymodus

Azure Cosmos DB-Anforderungen erfolgen im Gatewaymodus über HTTPS/REST. Sie unterliegen dem Standardverbindungslimit pro Hostname oder IP-Adresse. Unter Umständen müssen Sie einen höheren MaxConnections-Wert festlegen (100 – 1.000), damit die Clientbibliothek mehrere Verbindungen mit Azure Cosmos DB gleichzeitig nutzen kann. In .NET SDK 1.8.0 und höher ist der Standardwert für ServicePointManager.DefaultConnectionLimit „50“. Um den Wert zu ändern, können Sie Documents.Client.ConnectionPolicy.MaxConnectionLimit auf einen höheren Wert festlegen.

Implementieren eines Backoffs in RetryAfter-Intervallen

Es empfiehlt sich, die Last während Leistungstests so lange erhöhen, bis eine geringe Menge von Anforderungen gedrosselt wird. Wenn die Anforderungen gedrosselt werden, sollte die Clientanwendung diese Drosselung für das vom Server angegebene Wiederholungsintervall aussetzen. Durch das Aussetzen wird die geringstmögliche Wartezeit zwischen den Wiederholungsversuchen gewährleistet.

Die folgenden SDKs bieten Unterstützung für Wiederholungsrichtlinien:

Weitere Informationen finden Sie unter RetryAfter.

Das .NET SDK ab Version 1.19 verfügt über einen Mechanismus zum Protokollieren zusätzlicher Diagnoseinformationen und zum Beheben von Problemen mit der Latenz, wie im folgenden Beispiel gezeigt. Sie können die Diagnosezeichenfolge für Anforderungen protokollieren, die eine höhere Leselatenz aufweisen. Mithilfe der erfassten Diagnosezeichenfolge können Sie ermitteln, wie häufig bei einer bestimmten Anforderung der Fehler 429 aufgetreten ist.

ResourceResponse<Document> readDocument = await this.readClient.ReadDocumentAsync(oldDocuments[i].SelfLink);
readDocument.RequestDiagnosticsString 

Zwischenspeichern von Dokument-URIs zur Verringerung der Latenz bei Lesevorgängen

Zur Erzielung einer optimalen Leseleistung sollten Dokument-URIs möglichst immer zwischengespeichert werden. Sie müssen die Logik definieren, um die Ressourcen-ID beim Erstellen einer Ressource zwischenzuspeichern. Suchvorgänge auf Basis von Ressourcen-IDs sind schneller als namensbasierte, sodass durch ein Zwischenspeichern dieser Werte die Leistung verbessert wird.

Erhöhen der Anzahl von Threads/Aufgaben

Siehe Erhöhen der Anzahl von Threads/Aufgaben im Abschnitt „Netzwerk“ dieses Artikels.

Abfragevorgänge

Informationen zu Abfragevorgängen finden Sie in den Leistungstipps für Abfragen.

Indizierungsrichtlinie

Beschleunigen von Schreibvorgängen durch Ausschließen nicht verwendeter Pfade von der Indizierung

Die Indizierungsrichtlinie von Azure Cosmos DB ermöglicht auch die Verwendung von Indizierungspfaden („IndexingPolicy.IncludedPaths“ und „IndexingPolicy.ExcludedPaths“), um anzugeben, welche Dokumentpfade in die Indizierung ein- bzw. ausgeschlossen werden sollen. Indizierungspfade können bessere Schreibleistungen und geringeren Indexspeicherbedarf für Szenarien bieten, in denen die Abfragemuster im Voraus bekannt sind. Dies liegt daran, dass der Indizierungsaufwand direkt mit der Anzahl der indizierten eindeutigen Pfade zusammenhängt. Der folgende Code zeigt beispielsweise, wie Sie einen vollständigen Abschnitt der Dokumente (eine Unterstruktur) mit dem Platzhalter „*“ von der Indizierung ausschließen:

var collection = new DocumentCollection { Id = "excludedPathCollection" };
collection.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" });
collection.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/nonIndexedContent/*");
collection = await client.CreateDocumentCollectionAsync(UriFactory.CreateDatabaseUri("db"), collection);

Weitere Informationen finden Sie unter Indizierungsrichtlinien für Azure Cosmos DB.

Throughput

Messen und Optimieren zum Senken der erforderlichen Anforderungseinheiten pro Sekunde

Azure Cosmos DB bietet einen umfangreichen Satz von Datenbankvorgängen. Diese Vorgänge umfassen relationale und hierarchische Abfragen mit UDFs, gespeicherte Prozeduren und Trigger, die alle in den Dokumenten innerhalb einer Datenbanksammlung ausgeführt werden. Die Kosten im Zusammenhang mit diesen Vorgängen variieren in Abhängigkeit vom CPU-, E/A- und Speicheraufwand, der für den jeweiligen Vorgang erforderlich ist. Anstelle sich Gedanken über Hardwareressourcen und deren Verwaltung zu machen, können Sie sich eine Anforderungseinheit (RU) als alleinige Maßeinheit für die Ressourcen vorstellen, die für das Durchführen der verschiedenen Datenbankvorgänge und das Ausführen einer Anwendungsanforderung erforderlich sind.

Der Durchsatz wird basierend auf der für jeden Container festgelegten Anzahl von Anforderungseinheiten bereitgestellt. Der Verbrauch von Anforderungseinheiten wird als Rate pro Sekunde bemessen. Anwendungen, die die bereitgestellte Rate von Anforderungseinheiten für ihre Container überschreiten, werden begrenzt, bis die Rate wieder unter das bereitgestellte Niveau für den Container fällt. Wenn Ihre Anwendung einen höheren Durchsatz erfordert, können Sie ihn durch Bereitstellung zusätzlicher Anforderungseinheiten erhöhen.

Die Komplexität einer Abfrage wirkt sich darauf aus, wie viele Anforderungseinheiten für einen Vorgang verbraucht werden. Die Anzahl von Prädikaten, die Art der Prädikate, die Anzahl von UDFs und die Größe des Quelldatasets beeinflussen die Kosten von Abfragevorgängen.

Untersuchen Sie zum Ermitteln des Aufwands für einen Vorgang (Erstellen, Aktualisieren oder Löschen) den Header x-ms-request-charge (oder die entsprechende RequestCharge-Eigenschaft in ResourceResponse\<T> oder FeedResponse\<T> im .NET SDK), um die Anzahl von Anforderungseinheiten zu ermitteln, die von diesen Vorgängen verbraucht werden:

// Measure the performance (Request Units) of writes
ResourceResponse<Document> response = await client.CreateDocumentAsync(collectionSelfLink, myDocument);
Console.WriteLine("Insert of document consumed {0} request units", response.RequestCharge);
// Measure the performance (Request Units) of queries
IDocumentQuery<dynamic> queryable = client.CreateDocumentQuery(collectionSelfLink, queryString).AsDocumentQuery();
while (queryable.HasMoreResults)
    {
        FeedResponse<dynamic> queryResponse = await queryable.ExecuteNextAsync<dynamic>();
        Console.WriteLine("Query batch consumed {0} request units", queryResponse.RequestCharge);
    }

Bei den in diesem Header zurückgegebenen Anforderungskosten handelt es sich um einen Bruchteil Ihres bereitgestellten Durchsatzes (2.000 RU/s). Falls die obige Abfrage also beispielsweise 1.000 Dokumente mit einer Größe von 1 KB zurückgibt, fallen für den Vorgang Kosten in Höhe von 1.000 an. Somit werden vom Server innerhalb einer Sekunde nur zwei solcher Anforderungen berücksichtigt, und für weitere Anforderungen wird die Rate begrenzt. Weitere Informationen finden Sie unter Anforderungseinheiten sowie unter dem Rechner für Anforderungseinheiten.

Behandeln von Ratenbeschränkungen/zu hohen Anforderungsraten

Wenn ein Client versucht, den für ein Konto reservierten Durchsatz zu überschreiten, wird die Serverleistung nicht beeinträchtigt, und es wird kein über die reservierte Kapazität hinausgehender Durchsatz in Anspruch genommen. Der Server beendet die Anforderung vorab mit RequestRateTooLarge (HTTP-Statuscode 429). Er gibt einen x-ms-retry-after-ms-Header zurück, der die Zeitspanne in Millisekunden angibt, die der Benutzer warten muss, bevor er die Anforderung erneut versuchen kann.

HTTP Status 429,
Status Line: RequestRateTooLarge
x-ms-retry-after-ms :100

Alle SDKs fangen diese Antwort implizit ab, berücksichtigen den vom Server angegebenen Header vom Typ „retry-after“ und wiederholen die Anforderung. Wenn nicht mehrere Clients gleichzeitig auf Ihr Konto zugreifen, wird die nächste Wiederholung erfolgreich ausgeführt.

Wenn insgesamt mehrere Clients beständig die Anforderungsrate überschreiten, reicht die standardmäßige Wiederholungsanzahl (vom Client intern auf 9 festgelegt) möglicherweise nicht aus. In diesem Fall löst der Client eine DocumentClientException mit dem Statuscode 429 für die Anwendung aus.

Sie können die Standardanzahl von Wiederholungsversuchen ändern, indem Sie die RetryOptions für die ConnectionPolicy-Instanz festlegen. Die DocumentClientException mit dem Statuscode 429 wird standardmäßig nach einer kumulierten Wartezeit von 30 Sekunden zurückgegeben, wenn die Anforderung weiterhin die Anforderungsrate übersteigt. Dieser Fehler wird auch dann zurückgegeben, wenn die aktuelle Wiederholungsanzahl unter der maximalen Wiederholungsanzahl liegt – ganz gleich, ob es sich dabei um den Standardwert (9) oder um einen benutzerdefinierten Wert handelt.

Das automatisierte Wiederholungsverhalten trägt dazu bei, die Resilienz und Benutzerfreundlichkeit für die meisten Anwendungen zu verbessern. Dies stellt jedoch möglicherweise nicht das beste Verhalten dar, wenn Sie Leistungsbenchmarks durchführen, und insbesondere nicht beim Messen der Latenz. Die Wartezeit für den Client nimmt stark zu, wenn das Experiment die Serverdrosselung erreicht und damit die automatische Wiederholung durch das Client-SDK auslöst. Ermitteln Sie zur Vermeidung von Latenzspitzenwerten bei Leistungsexperimenten die von den einzelnen Vorgängen zurückgegebene Belastung, und stellen Sie sicher, dass die Anforderungen die reservierte Anforderungsrate nicht überschreiten. Weitere Informationen finden Sie unter Anforderungseinheiten.

Verwenden eines auf kleinere Dokumente ausgerichteten Designs für einen höheren Durchsatz

Der Anforderungsaufwand (also die Kosten für die Anforderungsverarbeitung) eines Vorgangs hängt direkt mit der Größe des Dokuments zusammen. Vorgänge für große Dokumente sind teurer als Vorgänge für kleine Dokumente.

Nächste Schritte

Eine Beispielanwendung zur Evaluierung von Azure Cosmos DB für Hochleistungsszenarien auf einigen Clientcomputern finden Sie unter Leistungs- und Skalierungstests mit Azure Cosmos DB.

Weitere Informationen zum Entwerfen einer auf Skalierung und hohe Leistung ausgelegten Anwendung finden Sie unter Partitionieren und Skalieren in Azure Cosmos DB.