Diagnose und Fehlerbehebung bei langsamen Anforderungen in Azure Cosmos DB .NET SDK

GILT FÜR: NoSQL

In Azure Cosmos DB bemerken Sie möglicherweise langsame Anforderungen. Verzögerungen können aus verschiedenen Gründen auftreten, z. B. durch die Drosselung von Anforderungen oder die Art und Weise, wie Ihre Anwendung konzipiert ist. Dieser Artikel erklärt die verschiedenen Ursachen für dieses Problem.

Anforderungsrate zu groß

Die Einschränkung von Anforderungen ist der häufigste Grund für langsame Anforderungen. Azure Cosmos DB drosselt Anforderungen, wenn sie die zugewiesenen Anforderungseinheiten für die Datenbank oder den Container überschreiten. Das SDK verfügt über eine integrierte Logik zur Wiederholung dieser Anforderungen. Der Artikel zur Problembehandlung bei zu hoher Anforderungsrate erklärt, wie Sie überprüfen können, ob die Anforderungen gedrosselt werden. In diesem Artikel wird auch erläutert, wie Sie Ihr Konto skalieren, um diese Probleme in Zukunft zu vermeiden.

Anwendungsentwurf

Wenn Sie Ihre Anwendung entwerfen, befolgen Sie die bewährten Methoden für das .NET SDK, um die beste Leistung zu erzielen. Wenn Ihre Anwendung die SDK Best Practices nicht befolgt, kann es zu langsamen oder fehlgeschlagenen Anforderungen kommen.

Beachten Sie bei der Entwicklung Ihrer Anwendung die folgenden Punkte:

Metadatenvorgänge

Wenn Sie überprüfen müssen, ob eine Datenbank oder ein Container vorhanden ist, rufen Sie Create...IfNotExistsAsync oder Read...Async nicht auf, bevor Sie einen Elementvorgang durchführen. Die Validierung sollte nur beim Start der Anwendung erfolgen, wenn Sie erwarten, dass sie gelöscht werden. Diese Metadatenvorgänge generieren zusätzliche Latenz, verfügen über keine Vereinbarung zum Servicelevel (SLA) und verfügen über eigene separate Einschränkungen. Sie werden nicht wie Datenvorgänge skaliert.

Langsame Anforderungen im Massenmodus

Der Massenmodus ist ein durchsatzoptimierter Modus, der für Vorgänge mit hohem Datenvolumen und nicht für latenzoptimierte Vorgänge bestimmt ist. Er soll den verfügbaren Durchsatz ausnutzen. Wenn Sie bei der Verwendung des Massenmodus bemerken, dass Anforderungen langsam sind, stellen Sie Folgendes sicher:

  • Ihre Anwendung ist in der Releasekonfiguration kompiliert.
  • Beim Debuggen der Anwendung wird die Latenz nicht gemessen (es sind keine Debugger angefügt).
  • Das Volumen der Vorgänge ist hoch. Verwenden Sie den Massenmodus nicht für weniger als 1.000 Vorgänge. Der bereitgestellte Durchsatz bestimmt, wie viele Vorgänge pro Sekunde verarbeitet werden können. Das Ziel beim Massenmodus ist die höchstmögliche Auslastung.
  • Überwachen Sie den Container auf Drosselungsszenarien. Wenn der Container stark gedrosselt wird, bedeutet das, dass die Datenmenge größer als der bereitgestellte Durchsatz ist. Sie müssen den Container entweder hochskalieren oder die Datenmenge reduzieren (vielleicht erstellen Sie jeweils kleinere Datenbatches).
  • Sie verwenden das Muster async/await ordnungsgemäß, um alle gleichzeitigen Aufgaben zu verarbeiten, und Sie blockieren keine asynchronen Vorgänge.

Capture-Diagnose

Alle Antworten im SDK, einschließlich CosmosException, haben eine Diagnostics-Eigenschaft. In dieser Eigenschaft werden alle Informationen zu einer einzelnen Anforderung aufgezeichnet, unter anderem auch, ob es Wiederholungsversuche oder vorübergehende Fehler gab.

