Diagnozowanie i rozwiązywanie problemów z powolnymi żądaniami w zestawie SDK platformy .NET usługi Azure Cosmos DB

DOTYCZY: NoSQL

W usłudze Azure Cosmos DB możesz zauważyć powolne żądania. Opóźnienia mogą wystąpić z wielu powodów, takich jak ograniczanie żądań lub sposób projektowania aplikacji. W tym artykule wyjaśniono różne główne przyczyny tego problemu.

Zbyt duża liczba żądań

Ograniczanie żądań jest najczęstszą przyczyną wolnych żądań. Usługa Azure Cosmos DB ogranicza żądania, jeśli przekraczają przydzielone jednostki żądania dla bazy danych lub kontenera. Zestaw SDK ma wbudowaną logikę, aby ponowić próby tych żądań. W artykule dotyczącym rozwiązywania problemów zbyt duży współczynnik żądań wyjaśniono, jak sprawdzić, czy żądania są ograniczane. W tym artykule omówiono również sposób skalowania konta w celu uniknięcia tych problemów w przyszłości.

Projekt aplikacji

Podczas projektowania aplikacji postępuj zgodnie z najlepszymi rozwiązaniami dotyczącymi zestawu SDK platformy .NET , aby uzyskać najlepszą wydajność. Jeśli aplikacja nie stosuje najlepszych rozwiązań dotyczących zestawu SDK, żądania mogą być powolne lub nieudane.

Podczas tworzenia aplikacji należy wziąć pod uwagę następujące kwestie:

Operacje metadanych

Jeśli musisz sprawdzić, czy baza danych lub kontener istnieje, nie należy tego robić przez wywołanie Create...IfNotExistsAsync ani Read...Async przed wykonaniem operacji elementu. Walidacja powinna być wykonywana tylko podczas uruchamiania aplikacji, jeśli jest to konieczne, jeśli spodziewasz się ich usunięcia. Te operacje metadanych generują dodatkowe opóźnienia, nie mają umowy dotyczącej poziomu usług (SLA) i mają własne oddzielne ograniczenia. Nie są one skalowane w taki sposób, jak operacje na danych.

Powolne żądania w trybie zbiorczym

Tryb zbiorczy jest trybem zoptymalizowanym pod kątem przepływności przeznaczonym dla operacji o dużej ilości danych, a nie w trybie zoptymalizowanym pod kątem opóźnienia; ma na celu nasycenie dostępnej przepływności. Jeśli podczas korzystania z trybu zbiorczego występują powolne żądania, upewnij się, że:

  • Aplikacja jest kompilowana w konfiguracji wydania.
  • Nie mierzysz opóźnienia podczas debugowania aplikacji (bez dołączonych debugerów).
  • Ilość operacji jest duża, nie używaj zbiorczo dla mniej niż 1000 operacji. Aprowizowana przepływność określa liczbę operacji na sekundę, które można przetworzyć, a twoim celem jest zbiorcze wykorzystanie jak największej ilości operacji.
  • Monitorowanie kontenera pod kątem scenariuszy ograniczania przepustowości. Jeśli kontener jest coraz intensywnie ograniczany, oznacza to, że ilość danych jest większa niż aprowizowana przepływność, musisz skalować kontener w górę lub zmniejszyć ilość danych (może utworzyć mniejsze partie danych naraz).
  • Prawidłowo używasz wzorca do przetwarzania async/awaitwszystkich współbieżnych zadań i nie blokujesz żadnej operacji asynchronicznych.

Przechwytywanie danych diagnostycznych

Wszystkie odpowiedzi w zestawie SDK, w tym CosmosException, mają Diagnostics właściwość . Ta właściwość rejestruje wszystkie informacje związane z pojedynczym żądaniem, w tym w przypadku ponownych prób lub błędów przejściowych.

Diagnostyka jest zwracana jako ciąg. Ciąg zmienia się wraz z każdą wersją, ponieważ został ulepszony w celu rozwiązywania problemów z różnymi scenariuszami. W przypadku każdej wersji zestawu SDK ciąg będzie miał zmiany powodujące niezgodność w formatowaniu. Nie analizujej ciągu, aby uniknąć zmian powodujących niezgodność. Poniższy przykładowy kod pokazuje, jak odczytywać dzienniki diagnostyczne przy użyciu zestawu SDK platformy .NET:

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

Diagnostyka w wersji 3.19 lub nowszej

Struktura JSON ma zmiany powodujące niezgodność z każdą wersją zestawu SDK. To sprawia, że niebezpieczne jest analizowanie. Kod JSON reprezentuje strukturę drzewa żądania przechodzącą przez zestaw SDK. W poniższych sekcjach omówiono kilka kluczowych kwestii, na które należy zwrócić uwagę.

