Udostępnij za pośrednictwem


Porady dotyczące wydajności zestawu Java SDK usługi Azure Cosmos DB w wersji 4

DOTYCZY: NoSQL

Ważne

Porady dotyczące wydajności w tym artykule dotyczą tylko zestawu Java SDK usługi Azure Cosmos DB w wersji 4. Aby uzyskać więcej informacji, zobacz przewodnik rozwiązywania problemów z zestawem Java SDK usługi Azure Cosmos DB w wersji 4, repozytorium Maven i zestaw Java SDK usługi Azure Cosmos DB w wersji 4. Jeśli obecnie używasz starszej wersji niż 4, zobacz przewodnik Migrowanie do zestawu Java SDK usługi Azure Cosmos DB w wersji 4 , aby uzyskać pomoc dotyczącą uaktualniania do wersji 4.

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 lub wywołania metody zestawu SDK. Jednak ze względu na to, że dostęp do usługi Azure Cosmos DB jest uzyskiwany za pośrednictwem wywołań sieciowych, można dokonać optymalizacji po stronie klienta, aby osiągnąć szczytową wydajność podczas korzystania z zestawu Java SDK usługi Azure Cosmos DB w wersji 4.

Jeśli więc zadajesz pytanie "Jak mogę poprawić wydajność bazy danych?", rozważ następujące opcje:

Sieć

  • Sortowanie klientów w tym samym regionie świadczenia usługi Azure pod kątem wydajności

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. Aby uzyskać przybliżone porównanie, wywołania usługi Azure Cosmos DB w tym samym regionie są kompletne w ciągu 1–2 ms, ale opóźnienie między zachodnim i wschodnim wybrzeżem STANÓW Zjednoczonych wynosi >50 ms. To opóźnienie może się różnić w zależności od trasy podjętej przez żądanie w zależności od trasy, która przechodzi od klienta do granicy centrum danych platformy Azure. Najmniejsze możliwe opóźnienie jest osiągane przez zapewnienie, ż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.

Ilustracja przedstawiająca zasady połączenia usługi Azure Cosmos DB

Aplikacja, która współdziała z kontem usługi Azure Cosmos DB w wielu regionach, musi skonfigurować preferowane lokalizacje , aby upewnić się, że żądania będą kierowane do kolokowanego regionu.

Włączanie przyspieszonej sieci w celu zmniejszenia opóźnienia i zakłócenia procesora CPU

Zdecydowanie zalecamy wykonanie instrukcji dotyczących włączania przyspieszonej sieci w systemie Windows (wybierz, aby uzyskać instrukcje) lub Linux (wybierz, aby uzyskać instrukcje) maszyny wirtualnej platformy Azure, aby zmaksymalizować wydajność przez zmniejszenie opóźnienia i zakłócenia procesora CPU.

Bez przyspieszonej sieci we/wy przesyłane między maszyną wirtualną platformy Azure i innymi zasobami platformy Azure mogą być kierowane za pośrednictwem hosta i przełącznika wirtualnego znajdującego się między maszyną wirtualną a jej kartą sieciową. Posiadanie wbudowanego hosta i przełącznika wirtualnego w ścieżce danych nie tylko zwiększa opóźnienie i zakłócenia w kanale komunikacyjnym, ale także kradnie cykle procesora CPU z maszyny wirtualnej. W przypadku przyspieszonej sieci interfejsy maszyn wirtualnych bezpośrednio z kartą sieciową bez pośredników. Wszystkie szczegóły zasad sieciowych są obsługiwane na sprzęcie na karcie sieciowej, pomijając hosta i przełącznik wirtualny. Ogólnie rzecz biorąc, można oczekiwać mniejszego opóźnienia i większej przepływności, a także bardziej spójnego opóźnienia i mniejszego wykorzystania procesora CPU po włączeniu przyspieszonej sieci.

Ograniczenia: przyspieszona sieć musi być obsługiwana w systemie operacyjnym maszyny wirtualnej i może być włączona tylko wtedy, gdy maszyna wirtualna zostanie zatrzymana i cofnięto przydział. Nie można wdrożyć maszyny wirtualnej za pomocą usługi Azure Resource Manager. Usługa App Service nie ma włączonej przyspieszonej sieci.