Die Diagnosen werden als Zeichenfolge zurückgegeben. Der String ändert sich mit jeder Version, da er für die Fehlersuche in verschiedenen Szenarien verbessert wurde. Mit jeder Version des SDK wird die Formatierung der Zeichenfolge geändert. Analysieren Sie die Zeichenfolge nicht, um Breaking Changes zu vermeiden. Das folgende Codebeispiel zeigt, wie Diagnoseprotokolle mit dem .NET SDK gelesen werden:

try
{
    ItemResponse<Book> response = await this.Container.CreateItemAsync<Book>(item: testItem);
    if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan)
    {
        // Log the response.Diagnostics.ToString() and add any additional info necessary to correlate to other logs 
    }
}
catch (CosmosException cosmosException)
{
    // Log the full exception including the stack trace with: cosmosException.ToString()
    
    // The Diagnostics can be logged separately if required with: cosmosException.Diagnostics.ToString()
}

// When using Stream APIs
ResponseMessage response = await this.Container.CreateItemStreamAsync(partitionKey, stream);
if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan || !response.IsSuccessStatusCode)
{
    // Log the diagnostics and add any additional info necessary to correlate to other logs with: response.Diagnostics.ToString()
}

Diagnostik in Version 3.19 und höher

Die JSON-Struktur hat sich mit jeder Version des SDK geändert. Das macht sie unsicher beim Parsen. Das JSON stellt eine Baumstruktur der Anforderungen dar, die das SDK durchlaufen. In den folgenden Abschnitten werden einige wichtige Punkte behandelt.

CPU-Verlauf

Eine hohe CPU-Auslastung ist die häufigste Ursache für langsame Anforderungen. Für optimale Latenz sollte die CPU-Auslastung ungefähr 40 Prozent betragen. Verwenden Sie 10 Sekunden als Intervall zur Überwachung der maximalen (nicht durchschnittlichen) CPU-Nutzung. CPU-Spitzen treten häufiger bei partitionsübergreifenden Abfragen auf, bei denen die Anforderungen möglicherweise mehrere Konnektivitäten für eine einzige Abfrage erfordern.

Zu den Timeouts gehört die Diagnose, die Folgendes enthält, z. B.:

"systemHistory": [
{
"dateUtc": "2021-11-17T23:38:28.3115496Z",
"cpu": 16.731,
"memory": 9024120.000,
"threadInfo": {
"isThreadStarving": "False",
....
}

},
{
"dateUtc": "2021-11-17T23:38:38.3115496Z",
"cpu": 16.731,
"memory": 9024120.000,
"threadInfo": {
"isThreadStarving": "False",
....
}

},
...
]
  • Wenn die cpu-Werte über 70 Prozent liegen, ist die Zeitüberschreitung wahrscheinlich auf eine Erschöpfung der CPU zurückzuführen. In diesem Fall besteht die Lösung darin, die Quelle für die hohe CPU-Auslastung zu ermitteln und für eine Reduzierung zu sorgen oder die Ressourcengröße für den Computer zu erhöhen.
  • Wenn die threadInfo/isThreadStarving-Knoten True-Werte enthalten, ist die Ursache Threadmangel. In diesem Fall besteht die Lösung darin, die Quelle(n) des Threadmangels (möglicherweise gesperrte Threads) zu untersuchen oder den oder die Rechner auf eine größere Ressourcengröße zu skalieren.
  • Wenn die dateUtc-Zeit zwischen den Messungen nicht etwa 10 Sekunden beträgt, deutet dies ebenfalls auf eine Konkurrenzsituation im Thread-Pool hin. Die CPU wird als eine unabhängige Aufgabe gemessen, die alle 10 Sekunden in den Thread-Pool eingereiht wird. Wenn die Zeit zwischen den Messungen länger ist, gibt dies an, dass die asynchronen Aufgaben nicht rechtzeitig verarbeitet werden können. Das häufigste Szenario ist, dass Ihr Anwendungscode Aufrufe über asynchronen Code blockiert.