Historia procesora CPU

Wysokie wykorzystanie procesora CPU jest najczęstszą przyczyną wolnych żądań. Aby uzyskać optymalne opóźnienie, użycie procesora powinno wynosić około 40%. Użyj interwału 10 sekund, aby monitorować maksymalne (a nie średnie) użycie procesora. Skoki użycia procesora CPU są bardziej typowe w przypadku zapytań obejmujących wiele partycji, w których żądania mogą wykonywać wiele połączeń dla pojedynczego zapytania.

Limity czasu obejmują diagnostykę, która zawiera następujące elementy, na przykład:

"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",
....
}

},
...
]
  • cpu Jeśli wartości są powyżej 70 procent, limit czasu może być spowodowany wyczerpaniem procesora CPU. W takim przypadku rozwiązaniem jest zbadanie źródła dużego użycia procesora CPU i zmniejszenie go lub przeskalowanie maszyny do większego rozmiaru zasobów.
  • threadInfo/isThreadStarving Jeśli węzły mają True wartości, przyczyną jest głód wątku. W takim przypadku rozwiązaniem jest zbadanie źródła lub źródeł głodu wątku (potencjalnie zablokowanych wątków) lub skalowanie maszyny lub maszyn do większego rozmiaru zasobu.
  • dateUtc Jeśli czas między pomiarami nie wynosi około 10 sekund, wskazuje również rywalizację o pulę wątków. Procesor CPU jest mierzony jako niezależne zadanie, które jest w kolejce w puli wątków co 10 sekund. Jeśli czas między pomiarami jest dłuższy, oznacza to, że zadania asynchroniczne nie mogą być przetwarzane w sposób terminowy. Najbardziej typowym scenariuszem jest to, że kod aplikacji blokuje wywołania za pośrednictwem kodu asynchronicznego.

Rozwiązanie

Aplikacja kliencka korzystająca z zestawu SDK powinna zostać przeskalowana w górę lub w poziomie.

HttpResponseStats

HttpResponseStats to żądania, które przechodzą do bramy. Nawet w trybie bezpośrednim zestaw SDK pobiera wszystkie informacje o metadanych z bramy.

Jeśli żądanie jest powolne, najpierw sprawdź, czy żadna z poprzednich sugestii nie daje żądanych wyników. Jeśli nadal działa wolno, różne wzorce wskazują na różne problemy. Poniższa tabela zawiera więcej szczegółów.

Liczba żądań Scenariusz Opis
Jeden do wszystkich Limit czasu żądania lub HttpRequestExceptions Wskazuje na wyczerpanie portów SNAT lub brak zasobów na maszynie w celu przetworzenia żądania w czasie.
Pojedynczy lub niewielki procent (umowa SLA nie jest naruszona) Wszystko Pojedynczy lub niewielki procent wolnych żądań może być spowodowany kilkoma różnymi przejściowymi problemami i powinien być oczekiwany.
Wszystko Wszystko Wskazuje na problem z infrastrukturą lub siecią.
Umowa SLA naruszona Brak zmian w aplikacji i umowa SLA została porzucona. Wskazuje na problem z usługą Azure Cosmos DB.
"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 reprezentuje pojedyncze żądanie do usługi Azure Cosmos DB przy użyciu trybu bezpośredniego z protokołem TCP.

Jeśli nadal działa wolno, różne wzorce wskazują na różne problemy. Poniższa tabela zawiera więcej szczegółów.

Liczba żądań Scenariusz Opis
Jeden do wszystkich StoreResult Zawiera TransportException Wskazuje na wyczerpanie portów SNAT lub brak zasobów na maszynie w celu przetworzenia żądania w czasie.
Pojedynczy lub niewielki procent (umowa SLA nie jest naruszona) Wszystko Pojedynczy lub niewielki procent wolnych żądań może być spowodowany kilkoma różnymi przejściowymi problemami i powinien być oczekiwany.
Wszystko Wszystko Problem z infrastrukturą lub siecią.
Umowa SLA naruszona Żądania zawierają wiele kodów błędów błędów, takich jak 410 Wskazuje na problem z usługą Azure Cosmos DB lub maszyną kliencką.
Umowa SLA naruszona StorePhysicalAddress są takie same, bez kodu stanu błędu. Prawdopodobnie występuje problem z usługą Azure Cosmos DB.
Umowa SLA naruszona StorePhysicalAddress mają ten sam identyfikator partycji, ale różne identyfikatory replik bez kodu stanu błędu. Prawdopodobnie występuje problem z usługą Azure Cosmos DB.
Umowa SLA naruszona StorePhysicalAddress jest losowy, bez kodu stanu błędu. Wskazuje na problem z maszyną.