Aby uzyskać więcej informacji, zobacz instrukcje dotyczące systemów Windows i Linux .

Dostrajanie konfiguracji połączenia bezpośredniego i bramy

Aby zoptymalizować konfiguracje połączeń trybu bezpośredniego i bramy, zobacz jak dostroić konfiguracje połączeń dla zestawu Java SDK w wersji 4.

SDK usage (Użycie zestawu SDK)

  • Instalowanie najnowszego zestawu SDK

Zestawy SDK usługi Azure Cosmos DB są stale ulepszane, aby zapewnić najlepszą wydajność. Aby określić najnowsze ulepszenia zestawu SDK, odwiedź stronę zestawu SDK usługi Azure Cosmos DB.

  • Używanie pojedynczego klienta usługi Azure Cosmos DB przez cały okres istnienia aplikacji

Każde wystąpienie klienta usługi Azure Cosmos DB jest bezpieczne wątkowo i wykonuje wydajne zarządzanie połączeniami i buforowanie adresów. Aby umożliwić wydajne zarządzanie połączeniami i lepszą wydajność przez klienta usługi Azure Cosmos DB, zdecydowanie zalecamy użycie pojedynczego wystąpienia klienta usługi Azure Cosmos DB przez cały okres istnienia aplikacji.

  • Użyj najniższego poziomu spójności wymaganego dla aplikacji

Podczas tworzenia elementu CosmosClient domyślna spójność używana, jeśli nie jest jawnie ustawiona, to Sesja. Jeśli spójność sesji nie jest wymagana przez logikę aplikacji, ustaw wartość Spójność na ostateczną. Uwaga: zaleca się stosowanie co najmniej spójności sesji w aplikacjach korzystających z procesora zestawienia zmian usługi Azure Cosmos DB.

  • Używanie interfejsu API asynchronicznego do maksymalnej aprowizowanej przepływności

Zestaw Java SDK usługi Azure Cosmos DB w wersji 4 zawiera dwa interfejsy API: synchroniczny i asynchroniczny. Mówiąc mniej więcej, interfejs API asynchroniczny implementuje funkcje zestawu SDK, natomiast interfejs API synchronizacji jest cienką otoką, która wykonuje wywołania blokujące interfejsu API asynchronicznego. Jest to przeciwieństwo starszego zestawu Java SDK asynchronicznego języka Java usługi Azure Cosmos DB w wersji 2, który był tylko asynchroniczny, oraz starszego zestawu Java SDK synchronizacji usługi Azure Cosmos DB w wersji 2, który był tylko synchronizacją i miał oddzielną implementację.

Wybór interfejsu API jest określany podczas inicjowania klienta; Obiekt CosmosAsyncClient obsługuje interfejs API asynchroniczny, a klient CosmosClient obsługuje interfejs API synchronizacji.

Interfejs API asynchroniczny implementuje nieblokujące operacje we/wy i jest optymalnym wyborem, jeśli twoim celem jest maksymalne wykorzystanie przepływności podczas wydawania żądań do usługi Azure Cosmos DB.

Użycie interfejsu API synchronizacji może być właściwym wyborem, jeśli chcesz lub potrzebujesz interfejsu API, który blokuje odpowiedź na każde żądanie, lub jeśli operacja synchroniczna jest dominującym paradygmatem w aplikacji. Na przykład możesz chcieć, aby interfejs API synchronizacji był utrwalany w usłudze Azure Cosmos DB w aplikacji mikrousług, pod warunkiem, że przepływność nie jest krytyczna.

Zwróć uwagę, że przepływność interfejsu API synchronizacji spada wraz ze zwiększeniem czasu odpowiedzi na żądanie, natomiast interfejs API asynchroniczny może usycić pełne możliwości przepustowości sprzętu.

Kolokacja geograficzna może zapewnić wyższą i bardziej spójną przepływność podczas korzystania z interfejsu API synchronizacji (zobacz Collocate clients in same region azure for performance), ale nadal nie oczekuje się przekroczenia osiągalnej przepływności interfejsu API asynchronicznego.

