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ą powolnych żą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 z zbyt dużą szybkością żą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 jest zgodna z najlepszymi rozwiązaniami dotyczącymi zestawu SDK, żądania mogą być powolne lub nieudane.
Podczas tworzenia aplikacji należy wziąć pod uwagę następujące kwestie:
- Aplikacja powinna znajdować się w tym samym regionie co konto usługi Azure Cosmos DB.
- Region aplikacji lub ApplicationPreferredRegions powinien odzwierciedlać preferencje regionalne i wskazać region, w którym aplikacja jest wdrożona.
- Może wystąpić wąskie gardło w interfejsie sieciowym z powodu dużego ruchu. Jeśli aplikacja jest uruchomiona w usłudze Azure Virtual Machines, istnieją możliwe obejścia:
- Rozważ użycie maszyny wirtualnej z włączoną przyspieszoną siecią.
- Włącz przyspieszoną sieć na istniejącej maszynie wirtualnej.
- Rozważ użycie wyższej maszyny wirtualnej.
- Preferuj tryb łączności bezpośredniej.
- Unikaj wysokiego użycia procesora CPU. Pamiętaj, aby przyjrzeć się maksymalnemu procesorowi CPU, a nie średniej, która jest wartością domyślną dla większości systemów rejestrowania. Wszystkie elementy powyżej około 40 procent mogą zwiększyć opóźnienie.
Operacje na metadanych
Jeśli musisz sprawdzić, czy baza danych lub kontener istnieje, nie należy tego robić przez wywołanie Create...IfNotExistsAsync
lub Read...Async
przed wykonaniem operacji elementu. Walidację należy wykonać 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ą skalowane tak jak operacje na danych.
Wolne żą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óźnień. Ma to 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).
- Liczba operacji jest duża, nie używaj zbiorczo dla mniej niż 1000 operacji. Aprowizowana przepływność określa, ile operacji na sekundę można przetworzyć. Celem operacji zbiorczych byłoby wykorzystanie jak największej ilości operacji.
- Monitoruj kontener 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
async/await
wzorca do przetwarzania wszystkich współbieżnych zadań i nie blokuje ż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 do 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 analizuj 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 zawiera zmiany powodujące niezgodność z każdą wersją zestawu SDK. To sprawia, że niebezpieczne jest analizowanie. Kod JSON reprezentuje strukturę drzewa żądania przechodzącego 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ą częściej spotykane 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ą ponad 70 procent, limit czasu prawdopodobnie będzie 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.- Jeśli węzły
threadInfo/isThreadStarving
mająTrue
wartości, przyczyną jest głodowanie 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 do większego rozmiaru zasobów. dateUtc
Jeśli czas między pomiarami nie wynosi około 10 sekund, wskazuje również rywalizację w puli 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 odpowiednim czasie. 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 pożą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. |
Pojedyncza lub niewielka wartość procentowa (umowa SLA nie jest naruszona) | wszystkie | Pojedynczy lub niewielki procent wolnych żądań może być spowodowany kilkoma różnymi przejściowymi problemami i powinien być oczekiwany. |
wszystkie | wszystkie | Wskazuje na problem z infrastrukturą lub siecią. |
Naruszono umowę SLA | Nie wprowadzono żadnych 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 Contains TransportException |
Wskazuje na wyczerpanie portów SNAT lub brak zasobów na maszynie w celu przetworzenia żądania w czasie. |
Pojedyncza lub niewielka wartość procentowa (umowa SLA nie jest naruszona) | wszystkie | Pojedynczy lub niewielki procent wolnych żądań może być spowodowany kilkoma różnymi przejściowymi problemami i powinien być oczekiwany. |
wszystkie | wszystkie | Problem z infrastrukturą lub siecią. |
Naruszono umowę SLA | Żą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ą. |
Naruszono umowę SLA | StorePhysicalAddress są takie same, bez kodu stanu błędu. |
Prawdopodobnie występuje problem z usługą Azure Cosmos DB. |
Naruszono umowę SLA | 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. |
Naruszono umowę SLA | StorePhysicalAddress jest losowy, bez kodu stanu błędu. |
Wskazuje na problem z maszyną. |
W przypadku wielu wyników magazynu dla jednego żą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 przechowywania.
- Sprawdź kod stanu każdego
StoreResult
elementu . Zestaw SDK ponawia próby automatycznie na wielu różnych błędach przejściowych. Zestaw SDK jest stale ulepszany, aby uwzględnić więcej scenariuszy.
RequestTimeline
Pokaż czas dla różnych etapów 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 spędzony na zapisaniu żądania do gniazda TCP. Żądanie można zapisywać tylko na gniazdach TCP pojedynczo. Duża wartość wskazuje wąskie gardło gniazda TCP, które jest często skojarzone z zablokowanymi wątkami przez kod aplikacji lub duże żądania.Transit time
: czas spędzony w sieci po zapisaniu żądania w gniazdie TCP. Porównaj tę liczbę z .BELatencyInMs
JeśliBELatencyInMs
jest mały, to czas spędzony w sieci, a nie w usłudze Azure Cosmos DB. Jeśli żądanie nie powiodło się z przekroczeniem limitu czasu, wskazuje, jak długo klient czekał bez odpowiedzi, a źródłem jest opóźnienie sieci.Received
: czas między odebraniem odpowiedzi a przetworzeniem przez zestaw SDK. Duża wartość jest zwykle spowodowana głodem wątku lub zablokowanymi wątkami.
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 całkowita 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.
ConnectionStatistics
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 wywołań 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 operacja zapytania lub 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. Ta funkcja wraz z elementem LastReceivedTime może służyć do wyświetlenia problemów z łącznością lub punktem końcowym. Jeśli na przykład istnieje wiele limitów czasu odbierania, czas wysłania będzie znacznie większy niż czas odbierania.lastReceive
: Czas ostatniego żądania odebranego z tego serweralastSendAttempt
: Godzina ostatniej próby wysłania
Rozmiary żądań i odpowiedzi
requestSizeInBytes
: całkowity rozmiar żądania wysłanego do usługi Azure Cosmos DBresponseMetadataSizeInBytes
: rozmiar nagłówków zwracanych z usługi Azure Cosmos DBresponseBodySizeInBytes
: rozmiar zawartości zwracanej 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