W przypadku wielu wyników magazynu dla pojedynczego żądania należy pamiętać o następujących kwestiach:

  • Silna spójność i powiązana spójność nieaktualności zawsze mają co najmniej dwa wyniki magazynu.
  • Sprawdź kod stanu każdego StoreResultelementu . Zestaw SDK ponawia próbę automatycznie na wielu różnych błędach przejściowych. Zestaw SDK jest stale ulepszany w celu pokrycia większej liczby scenariuszy.

RequestTimeline

Pokaż czas na różne etapy wysyłania i odbierania żądania w warstwie transportu.

  • ChannelAcquisitionStarted: czas na pobranie lub utworzenie nowego połączenia. Połączenia można utworzyć z wielu powodów, takich jak: Poprzednie połączenie zostało zamknięte z powodu braku aktywności przy użyciu elementu CosmosClientOptions.IdleTcpConnectionTimeout, liczba współbieżnych żądań przekracza wartość CosmosClientOptions.MaxRequestsPerTcpConnection, połączenie zostało zamknięte z powodu błędu sieciowego lub aplikacja nie jest stale tworzona zgodnie ze wzorcem singleton , a nowe wystąpienia są stale tworzone. Po nawiązaniu połączenia jest ono ponownie używane dla kolejnych żądań, więc nie powinno to mieć wpływu na opóźnienie P99, chyba że występują wcześniej wymienione problemy.
  • Pipelined czas jest duży, może być spowodowany dużym żądaniem.
  • Transit time jest duży, co prowadzi do problemu z siecią. Porównaj tę liczbę z .BELatencyInMs Jeśli BELatencyInMs jest mała, to czas spędzony w sieci, a nie w usłudze Azure Cosmos DB.
  • Received czas jest duży może być spowodowany problemem z głodem wątku. Jest to czas między otrzymaniem odpowiedzi a zwróceniem wyniku.

ServiceEndpointStatistics

Informacje o określonym serwerze zaplecza. Zestaw SDK może otwierać wiele połączeń z jednym serwerem zaplecza w zależności od liczby oczekujących żądań i maxConcurrentRequestsPerConnection.

  • inflightRequests Liczba oczekujących żądań na serwer zaplecza (może z różnych partycji). Duża liczba może prowadzić do większego ruchu i większych opóźnień.
  • openConnections to łączna liczba połączeń otwartych dla pojedynczego serwera zaplecza. Może to być przydatne, aby pokazać wyczerpanie portów SNAT, jeśli ta liczba jest bardzo wysoka.

Statystyki połączeń

Informacje o konkretnym połączeniu (nowym lub starym), do którego zostanie przypisane żądanie.

  • waitforConnectionInit: Bieżące żądanie czekało na ukończenie nowej inicjowania połączenia. Doprowadzi to do wyższych opóźnień.
  • callsPendingReceive: liczba wywołań oczekujących na odebranie przed wysłaniem tego połączenia. Duża liczba może pokazać nam, że było wiele połączeń przed tym wywołaniem i może to prowadzić do wyższych opóźnień. Jeśli ta liczba jest duża, wskazuje na problem z blokowaniem wiersza prawdopodobnie spowodowany przez inne żądanie, takie jak zapytanie lub operacja kanału informacyjnego, która trwa długo. Spróbuj zmniejszyć liczbę kanałów CosmosClientOptions.MaxRequestsPerTcpConnection.
  • LastSentTime: Czas ostatniego żądania wysłanego na ten serwer. Może to być używane wraz z lastReceivedTime w celu wyświetlenia problemów z łącznością lub punktem końcowym. Jeśli na przykład istnieje wiele limitów czasu odbierania, czas wysyłania będzie znacznie większy niż czas odbierania.
  • lastReceive: Czas ostatniego żądania odebranego z tego serwera
  • lastSendAttempt: Godzina ostatniej próby wysłania

Rozmiary żądań i odpowiedzi

  • requestSizeInBytes: całkowity rozmiar żądania wysłanego do usługi Azure Cosmos DB
  • responseMetadataSizeInBytes: rozmiar nagłówków zwracanych z usługi Azure Cosmos DB
  • responseBodySizeInBytes: rozmiar zawartości zwróconej z usługi Azure Cosmos DB
"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
}

Współczynnik niepowodzeń narusza umowę SLA usługi Azure Cosmos DB

Skontaktuj się z pomoc techniczna platformy Azure.

Następne kroki

  • Diagnozowanie i rozwiązywanie problemów podczas korzystania z zestawu .NET SDK usługi Azure Cosmos DB.
  • Dowiedz się więcej o wytycznych dotyczących wydajności zestawu .NET SDK.
  • Dowiedz się więcej o najlepszych rozwiązaniach dotyczących zestawu .NET SDK