Niektórzy użytkownicy mogą być również nieznani w programie Project Reactor— reaktywnej strukturze Strumienie używanej do implementowania interfejsu API asynchronicznego zestawu Java SDK usługi Azure Cosmos DB w wersji 4. Jeśli jest to problem, zalecamy zapoznanie się z naszym przewodnikiem wprowadzającym wzorzec reaktora, a następnie zapoznaj się z tym wprowadzeniem do programowania reaktywnego, aby zapoznać się z tym tematem. Jeśli używasz już usługi Azure Cosmos DB z interfejsem asynchroniczny, a użyty zestaw SDK to zestaw SDK języka Java asynchronicznego usługi Azure Cosmos DB w wersji 2, możesz zapoznać się z reaktywnym X/RxJava, ale nie masz pewności, co zmieniło się w usłudze Project Reactor. W takim przypadku zapoznaj się z naszym przewodnikiem Reactor vs RxJava, aby się zapoznać.

W poniższych fragmentach kodu pokazano, jak zainicjować klienta usługi Azure Cosmos DB na potrzeby operacji interfejsu API asynchronicznego lub interfejsu API synchronizacji, odpowiednio:

Zestaw JAVA SDK w wersji 4 (Maven com.azure::azure-cosmos) Async API


CosmosAsyncClient client = new CosmosClientBuilder()
        .endpoint(HOSTNAME)
        .key(MASTERKEY)
        .consistencyLevel(CONSISTENCY)
        .buildAsyncClient();

  • Skalowanie w poziomie obciążenia klienta

Jeśli testujesz na wysokim poziomie przepływności, 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.

Dobrą regułą kciuka nie jest przekroczenie >50% wykorzystania procesora CPU na dowolnym serwerze, aby zachować małe opóźnienie.

  • Użyj odpowiedniego harmonogramu (unikaj kradzieży wątków we/wy pętli zdarzeń)

Funkcja asynchroniczna zestawu SDK java usługi Azure Cosmos DB jest oparta na netty nieblokujących operacji we/wy. Zestaw SDK używa do wykonywania operacji we/wy stałej liczby wątków Netty pętli zdarzeń operacji we/wy (równej liczbie rdzeni procesora CPU komputera). Strumień zwrócony przez interfejs API emituje wynik dla jednego z współdzielonych wątków Netty pętli zdarzeń we/wy. Dlatego ważne jest, aby nie blokować współdzielonych wątków Netty pętli zdarzeń operacji we/wy. Wykonywanie intensywnej pracy procesora CPU lub blokowanie operacji w wątku netty pętli zdarzeń we/wy może spowodować zakleszczenie lub znaczne zmniejszenie przepływności zestawu SDK.

Na przykład poniższy kod wykonuje pracę intensywnie korzystającą z procesora CPU w wątku netty pętli zdarzeń:


Mono<CosmosItemResponse<CustomPOJO>> createItemPub = asyncContainer.createItem(item);
createItemPub.subscribe(
        itemResponse -> {
            //this is executed on eventloop IO netty thread.
            //the eventloop thread is shared and is meant to return back quickly.
            //
            // DON'T do this on eventloop IO netty thread.
            veryCpuIntensiveWork();
        });


Po otrzymaniu wyniku należy unikać wykonywania wszelkich prac intensywnie korzystających z procesora CPU w wyniku w wątku netty pętli zdarzeń. Zamiast tego możesz podać własny harmonogram, aby udostępnić własny wątek do uruchamiania pracy, jak pokazano poniżej (wymaga import reactor.core.scheduler.Schedulers).


Mono<CosmosItemResponse<CustomPOJO>> createItemPub = asyncContainer.createItem(item);
createItemPub
        .publishOn(Schedulers.parallel())
        .subscribe(
                itemResponse -> {
                    //this is now executed on reactor scheduler's parallel thread.
                    //reactor scheduler's parallel thread is meant for CPU intensive work.
                    veryCpuIntensiveWork();
                });

Na podstawie typu pracy należy użyć odpowiedniego harmonogramu reaktora do pracy. Przeczytaj tutaj Schedulers.

Aby lepiej zrozumieć model wątkowania i planowania projektu Reactor, zapoznaj się z tym wpisem w blogu autorstwa Project Reactor.

Aby uzyskać więcej informacji na temat zestawu Java SDK usługi Azure Cosmos DB w wersji 4, zobacz katalog usługi Azure Cosmos DB zestawu Azure SDK dla języka Java monorepo w witrynie GitHub.

  • Optymalizowanie ustawień rejestrowania w aplikacji