Lösung

Die Clientanwendung, die das SDK verwendet, sollte entsprechend skaliert werden.

HttpResponseStats

HttpResponseStats sind Anforderungen, die an das Gateway gerichtet werden. Selbst im direkten Modus erhält das SDK alle Metadaten vom Gateway.

Wenn die Anforderung langsam ist, überprüfen Sie zunächst, ob keiner der vorherigen Vorschläge die gewünschten Ergebnisse liefert. Wenn es immer noch langsam ist, deuten verschiedene Muster auf verschiedene Probleme hin. Die folgende Tabelle enthält weitere Einzelheiten.

Anzahl von Anforderungen Szenario BESCHREIBUNG
Einzeln bis alle Anforderungstimeout oder HttpRequestExceptions Weist darauf hin, dass der SNAT-Port erschöpft ist oder dass die Ressourcen des Rechners nicht ausreichen, um die Anforderung rechtzeitig zu bearbeiten.
Einzelner oder kleiner Prozentsatz (SLA wird nicht verletzt) Alle Ein einzelner oder kleiner Prozentsatz langsamer Anforderungen kann durch verschiedene vorübergehende Probleme verursacht werden und sollte erwartet werden.
All All Weist auf ein Problem mit der Infrastruktur oder dem Netzwerk hin.
SLA-Verletzung Keine Änderungen an der Anwendung und SLA verworfen Weist auf ein Problem mit dem Azure Cosmos DB-Dienst hin.
"HttpResponseStats": [
    {
        "StartTimeUTC": "2021-06-15T13:53:09.7961124Z",
        "EndTimeUTC": "2021-06-15T13:53:09.7961127Z",
        "RequestUri": "https://127.0.0.1:8081/dbs/347a8e44-a550-493e-88ee-29a19c070ecc/colls/4f72e752-fa91-455a-82c1-bf253a5a3c4e",
        "ResourceType": "Collection",
        "HttpMethod": "GET",
        "ActivityId": "e16e98ec-f2e3-430c-b9e9-7d99e58a4f72",
        "StatusCode": "OK"
    }
]

StoreResult

StoreResult stellt eine einzelne Anforderung an Azure Cosmos DB dar, indem der direkte Modus mit dem TCP-Protokoll verwendet wird.

Wenn es immer noch langsam ist, deuten verschiedene Muster auf verschiedene Probleme hin. Die folgende Tabelle enthält weitere Einzelheiten.

Anzahl von Anforderungen Szenario BESCHREIBUNG
Einzeln bis alle StoreResult enthält TransportException Weist darauf hin, dass der SNAT-Port erschöpft ist oder dass die Ressourcen des Rechners nicht ausreichen, um die Anforderung rechtzeitig zu bearbeiten.
Einzelner oder kleiner Prozentsatz (SLA wird nicht verletzt) Alle Ein einzelner oder kleiner Prozentsatz langsamer Anforderungen kann durch verschiedene vorübergehende Probleme verursacht werden und sollte erwartet werden.
All Alle Ein Problem mit der Infrastruktur oder dem Netzwerk.
SLA-Verletzung Anforderungen enthalten mehrere Fehlercodes, wie 410. Verweist auf ein Problem mit dem Azure Cosmos DB-Dienst oder dem Clientcomputer.
SLA-Verletzung StorePhysicalAddress sind identisch, ohne Fehlerstatuscode. Wahrscheinlich ein Problem mit Azure Cosmos DB.
SLA-Verletzung StorePhysicalAddress haben dieselbe Partitions-ID, aber unterschiedliche Replikations-IDs, ohne dass ein Fehlerstatuscode vorliegt. Wahrscheinlich ein Problem mit Azure Cosmos DB.
SLA-Verletzung StorePhysicalAddress ist zufällig und hat keinen Fehlerstatuscode. Verweist auf ein Problem mit dem Computer.

