Porady dotyczące wydajności usługi Azure Cosmos DB i zestawu .NET SDK w wersji 2
DOTYCZY: NoSQL
Azure Cosmos DB to szybka i elastyczna rozproszona baza danych, która bezproblemowo skaluje się z gwarantowanym opóźnieniem i przepływnością. Nie musisz wprowadzać istotnych zmian architektury ani pisać złożonego kodu w celu skalowania bazy danych za pomocą usługi Azure Cosmos DB. Skalowanie w górę i w dół jest tak proste, jak tworzenie pojedynczego wywołania interfejsu API. Aby dowiedzieć się więcej, zobacz jak aprowizować przepływność kontenera lub jak aprowizować przepływność bazy danych. Jednak ze względu na to, że usługa Azure Cosmos DB jest dostępna za pośrednictwem wywołań sieciowych, można dokonać optymalizacji po stronie klienta, aby osiągnąć szczytową wydajność podczas korzystania z zestawu SQL .NET SDK.
Dlatego jeśli próbujesz poprawić wydajność bazy danych, rozważ następujące opcje:
Uaktualnianie do zestawu SDK platformy .NET w wersji 3
Zestaw SDK platformy .NET w wersji 3 jest udostępniany. Jeśli używasz zestawu .NET v3 SDK, zapoznaj się z przewodnikiem wydajności platformy .NET w wersji 3, aby uzyskać następujące informacje:
- Domyślnie tryb Direct TCP
- Obsługa interfejsu API usługi Stream
- Obsługa niestandardowego serializatora w celu zezwolenia na użycie System.Text.JSON
- Zintegrowana obsługa wsadowa i zbiorcza
Zalecenia dotyczące hostingu
Włączanie odzyskiwania pamięci po stronie serwera (GC)
Zmniejszenie częstotliwości odzyskiwania pamięci może pomóc w niektórych przypadkach. Na platformie .NET ustaw wartość gcServer na true
.
Skalowanie obciążenia klienta w poziomie
Jeśli testujesz na wysokich poziomach przepływności (ponad 50 000 RU/s), aplikacja kliencka może stać się wąskim gardłem spowodowanym ograniczeniem użycia procesora CPU lub sieci przez maszynę. Jeśli osiągniesz ten punkt, możesz kontynuować wypychanie konta usługi Azure Cosmos DB, skalując aplikacje klienckie na wielu serwerach.
Uwaga
Wysokie użycie procesora CPU może spowodować zwiększone opóźnienie i wyjątki limitu czasu żądania.
Operacje na metadanych
Nie należy weryfikować, czy baza danych i/lub kolekcja istnieje przez wywołanie Create...IfNotExistsAsync
metody i/lub Read...Async
w ścieżce gorącej i/lub przed wykonaniem operacji elementu. Walidację należy wykonać tylko podczas uruchamiania aplikacji, jeśli jest to konieczne, jeśli spodziewasz się ich usunięcia (w przeciwnym razie nie jest to konieczne). Te operacje metadanych będą generować dodatkowe kompleksowe opóźnienia, nie mają umowy SLA i własnych oddzielnych ograniczeń, które nie są skalowane, takie jak operacje na danych.
Rejestrowanie i śledzenie
Niektóre środowiska mają włączony element DefaultTraceListener platformy .NET. Element DefaultTraceListener stwarza problemy z wydajnością w środowiskach produkcyjnych powodujących wąskie gardła procesora CPU i we/wy. Sprawdź i upewnij się, że element DefaultTraceListener jest wyłączony dla aplikacji, usuwając go ze środowiska produkcyjnego TraceListeners .
Najnowsze wersje zestawu SDK (nowsze niż 2.16.2) automatycznie usuwają je po wykryciu, ze starszymi wersjami, można je usunąć, wykonując następujące czynności:
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
}
Sieć
Zasady połączeń: użyj trybu połączenia bezpośredniego
Domyślny tryb połączenia zestawu SDK platformy .NET w wersji 2 to brama. Tryb połączenia można skonfigurować podczas konstruowania DocumentClient
wystąpienia przy użyciu parametru ConnectionPolicy
. Jeśli używasz trybu bezpośredniego, należy również ustawić Protocol
parametr przy użyciu parametru ConnectionPolicy
. Aby dowiedzieć się więcej o różnych opcjach łączności, zobacz artykuł Tryby łączności.
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
});
Wyczerpanie portów efemerycznych
Jeśli w wystąpieniach zostanie wyświetlony duży wolumin połączenia lub wysokie użycie portów, najpierw sprawdź, czy wystąpienia klientów są pojedynczymi wystąpieniami. Innymi słowy, wystąpienia klienta powinny być unikatowe przez cały okres istnienia aplikacji.
Podczas uruchamiania w protokole TCP klient optymalizuje opóźnienia przy użyciu długotrwałych połączeń, w przeciwieństwie do protokołu HTTPS, który przerywa połączenia po 2 minutach braku aktywności.
W scenariuszach, w których masz dostęp rozrzedny i jeśli zauważysz większą liczbę połączeń w porównaniu z dostępem w trybie bramy, możesz:
- Skonfiguruj właściwość
PrivatePortPool
ConnectionPolicy.PortReuseMode na (obowiązująca z wersją> platformy= 4.6.1 i platformą .NET Core >= 2.0): ta właściwość umożliwia zestawowi SDK używanie małej puli portów efemerycznych dla różnych punktów końcowych docelowych usługi Azure Cosmos DB. - Skonfiguruj właściwość ConnectionPolicy.IdleConnectionTimeout musi być większa lub równa 10 minutom. Zalecane wartości to od 20 minut do 24 godzin.
Wywołaj metodę OpenAsync, aby uniknąć opóźnienia uruchamiania na pierwszym żądaniu
Domyślnie pierwsze żądanie ma większe opóźnienie, ponieważ musi pobrać tabelę routingu adresów. W przypadku korzystania z zestawu SDK w wersji 2 wywołaj metodę OpenAsync()
raz podczas inicjowania, aby uniknąć tego opóźnienia uruchamiania w pierwszym żądaniu. Wywołanie wygląda następująco: await client.OpenAsync();
Uwaga
OpenAsync
spowoduje wygenerowanie żądań uzyskania tabeli routingu adresów dla wszystkich kontenerów na koncie. W przypadku kont, które mają wiele kontenerów, ale których aplikacja uzyskuje dostęp do podzbioru, OpenAsync
wygeneruje niepotrzebną ilość ruchu, co spowodowałoby spowolnienie inicjowania. Dlatego użycie OpenAsync
może nie być przydatne w tym scenariuszu, ponieważ spowalnia uruchamianie aplikacji.
W celu uzyskania wydajności posuń klientów w tym samym regionie świadczenia usługi Azure
Jeśli to możliwe, umieść wszystkie aplikacje wywołujące usługę Azure Cosmos DB w tym samym regionie co baza danych usługi Azure Cosmos DB. Oto przybliżone porównanie: wywołania usługi Azure Cosmos DB w tym samym regionie są kompletne w ciągu 1 ms do 2 ms, ale opóźnienie między zachodnim i wschodnim wybrzeżem USA wynosi ponad 50 ms. To opóźnienie może się różnić od żądania, w zależności od trasy podjętej przez żądanie, gdy przechodzi od klienta do granicy centrum danych platformy Azure. Aby uzyskać najmniejsze możliwe opóźnienie, upewnij się, że aplikacja wywołująca znajduje się w tym samym regionie świadczenia usługi Azure, co aprowizowany punkt końcowy usługi Azure Cosmos DB. Aby uzyskać listę dostępnych regionów, zobacz Regiony świadczenia usługi Azure.
Zwiększanie liczby wątków/zadań
Ponieważ wywołania usługi Azure Cosmos DB są wykonywane za pośrednictwem sieci, może być konieczne zmianę stopnia równoległości żądań, aby aplikacja kliencka spędzała minimalny czas oczekiwania między żądaniami. Jeśli na przykład używasz biblioteki równoległej zadań platformy .NET, utwórz je w kolejności setek zadań odczytywanych z usługi Azure Cosmos DB lub zapisu.
Włączanie przyspieszonej sieci
Aby zmniejszyć opóźnienia i zakłócenia procesora CPU, zalecamy włączenie przyspieszonej sieci na maszynach wirtualnych klienckich. Zobacz Tworzenie maszyny wirtualnej z systemem Windows z przyspieszoną siecią lub Tworzenie maszyny wirtualnej z systemem Linux z przyspieszoną siecią.
SDK usage (Użycie zestawu SDK)
Instalowanie najnowszego zestawu SDK
Zestawy SDK usługi Azure Cosmos DB są stale ulepszane, aby zapewnić najlepszą wydajność. Zobacz strony zestawu SDK usługi Azure Cosmos DB, aby określić najnowszy zestaw SDK i przejrzeć ulepszenia.
Używanie pojedynczego klienta usługi Azure Cosmos DB przez cały okres istnienia aplikacji
Każde DocumentClient
wystąpienie jest bezpieczne wątkowo i wykonuje wydajne zarządzanie połączeniami i buforowanie adresów podczas pracy w trybie bezpośrednim. Aby umożliwić wydajne zarządzanie połączeniami i lepszą wydajność klienta zestawu SDK, zalecamy użycie pojedynczego wystąpienia na AppDomain
okres istnienia aplikacji.
Unikaj blokowania wywołań
Zestaw SDK usługi Azure Cosmos DB powinien być zaprojektowany tak, aby przetwarzał wiele żądań jednocześnie. Asynchroniczne interfejsy API umożliwiają małą pulę wątków do obsługi tysięcy współbieżnych żądań, nie czekając na wywołania blokujące. Zamiast czekać na wykonanie długotrwałego zadania synchronicznego, wątek może pracować nad innym żądaniem.
Typowym problemem z wydajnością aplikacji korzystających z zestawu SDK usługi Azure Cosmos DB jest blokowanie wywołań, które mogą być asynchroniczne. Wiele synchronicznych wywołań blokowania prowadzi do głodu puli wątków i obniżonych czasów odpowiedzi.
Nie:
- Blokuj wykonywanie asynchroniczne, wywołując metodę Task.Wait lub Task.Result.
- Użyj elementu Task.Run , aby utworzyć asynchroniczny interfejs API synchroniczny.
- Uzyskiwanie blokad w typowych ścieżkach kodu. Zestaw .NET SDK usługi Azure Cosmos DB jest najbardziej wydajny podczas tworzenia architektury do równoległego uruchamiania kodu.
- Wywołaj polecenie Task.Run i natychmiast go zaczekaj. ASP.NET Core uruchamia już kod aplikacji w normalnych wątkach puli wątków, więc wywołanie task.Run powoduje jedynie dodatkowe niepotrzebne planowanie puli wątków. Nawet jeśli zaplanowany kod zablokuje wątek, polecenie Task.Run nie zapobiega temu.
- Użyj metody ToList(), w
DocumentClient.CreateDocumentQuery(...)
której używane są wywołania blokujące w celu synchronicznego opróżniania zapytania. Użyj metody AsDocumentQuery(), aby opróżnić zapytanie asynchronicznie.
Część praktyczna:
- Asynchronicznie wywołaj interfejsy API platformy .NET usługi Azure Cosmos DB.
- Cały stos wywołań jest asynchroniczny, aby korzystać z wzorców asynchronicznych/await .
Profiler, taki jak PerfView, może służyć do znajdowania wątków często dodawanych do puli wątków. Zdarzenie Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start
wskazuje wątek dodany do puli wątków.
Zwiększ System.Net maxConnections na hosta podczas korzystania z trybu bramy
Żądania usługi Azure Cosmos DB są wysyłane za pośrednictwem protokołu HTTPS/REST podczas korzystania z trybu bramy. Podlegają one domyślnemu limitowi połączeń na nazwę hosta lub adres IP. Może być konieczne ustawienie MaxConnections
wartości wyższej (od 100 do 1000), aby biblioteka kliencka mogła używać wielu równoczesnych połączeń z usługą Azure Cosmos DB. W zestawie .NET SDK 1.8.0 lub nowszym wartość domyślna parametru ServicePointManager.DefaultConnectionLimit to 50. Aby zmienić wartość, możesz ustawić wartość Documents.Client.ConnectionPolicy.MaxConnectionLimit na wyższą wartość.
Implementowanie wycofywania w interwałach ponawiania prób
Podczas testowania wydajności należy zwiększyć obciążenie do momentu ograniczenia niewielkiej liczby żądań. Jeśli żądania są ograniczane, aplikacja kliencka powinna wycofać się z ograniczania dla interwału ponawiania określonego przez serwer. Przestrzeganie wycofywania gwarantuje, że spędzasz minimalny czas oczekiwania między ponawianiem prób.
Obsługa zasad ponawiania prób jest uwzględniona w następujących zestawach SDK:
- Wersja 1.8.0 lub nowsza zestawu .NET SDK dla języka SQL i zestawu JAVA SDK dla języka SQL
- Wersja 1.9.0 i nowsze zestawu SDK Node.js dla języka SQL i zestawu SDK języka Python dla języka SQL
- Wszystkie obsługiwane wersje zestawów SDK platformy .NET Core
Aby uzyskać więcej informacji, zobacz RetryAfter.
W wersji 1.19 lub nowszej zestawu .NET SDK istnieje mechanizm rejestrowania dodatkowych informacji diagnostycznych i rozwiązywania problemów z opóźnieniami, jak pokazano w poniższym przykładzie. Możesz zarejestrować ciąg diagnostyczny dla żądań, które mają większe opóźnienie odczytu. Przechwycony ciąg diagnostyczny pomoże Ci zrozumieć, ile razy otrzymano błędy 429 dla danego żądania.
ResourceResponse<Document> readDocument = await this.readClient.ReadDocumentAsync(oldDocuments[i].SelfLink);
readDocument.RequestDiagnosticsString
Identyfikatory URI dokumentów pamięci podręcznej w celu uzyskania mniejszego opóźnienia odczytu
Buforuj identyfikatory URI dokumentów, gdy jest to możliwe, aby uzyskać najlepszą wydajność odczytu. Należy zdefiniować logikę, aby buforować identyfikator zasobu podczas tworzenia zasobu. Wyszukiwania oparte na identyfikatorach zasobów są szybsze niż wyszukiwania oparte na nazwach, więc buforowanie tych wartości zwiększa wydajność.
Zwiększanie liczby wątków/zadań
Zobacz Zwiększanie liczby wątków/zadań w sekcji sieci w tym artykule.
Operacje zapytań
Aby uzyskać informacje o operacjach zapytań, zobacz porady dotyczące wydajności zapytań.
Zasady indeksowania
Wyklucz nieużywane ścieżki z indeksowania w celu przyspieszenia operacji zapisu
Zasady indeksowania usługi Azure Cosmos DB umożliwiają również określenie ścieżek dokumentów do uwzględnienia w indeksowaniu lub wykluczania ich przy użyciu ścieżek indeksowania (IndexingPolicy.IncludedPaths i IndexingPolicy.ExcludedPaths). Ścieżki indeksowania mogą poprawić wydajność zapisu i zmniejszyć magazyn indeksów w scenariuszach, w których wzorce zapytań są znane wcześniej. Wynika to z faktu, że koszty indeksowania są skorelowane bezpośrednio z liczbą indeksowanych ścieżek unikatowych. Na przykład ten kod pokazuje, jak wykluczyć całą sekcję dokumentów (poddrzewo) z indeksowania przy użyciu symbolu wieloznakowego "*":
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);
Aby uzyskać więcej informacji, zobacz Zasady indeksowania usługi Azure Cosmos DB.
Produktywność
Mierzenie i dostrajanie do niższych jednostek żądania/drugiego użycia
Usługa Azure Cosmos DB oferuje bogaty zestaw operacji bazy danych. Te operacje obejmują zapytania relacyjne i hierarchiczne z funkcjami zdefiniowanymi przez użytkownika, procedurami składowanymi i wyzwalaczami, wszystkie operacje na dokumentach w kolekcji bazy danych. Koszt związany z każdą z tych operacji różni się w zależności od procesora CPU, operacji we/wy i pamięci wymaganej do ukończenia operacji. Nie myśl o zasobach sprzętowych i zarządzaniu nimi — zamiast tego pomyśl o jednostce żądania jako pojedynczej mierze zasobów wymaganych do wykonywania różnych operacji bazy danych i obsługiwania żądania aplikacji.
Przepływność jest aprowizowana na podstawie liczby jednostek żądań ustawionych dla każdego kontenera. Użycie jednostek żądania jest oceniane jako stawka na sekundę. Aplikacje, które przekraczają aprowizowaną stawkę jednostek żądań dla kontenera, są ograniczone do momentu spadku szybkości poniżej aprowizowanego poziomu dla kontenera. Jeśli aplikacja wymaga wyższego poziomu przepływności, możesz zwiększyć przepływność, aprowizując dodatkowe jednostki żądań.
Złożoność zapytania wpływa na liczbę jednostek żądań używanych dla operacji. Liczba predykatów, charakter predykatów, liczba funkcji zdefiniowanych przez użytkownika i rozmiar źródłowego zestawu danych wpływają na koszt operacji zapytań.
Aby zmierzyć obciążenie dowolnej operacji (tworzenie, aktualizowanie lub usuwanie), sprawdź nagłówek x-ms-request-charge (lub równoważną RequestCharge
właściwość w ResourceResponse\<T>
zestawie FeedResponse\<T>
SDK platformy .NET), aby zmierzyć liczbę jednostek żądań używanych przez operacje:
// 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);
}
Opłata za żądanie zwrócona w tym nagłówku jest ułamkiem aprowizowanej przepływności (czyli 2000 jednostek RU/sekundę). Jeśli na przykład poprzednie zapytanie zwróci 1000 dokumentów o wartości 1000 KB, koszt operacji wynosi 1000. Dlatego w ciągu jednej sekundy serwer honoruje tylko dwa takie żądania przed ograniczeniem szybkości późniejszych żądań. Aby uzyskać więcej informacji, zobacz Jednostki żądań i kalkulator jednostki żądania.
Obsługa ograniczania szybkości/szybkości żądań jest zbyt duża
Gdy klient próbuje przekroczyć zarezerwowaną przepływność dla konta, nie ma spadku wydajności na serwerze i nie ma użycia pojemności przepływności poza poziomem zarezerwowanym. Serwer z preemptively zakończy żądanie requestRateTooLarge (kod stanu HTTP 429). Spowoduje to zwrócenie nagłówka x-ms-retry-after-ms , który wskazuje czas (w milisekundach), który użytkownik musi czekać przed ponownym podjęciem próby żądania.
HTTP Status 429,
Status Line: RequestRateTooLarge
x-ms-retry-after-ms :100
Zestawy SDK przechwytują tę odpowiedź niejawnie, przestrzegają określonego przez serwer nagłówka ponawiania próby i ponów próbę żądania. Jeśli twoje konto nie jest używane współbieżnie przez wielu klientów, następne ponowienie próby powiedzie się.
Jeśli masz więcej niż jednego klienta skumulowanie operacyjnego powyżej szybkości żądań, domyślna liczba ponownych prób jest obecnie ustawiona na 9 wewnętrznie przez klienta może nie wystarczyć. W takim przypadku klient zgłasza wyjątek DocumentClientException z kodem stanu 429 do aplikacji.
Domyślną liczbę ponownych prób można zmienić, ustawiając RetryOptions
wartość w wystąpieniu ConnectionPolicy
. Domyślnie wyjątek DocumentClientException z kodem stanu 429 jest zwracany po skumulowanym czasie oczekiwania wynoszącym 30 sekund, jeśli żądanie nadal działa powyżej szybkości żądania. Ten błąd zwraca wartość nawet wtedy, gdy bieżąca liczba ponownych prób jest mniejsza niż maksymalna liczba ponownych prób, niezależnie od tego, czy bieżąca wartość jest wartością domyślną 9, czy wartością zdefiniowaną przez użytkownika.
Automatyczne zachowanie ponawiania prób pomaga zwiększyć odporność i użyteczność większości aplikacji. Jednak może to nie być najlepsze zachowanie podczas wykonywania testów porównawczych wydajności, zwłaszcza podczas mierzenia opóźnienia. Obserwowane przez klienta opóźnienie wzrośnie, jeśli eksperyment osiągnie ograniczenie przepustowości serwera i spowoduje, że zestaw SDK klienta ponawia próbę w trybie dyskretnym. Aby uniknąć skoków opóźnień podczas eksperymentów wydajności, zmierz opłatę zwróconą przez każdą operację i upewnij się, że żądania działają poniżej zarezerwowanej stawki żądań. Aby uzyskać więcej informacji, zobacz Request Units (Jednostki żądań).
W przypadku większej przepływności projektowanie mniejszych dokumentów
Opłata za żądanie (czyli koszt przetwarzania żądań) danej operacji jest skorelowana bezpośrednio z rozmiarem dokumentu. Operacje na dużych dokumentach kosztują więcej niż operacje na małych dokumentach.
Następne kroki
Aby zapoznać się z przykładową aplikacją używaną do oceny usługi Azure Cosmos DB pod kątem scenariuszy o wysokiej wydajności na kilku maszynach klienckich, zobacz Performance and scale testing with Azure Cosmos DB (Wydajność i skalowanie przy użyciu usługi Azure Cosmos DB).
Aby dowiedzieć się więcej na temat projektowania aplikacji pod kątem skalowania i wysokiej wydajności, zobacz Partycjonowanie i skalowanie w usłudze Azure Cosmos DB.