Z różnych powodów należy dodać rejestrowanie w wątku, który generuje wysoką przepływność żądań. Jeśli Twoim celem jest pełne nasycenie aprowizowanej przepływności kontenera z żądaniami wygenerowanymi przez ten wątek, optymalizacje rejestrowania mogą znacznie poprawić wydajność.

  • Konfigurowanie rejestratora asynchronicznego

Opóźnienie synchronicznego rejestratora musi wpływać na ogólne obliczenie opóźnienia wątku generowania żądań. Rejestrator asynchroniczny, taki jak log4j2, zaleca się oddzielenie obciążeń związanych z rejestrowaniem z wątków aplikacji o wysokiej wydajności.

  • Wyłączanie rejestrowania netty

Rejestrowanie biblioteki Netty jest czatty i musi być wyłączone (pomijanie logowania w konfiguracji może nie być wystarczające), aby uniknąć dodatkowych kosztów procesora CPU. Jeśli nie jesteś w trybie debugowania, wyłącz rejestrowanie netty całkowicie. Dlatego jeśli używasz usługi Log4j, aby usunąć dodatkowe koszty procesora CPU poniesione przez org.apache.log4j.Category.callAppenders() netty, dodaj następujący wiersz do bazy kodu:

org.apache.log4j.Logger.getLogger("io.netty").setLevel(org.apache.log4j.Level.OFF);
  • Limit zasobów otwartych plików systemu operacyjnego

Niektóre systemy Linux (takie jak Red Hat) mają górny limit liczby otwartych plików, więc łączna liczba połączeń. Uruchom następujące polecenie, aby wyświetlić bieżące limity:

ulimit -a

Liczba otwartych plików (nofile) musi być wystarczająco duża, aby mieć wystarczającą ilość miejsca dla skonfigurowanego rozmiaru puli połączeń i innych otwartych plików przez system operacyjny. Można go zmodyfikować, aby umożliwić większy rozmiar puli połączeń.

Otwórz plik limits.conf:

vim /etc/security/limits.conf

Dodaj/zmodyfikuj następujące wiersze:

* - nofile 100000
  • Określanie klucza partycji w zapisach punktów

Aby zwiększyć wydajność zapisów punktów, określ klucz partycji elementu w wywołaniu interfejsu API zapisu punktu, jak pokazano poniżej:

Zestaw JAVA SDK w wersji 4 (Maven com.azure::azure-cosmos) Async API

asyncContainer.createItem(item,new PartitionKey(pk),new CosmosItemRequestOptions()).block();

Zamiast dostarczać tylko wystąpienie elementu, jak pokazano poniżej:

Zestaw JAVA SDK w wersji 4 (Maven com.azure::azure-cosmos) Async API

asyncContainer.createItem(item).block();

Ta ostatnia funkcja jest obsługiwana, ale spowoduje dodanie opóźnienia do aplikacji; zestaw SDK musi przeanalizować element i wyodrębnić klucz partycji.

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ą określenie ścieżek dokumentów do uwzględnienia lub wykluczenia z indeksowania przy użyciu ścieżek indeksowania (setIncludedPaths i setExcludedPaths). Użycie ścieżek indeksowania może oferować lepszą wydajność zapisu i niższy magazyn indeksów w scenariuszach, w których wzorce zapytań są znane wcześniej, ponieważ koszty indeksowania są bezpośrednio skorelowane z liczbą indeksowanych unikatowych ścieżek. Na przykład poniższy kod przedstawia sposób dołączania i wykluczania całych sekcji dokumentów (nazywanych również poddrzewem) z indeksowania przy użyciu symbolu wieloznakowego "*".


CosmosContainerProperties containerProperties = new CosmosContainerProperties(containerName, "/lastName");

// Custom indexing policy
IndexingPolicy indexingPolicy = new IndexingPolicy();
indexingPolicy.setIndexingMode(IndexingMode.CONSISTENT);

// Included paths
List<IncludedPath> includedPaths = new ArrayList<>();
includedPaths.add(new IncludedPath("/*"));
indexingPolicy.setIncludedPaths(includedPaths);

// Excluded paths
List<ExcludedPath> excludedPaths = new ArrayList<>();
excludedPaths.add(new ExcludedPath("/name/*"));
indexingPolicy.setExcludedPaths(excludedPaths);