Beachten Sie bei mehreren Speicherergebnissen für eine einzelne Anforderung Folgendes:

  • Starke Konsistenz und begrenzte Staleness-Konsistenz haben immer mindestens zwei Speicherergebnisse.
  • Prüfen Sie den Statuscode jedes StoreResult. Das SDK führt bei mehreren verschiedenen vorübergehenden Fehlschlägen automatisch Wiederholungsversuche durch. Das SDK wird ständig verbessert, um mehr Szenarien abzudecken.

RequestTimeline

Zeigt die Zeit für die verschiedenen Phasen des Sendens und Empfangens einer Anforderung in der Datentransportebene an.

  • ChannelAcquisitionStarted: Die Zeit, um eine neue Verbindung zu erhalten oder herzustellen. Verbindungen können aus zahlreichen Gründen erstellt werden, z. B.: Die vorherige Verbindung wurde aufgrund von Inaktivität mit CosmosClientOptions.IdleTcpConnectionTimeout geschlossen, das Volumen gleichzeitiger Anforderungen überschreitet die CosmosClientOptions.MaxRequestsPerTcpConnection, die Verbindung wurde aufgrund eines Netzwerkfehlers geschlossen, oder die Anwendung folgt nicht dem Singleton-Muster , und es werden ständig neue Instanzen erstellt. Sobald eine Verbindung hergestellt wurde, wird sie für nachfolgende Anforderungen wiederverwendet, sodass sich dies nicht auf die P99-Latenz auswirken sollte, es sei denn, die zuvor erwähnten Probleme treten auf.
  • Die „Pipelined time“ (Pipeline-Zeit) ist groß, was durch eine große Anforderung verursacht werden kann.
  • Die „Transit time“ (Transit-Zeit) ist groß, was zu einem Netzwerkproblem führt. Vergleichen Sie diese Zahl mit der BELatencyInMs. Wenn BELatencyInMs gering ist, wurde die Zeit im Netzwerk verbracht und nicht mit dem Azure Cosmos DB-Dienst.
  • Die „Received time“ (empfangene Zeit) ist groß, was durch ein „Thread-Starvation“-Problem verursacht werden kann. Dies ist die Zeit zwischen dem Erhalt der Antwort und der Rückgabe des Ergebnisses.

ServiceEndpointStatistics

Informationen zu einem bestimmten Back-End-Server. Das SDK kann mehrere Verbindungen zu einem einzelnen Back-End-Server öffnen, abhängig von der Anzahl der ausstehenden Anforderungen und dem Parameter MaxConcurrentRequestsPerConnection.

  • inflightRequests Die Anzahl der ausstehenden Anforderungen an einen Back-End-Server (möglicherweise aus verschiedenen Partitionen). Eine hohe Anzahl kann zu mehr Datenverkehr und höheren Latenzen führen.
  • openConnections ist die Gesamtanzahl der Verbindungen, die für einen einzelnen Back-End-Server geöffnet sind. Dies kann nützlich sein, um die Erschöpfung des SNAT-Ports anzuzeigen, wenn diese Zahl sehr hoch ist.

ConnectionStatistics