containerProperties.setIndexingPolicy(indexingPolicy);

ThroughputProperties throughputProperties = ThroughputProperties.createManualThroughput(400);

database.createContainerIfNotExists(containerProperties, throughputProperties);
CosmosAsyncContainer containerIfNotExists = database.getContainer(containerName);

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, w tym 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 zależy od procesora, danych We/Wy i pamięci wymaganej do wykonania danej operacji. Zamiast myśleć o zasobach sprzętowych i zarządzaniu nimi, możesz traktować jednostkę żądania (RU) jako pojedynczą miarę dla zasobów wymaganych do wykonywania różnych operacji bazy danych i obsługi żądania aplikacji.

Przepływność jest aprowizowana na podstawie liczby jednostek żądań ustawionych dla każdego kontenera. Użycie jednostek żądania jest oceniane jako szybkość na sekundę. Aplikacje, które przekraczają aprowizowaną liczbę 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 ma wpływ na liczbę jednostek żądania używanych dla operacji. Liczba predykatów, charakter predykatów, liczba funkcji zdefiniowanych przez użytkownika i rozmiar zestawu danych źródłowych wpływają na koszt operacji zapytań.

Aby zmierzyć obciążenie dowolnej operacji (tworzenie, aktualizowanie lub usuwanie), sprawdź nagłówek x-ms-request-charge , aby zmierzyć liczbę jednostek żądań używanych przez te operacje. Możesz również przyjrzeć się równoważnej właściwości RequestCharge w elemencie ResourceResponse<T> lub FeedResponse<T>.

Zestaw JAVA SDK w wersji 4 (Maven com.azure::azure-cosmos) Async API

CosmosItemResponse<CustomPOJO> response = asyncContainer.createItem(item).block();

response.getRequestCharge();

Opłata za żądanie zwrócona w tym nagłówku jest ułamkiem aprowizowanej przepływności. Jeśli na przykład masz aprowizowaną wartość 2000 RU/s, a poprzednie zapytanie zwróci 1000 dokumentów 1 KB, koszt operacji wynosi 1000. W związku z tym w ciągu jednej sekundy serwer honoruje tylko dwa takie żądania przed ograniczeniem liczby kolejnych żądań. Aby uzyskać więcej informacji, zobacz Request units and the request unit calculator (Jednostki żądań i kalkulator jednostek żą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) i zwróci nagłówek x-ms-retry-after-ms wskazujący ilość czasu w milisekundach, że użytkownik musi czekać przed ponownego przypisania żą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, który stale działa powyżej szybkości żądań, domyślna liczba ponownych prób jest obecnie ustawiona na 9 wewnętrznie przez klienta może nie być wystarczająca; w tym przypadku klient zgłasza wyjątek CosmosClientException z kodem stanu 429 do aplikacji. Domyślna liczba ponownych prób można zmienić przy użyciu polecenia setMaxRetryAttemptsOnThrottledRequests() w wystąpieniu ThrottlingRetryOptions . Domyślnie wyjątek CosmosClientException 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. Dzieje się tak nawet wtedy, gdy bieżąca liczba ponownych prób jest mniejsza niż maksymalna liczba ponownych prób, może to być wartość domyślna 9 lub wartość zdefiniowana przez użytkownika.

Chociaż automatyczne zachowanie ponawiania prób pomaga zwiększyć odporność i użyteczność dla większości aplikacji, może to być sprzeczne 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ń).

  • Projektowanie pod kątem mniejszych dokumentów pod kątem większej przepływności

Opłata za żądanie (koszt przetwarzania żądań) danej operacji jest bezpośrednio skorelowana z rozmiarem dokumentu. Operacje na dużych dokumentach kosztują więcej niż operacje dla małych dokumentów. W idealnym przypadku należy utworzyć architekturę aplikacji i przepływów pracy, aby rozmiar elementu wynosił ok. 1 KB lub podobnej kolejności lub wielkości. W przypadku aplikacji wrażliwych na opóźnienia należy unikać dużych elementów — dokumenty z wieloma MB spowalniają aplikację.

Następne kroki

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.

Próbujesz zaplanować pojemność migracji do usługi Azure Cosmos DB? Informacje o istniejącym klastrze bazy danych można użyć do planowania pojemności.