Informationen zu der bestimmten Verbindung (neu oder alt) der Anforderung wird zugewiesen.

  • waitforConnectionInit: Die aktuelle Anforderung wartet auf die Initialisierung neuer Verbindungen. Dies führt zu längeren Wartezeiten.
  • callsPendingReceive: Anzahl der Aufrufe, deren Empfang ausstand, bevor dieser Aufruf gesendet wurde. Eine hohe Anzahl kann darauf hinweisen, dass vor diesem Aufruf viele Aufrufe erfolgt sind und dass es zu längeren Wartezeiten kommen kann. Wenn diese Anzahl hoch ist, deutet dies auf ein Head-of-Line-Blockierproblem hin, das möglicherweise durch eine andere Anforderung wie eine Abfrage oder einen Einspeisevorgang verursacht wird, deren Bearbeitung viel Zeit in Anspruch nimmt. Versuchen Sie, die CosmosClientOptions.MaxRequestsPerTcpConnection zu verringern, um die Anzahl der Kanäle zu erhöhen.
  • LastSentTime: Zeitpunkt der letzten Anforderung, die an diesen Server gesendet wurde. Dies zusammen mit LastReceivedTime kann verwendet werden, um Verbindungs- oder Endpunktprobleme zu erkennen. Wenn es beispielsweise viele Empfangstimeouts gibt, dauert das Senden viel länger als das Empfangen.
  • lastReceive: Zeitpunkt der letzten Anforderung, die von diesem Server empfangen wurde
  • lastSendAttempt: Zeitpunkt des letzten Sendeversuchs

Größen von Anforderung und Antwort

  • requestSizeInBytes: Die Gesamtgröße der an Azure Cosmos DB gesendeten Anforderung
  • responseMetadataSizeInBytes: Die Größe der von Azure Cosmos DB zurückgegebenen Header
  • responseBodySizeInBytes: Die Größe des von Azure Cosmos DB zurückgegebenen Inhalts
"StoreResult": {
    "ActivityId": "bab6ade1-b8de-407f-b89d-fa2138a91284",
    "StatusCode": "Ok",
    "SubStatusCode": "Unknown",
    "LSN": 453362,
    "PartitionKeyRangeId": "1",
    "GlobalCommittedLSN": 0,
    "ItemLSN": 453358,
    "UsingLocalLSN": true,
    "QuorumAckedLSN": -1,
    "SessionToken": "-1#453362",
    "CurrentWriteQuorum": -1,
    "CurrentReplicaSetSize": -1,
    "NumberOfReadRegions": 0,
    "IsValid": true,
    "StorePhysicalAddress": "rntbd://127.0.0.1:10253/apps/DocDbApp/services/DocDbServer92/partitions/a4cb49a8-38c8-11e6-8106-8cdcd42c33be/replicas/1s/",
    "RequestCharge": 1,
    "RetryAfterInMs": null,
    "BELatencyInMs": "0.304",
    "transportRequestTimeline": {
        "requestTimeline": [
            {
                "event": "Created",
                "startTimeUtc": "2022-05-25T12:03:36.3081190Z",
                "durationInMs": 0.0024
            },
            {
                "event": "ChannelAcquisitionStarted",
                "startTimeUtc": "2022-05-25T12:03:36.3081214Z",
                "durationInMs": 0.0132
            },
            {
                "event": "Pipelined",
                "startTimeUtc": "2022-05-25T12:03:36.3081346Z",
                "durationInMs": 0.0865
            },
            {
                "event": "Transit Time",
                "startTimeUtc": "2022-05-25T12:03:36.3082211Z",
                "durationInMs": 1.3324
            },
            {
                "event": "Received",
                "startTimeUtc": "2022-05-25T12:03:36.3095535Z",
                "durationInMs": 12.6128
            },
            {
                "event": "Completed",
                "startTimeUtc": "2022-05-25T12:03:36.8621663Z",
                "durationInMs": 0
            }
        ],
        "serviceEndpointStats": {
            "inflightRequests": 1,
            "openConnections": 1
        },
        "connectionStats": {
            "waitforConnectionInit": "False",
            "callsPendingReceive": 0,
            "lastSendAttempt": "2022-05-25T12:03:34.0222760Z",
            "lastSend": "2022-05-25T12:03:34.0223280Z",
            "lastReceive": "2022-05-25T12:03:34.0257728Z"
        },
        "requestSizeInBytes": 447,
        "responseMetadataSizeInBytes": 438,
        "responseBodySizeInBytes": 604
    },
    "TransportException": null
}

Fehlerrate verstößt gegen die Azure Cosmos DB SLA

Kontaktieren Sie den Azure-Support.

Nächste Schritte